diff options
Diffstat (limited to 'net/sunrpc/auth_gss/auth_gss.c')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 204 |
1 files changed, 110 insertions, 94 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index b333b1bdad45..206788e8b787 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1671,59 +1671,62 @@ gss_refresh_null(struct rpc_task *task) | |||
1671 | return 0; | 1671 | return 0; |
1672 | } | 1672 | } |
1673 | 1673 | ||
1674 | static __be32 * | 1674 | static int |
1675 | gss_validate(struct rpc_task *task, __be32 *p) | 1675 | gss_validate(struct rpc_task *task, struct xdr_stream *xdr) |
1676 | { | 1676 | { |
1677 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; | 1677 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; |
1678 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1678 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
1679 | __be32 *seq = NULL; | 1679 | __be32 *p, *seq = NULL; |
1680 | struct kvec iov; | 1680 | struct kvec iov; |
1681 | struct xdr_buf verf_buf; | 1681 | struct xdr_buf verf_buf; |
1682 | struct xdr_netobj mic; | 1682 | struct xdr_netobj mic; |
1683 | u32 flav,len; | 1683 | u32 len, maj_stat; |
1684 | u32 maj_stat; | 1684 | int status; |
1685 | __be32 *ret = ERR_PTR(-EIO); | ||
1686 | 1685 | ||
1687 | dprintk("RPC: %5u %s\n", task->tk_pid, __func__); | 1686 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); |
1687 | if (!p) | ||
1688 | goto validate_failed; | ||
1689 | if (*p++ != rpc_auth_gss) | ||
1690 | goto validate_failed; | ||
1691 | len = be32_to_cpup(p); | ||
1692 | if (len > RPC_MAX_AUTH_SIZE) | ||
1693 | goto validate_failed; | ||
1694 | p = xdr_inline_decode(xdr, len); | ||
1695 | if (!p) | ||
1696 | goto validate_failed; | ||
1688 | 1697 | ||
1689 | flav = ntohl(*p++); | ||
1690 | if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE) | ||
1691 | goto out_bad; | ||
1692 | if (flav != RPC_AUTH_GSS) | ||
1693 | goto out_bad; | ||
1694 | seq = kmalloc(4, GFP_NOFS); | 1698 | seq = kmalloc(4, GFP_NOFS); |
1695 | if (!seq) | 1699 | if (!seq) |
1696 | goto out_bad; | 1700 | goto validate_failed; |
1697 | *seq = htonl(task->tk_rqstp->rq_seqno); | 1701 | *seq = cpu_to_be32(task->tk_rqstp->rq_seqno); |
1698 | iov.iov_base = seq; | 1702 | iov.iov_base = seq; |
1699 | iov.iov_len = 4; | 1703 | iov.iov_len = 4; |
1700 | xdr_buf_from_iov(&iov, &verf_buf); | 1704 | xdr_buf_from_iov(&iov, &verf_buf); |
1701 | mic.data = (u8 *)p; | 1705 | mic.data = (u8 *)p; |
1702 | mic.len = len; | 1706 | mic.len = len; |
1703 | |||
1704 | ret = ERR_PTR(-EACCES); | ||
1705 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 1707 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
1706 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1708 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1707 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1709 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1708 | if (maj_stat) { | 1710 | if (maj_stat) |
1709 | dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n", | 1711 | goto bad_mic; |
1710 | task->tk_pid, __func__, maj_stat); | 1712 | |
1711 | goto out_bad; | ||
1712 | } | ||
1713 | /* We leave it to unwrap to calculate au_rslack. For now we just | 1713 | /* We leave it to unwrap to calculate au_rslack. For now we just |
1714 | * calculate the length of the verifier: */ | 1714 | * calculate the length of the verifier: */ |
1715 | cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; | 1715 | cred->cr_auth->au_verfsize = XDR_QUADLEN(len) + 2; |
1716 | status = 0; | ||
1717 | out: | ||
1716 | gss_put_ctx(ctx); | 1718 | gss_put_ctx(ctx); |
1717 | dprintk("RPC: %5u %s: gss_verify_mic succeeded.\n", | ||
1718 | task->tk_pid, __func__); | ||
1719 | kfree(seq); | ||
1720 | return p + XDR_QUADLEN(len); | ||
1721 | out_bad: | ||
1722 | gss_put_ctx(ctx); | ||
1723 | dprintk("RPC: %5u %s failed ret %ld.\n", task->tk_pid, __func__, | ||
1724 | PTR_ERR(ret)); | ||
1725 | kfree(seq); | 1719 | kfree(seq); |
1726 | return ret; | 1720 | return status; |
1721 | |||
1722 | validate_failed: | ||
1723 | status = -EIO; | ||
1724 | goto out; | ||
1725 | bad_mic: | ||
1726 | dprintk("RPC: %5u %s: gss_verify_mic returned error 0x%08x\n", | ||
1727 | task->tk_pid, __func__, maj_stat); | ||
1728 | status = -EACCES; | ||
1729 | goto out; | ||
1727 | } | 1730 | } |
1728 | 1731 | ||
1729 | static int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | 1732 | static int gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, |
@@ -1921,79 +1924,98 @@ out: | |||
1921 | return status; | 1924 | return status; |
1922 | } | 1925 | } |
1923 | 1926 | ||
1924 | static inline int | 1927 | static int |
1928 | gss_unwrap_resp_auth(struct rpc_cred *cred) | ||
1929 | { | ||
1930 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize; | ||
1931 | return 0; | ||
1932 | } | ||
1933 | |||
1934 | static int | ||
1925 | gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | 1935 | gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, |
1926 | struct rpc_rqst *rqstp, __be32 **p) | 1936 | struct rpc_rqst *rqstp, struct xdr_stream *xdr) |
1927 | { | 1937 | { |
1928 | struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; | 1938 | struct xdr_buf integ_buf, *rcv_buf = &rqstp->rq_rcv_buf; |
1929 | struct xdr_buf integ_buf; | 1939 | u32 data_offset, mic_offset, integ_len, maj_stat; |
1930 | struct xdr_netobj mic; | 1940 | struct xdr_netobj mic; |
1931 | u32 data_offset, mic_offset; | 1941 | __be32 *p; |
1932 | u32 integ_len; | ||
1933 | u32 maj_stat; | ||
1934 | int status = -EIO; | ||
1935 | 1942 | ||
1936 | integ_len = ntohl(*(*p)++); | 1943 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); |
1944 | if (unlikely(!p)) | ||
1945 | goto unwrap_failed; | ||
1946 | integ_len = be32_to_cpup(p++); | ||
1937 | if (integ_len & 3) | 1947 | if (integ_len & 3) |
1938 | return status; | 1948 | goto unwrap_failed; |
1939 | data_offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; | 1949 | data_offset = (u8 *)(p) - (u8 *)rcv_buf->head[0].iov_base; |
1940 | mic_offset = integ_len + data_offset; | 1950 | mic_offset = integ_len + data_offset; |
1941 | if (mic_offset > rcv_buf->len) | 1951 | if (mic_offset > rcv_buf->len) |
1942 | return status; | 1952 | goto unwrap_failed; |
1943 | if (ntohl(*(*p)++) != rqstp->rq_seqno) | 1953 | if (be32_to_cpup(p) != rqstp->rq_seqno) |
1944 | return status; | 1954 | goto unwrap_failed; |
1945 | |||
1946 | if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, | ||
1947 | mic_offset - data_offset)) | ||
1948 | return status; | ||
1949 | 1955 | ||
1956 | if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset, integ_len)) | ||
1957 | goto unwrap_failed; | ||
1950 | if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) | 1958 | if (xdr_buf_read_netobj(rcv_buf, &mic, mic_offset)) |
1951 | return status; | 1959 | goto unwrap_failed; |
1952 | |||
1953 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); | 1960 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf, &mic); |
1954 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1961 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1955 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1962 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1956 | if (maj_stat != GSS_S_COMPLETE) | 1963 | if (maj_stat != GSS_S_COMPLETE) |
1957 | return status; | 1964 | goto bad_mic; |
1965 | |||
1966 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + 2 + | ||
1967 | 1 + XDR_QUADLEN(mic.len); | ||
1958 | return 0; | 1968 | return 0; |
1969 | unwrap_failed: | ||
1970 | return -EIO; | ||
1971 | bad_mic: | ||
1972 | dprintk("RPC: %s: gss_verify_mic returned error 0x%08x\n", | ||
1973 | __func__, maj_stat); | ||
1974 | return -EIO; | ||
1959 | } | 1975 | } |
1960 | 1976 | ||
1961 | static inline int | 1977 | static int |
1962 | gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | 1978 | gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, |
1963 | struct rpc_rqst *rqstp, __be32 **p) | 1979 | struct rpc_rqst *rqstp, struct xdr_stream *xdr) |
1964 | { | 1980 | { |
1965 | struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; | 1981 | struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; |
1966 | u32 offset; | 1982 | struct kvec *head = rqstp->rq_rcv_buf.head; |
1967 | u32 opaque_len; | 1983 | unsigned int savedlen = rcv_buf->len; |
1968 | u32 maj_stat; | 1984 | u32 offset, opaque_len, maj_stat; |
1969 | int status = -EIO; | 1985 | __be32 *p; |
1970 | 1986 | ||
1971 | opaque_len = ntohl(*(*p)++); | 1987 | p = xdr_inline_decode(xdr, 2 * sizeof(*p)); |
1972 | offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; | 1988 | if (unlikely(!p)) |
1989 | goto unwrap_failed; | ||
1990 | opaque_len = be32_to_cpup(p++); | ||
1991 | offset = (u8 *)(p) - (u8 *)head->iov_base; | ||
1973 | if (offset + opaque_len > rcv_buf->len) | 1992 | if (offset + opaque_len > rcv_buf->len) |
1974 | return status; | 1993 | goto unwrap_failed; |
1975 | /* remove padding: */ | ||
1976 | rcv_buf->len = offset + opaque_len; | 1994 | rcv_buf->len = offset + opaque_len; |
1977 | 1995 | ||
1978 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); | 1996 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, offset, rcv_buf); |
1979 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1997 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1980 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1998 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
1981 | if (maj_stat != GSS_S_COMPLETE) | 1999 | if (maj_stat != GSS_S_COMPLETE) |
1982 | return status; | 2000 | goto bad_unwrap; |
1983 | if (ntohl(*(*p)++) != rqstp->rq_seqno) | 2001 | /* gss_unwrap decrypted the sequence number */ |
1984 | return status; | 2002 | if (be32_to_cpup(p++) != rqstp->rq_seqno) |
1985 | 2003 | goto unwrap_failed; | |
1986 | return 0; | ||
1987 | } | ||
1988 | 2004 | ||
1989 | static int | 2005 | /* gss_unwrap redacts the opaque blob from the head iovec. |
1990 | gss_unwrap_req_decode(kxdrdproc_t decode, struct rpc_rqst *rqstp, | 2006 | * rcv_buf has changed, thus the stream needs to be reset. |
1991 | __be32 *p, void *obj) | 2007 | */ |
1992 | { | 2008 | xdr_init_decode(xdr, rcv_buf, p, rqstp); |
1993 | struct xdr_stream xdr; | ||
1994 | 2009 | ||
1995 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p, rqstp); | 2010 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + 2 + |
1996 | return decode(rqstp, &xdr, obj); | 2011 | XDR_QUADLEN(savedlen - rcv_buf->len); |
2012 | return 0; | ||
2013 | unwrap_failed: | ||
2014 | return -EIO; | ||
2015 | bad_unwrap: | ||
2016 | dprintk("RPC: %s: gss_unwrap returned error 0x%08x\n", | ||
2017 | __func__, maj_stat); | ||
2018 | return -EIO; | ||
1997 | } | 2019 | } |
1998 | 2020 | ||
1999 | static bool | 2021 | static bool |
@@ -2037,39 +2059,33 @@ out: | |||
2037 | } | 2059 | } |
2038 | 2060 | ||
2039 | static int | 2061 | static int |
2040 | gss_unwrap_resp(struct rpc_task *task, | 2062 | gss_unwrap_resp(struct rpc_task *task, struct xdr_stream *xdr) |
2041 | kxdrdproc_t decode, void *rqstp, __be32 *p, void *obj) | ||
2042 | { | 2063 | { |
2043 | struct rpc_cred *cred = task->tk_rqstp->rq_cred; | 2064 | struct rpc_rqst *rqstp = task->tk_rqstp; |
2065 | struct rpc_cred *cred = rqstp->rq_cred; | ||
2044 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, | 2066 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, |
2045 | gc_base); | 2067 | gc_base); |
2046 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 2068 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
2047 | __be32 *savedp = p; | 2069 | int status = -EIO; |
2048 | struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head; | ||
2049 | int savedlen = head->iov_len; | ||
2050 | int status = -EIO; | ||
2051 | 2070 | ||
2052 | if (ctx->gc_proc != RPC_GSS_PROC_DATA) | 2071 | if (ctx->gc_proc != RPC_GSS_PROC_DATA) |
2053 | goto out_decode; | 2072 | goto out_decode; |
2054 | switch (gss_cred->gc_service) { | 2073 | switch (gss_cred->gc_service) { |
2055 | case RPC_GSS_SVC_NONE: | 2074 | case RPC_GSS_SVC_NONE: |
2075 | status = gss_unwrap_resp_auth(cred); | ||
2056 | break; | 2076 | break; |
2057 | case RPC_GSS_SVC_INTEGRITY: | 2077 | case RPC_GSS_SVC_INTEGRITY: |
2058 | status = gss_unwrap_resp_integ(cred, ctx, rqstp, &p); | 2078 | status = gss_unwrap_resp_integ(cred, ctx, rqstp, xdr); |
2059 | if (status) | ||
2060 | goto out; | ||
2061 | break; | 2079 | break; |
2062 | case RPC_GSS_SVC_PRIVACY: | 2080 | case RPC_GSS_SVC_PRIVACY: |
2063 | status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p); | 2081 | status = gss_unwrap_resp_priv(cred, ctx, rqstp, xdr); |
2064 | if (status) | ||
2065 | goto out; | ||
2066 | break; | 2082 | break; |
2067 | } | 2083 | } |
2068 | /* take into account extra slack for integrity and privacy cases: */ | 2084 | if (status) |
2069 | cred->cr_auth->au_rslack = cred->cr_auth->au_verfsize + (p - savedp) | 2085 | goto out; |
2070 | + (savedlen - head->iov_len); | 2086 | |
2071 | out_decode: | 2087 | out_decode: |
2072 | status = gss_unwrap_req_decode(decode, rqstp, p, obj); | 2088 | status = rpcauth_unwrap_resp_decode(task, xdr); |
2073 | out: | 2089 | out: |
2074 | gss_put_ctx(ctx); | 2090 | gss_put_ctx(ctx); |
2075 | dprintk("RPC: %5u %s returning %d\n", | 2091 | dprintk("RPC: %5u %s returning %d\n", |