diff options
author | J. Bruce Fields <bfields@fieldses.org> | 2005-10-13 16:54:58 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2005-10-19 02:19:44 -0400 |
commit | 2d2da60c63b67174add32f06e8d54c3a0c5cd9cf (patch) | |
tree | 4b9df421a02217e1cd23b601b6c05c592d0bdf02 /net/sunrpc/auth_gss | |
parent | 24b2605becc10ca63c4c30808fa59a8abbf68727 (diff) |
RPCSEC_GSS: client-side privacy support
Add the code to the client side to handle privacy. This is dead code until
we actually add privacy support to krb5.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net/sunrpc/auth_gss')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 149 |
1 files changed, 148 insertions, 1 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index dc95b797ca65..5e4872058ec7 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/types.h> | 43 | #include <linux/types.h> |
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <linux/sched.h> | 45 | #include <linux/sched.h> |
46 | #include <linux/pagemap.h> | ||
46 | #include <linux/sunrpc/clnt.h> | 47 | #include <linux/sunrpc/clnt.h> |
47 | #include <linux/sunrpc/auth.h> | 48 | #include <linux/sunrpc/auth.h> |
48 | #include <linux/sunrpc/auth_gss.h> | 49 | #include <linux/sunrpc/auth_gss.h> |
@@ -975,6 +976,114 @@ gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
975 | return 0; | 976 | return 0; |
976 | } | 977 | } |
977 | 978 | ||
979 | static void | ||
980 | priv_release_snd_buf(struct rpc_rqst *rqstp) | ||
981 | { | ||
982 | int i; | ||
983 | |||
984 | for (i=0; i < rqstp->rq_enc_pages_num; i++) | ||
985 | __free_page(rqstp->rq_enc_pages[i]); | ||
986 | kfree(rqstp->rq_enc_pages); | ||
987 | } | ||
988 | |||
989 | static int | ||
990 | alloc_enc_pages(struct rpc_rqst *rqstp) | ||
991 | { | ||
992 | struct xdr_buf *snd_buf = &rqstp->rq_snd_buf; | ||
993 | int first, last, i; | ||
994 | |||
995 | if (snd_buf->page_len == 0) { | ||
996 | rqstp->rq_enc_pages_num = 0; | ||
997 | return 0; | ||
998 | } | ||
999 | |||
1000 | first = snd_buf->page_base >> PAGE_CACHE_SHIFT; | ||
1001 | last = (snd_buf->page_base + snd_buf->page_len - 1) >> PAGE_CACHE_SHIFT; | ||
1002 | rqstp->rq_enc_pages_num = last - first + 1 + 1; | ||
1003 | rqstp->rq_enc_pages | ||
1004 | = kmalloc(rqstp->rq_enc_pages_num * sizeof(struct page *), | ||
1005 | GFP_NOFS); | ||
1006 | if (!rqstp->rq_enc_pages) | ||
1007 | goto out; | ||
1008 | for (i=0; i < rqstp->rq_enc_pages_num; i++) { | ||
1009 | rqstp->rq_enc_pages[i] = alloc_page(GFP_NOFS); | ||
1010 | if (rqstp->rq_enc_pages[i] == NULL) | ||
1011 | goto out_free; | ||
1012 | } | ||
1013 | rqstp->rq_release_snd_buf = priv_release_snd_buf; | ||
1014 | return 0; | ||
1015 | out_free: | ||
1016 | for (i--; i >= 0; i--) { | ||
1017 | __free_page(rqstp->rq_enc_pages[i]); | ||
1018 | } | ||
1019 | out: | ||
1020 | return -EAGAIN; | ||
1021 | } | ||
1022 | |||
1023 | static inline int | ||
1024 | gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | ||
1025 | kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj) | ||
1026 | { | ||
1027 | struct xdr_buf *snd_buf = &rqstp->rq_snd_buf; | ||
1028 | u32 offset; | ||
1029 | u32 maj_stat; | ||
1030 | int status; | ||
1031 | u32 *opaque_len; | ||
1032 | struct page **inpages; | ||
1033 | int first; | ||
1034 | int pad; | ||
1035 | struct kvec *iov; | ||
1036 | char *tmp; | ||
1037 | |||
1038 | opaque_len = p++; | ||
1039 | offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base; | ||
1040 | *p++ = htonl(rqstp->rq_seqno); | ||
1041 | |||
1042 | status = encode(rqstp, p, obj); | ||
1043 | if (status) | ||
1044 | return status; | ||
1045 | |||
1046 | status = alloc_enc_pages(rqstp); | ||
1047 | if (status) | ||
1048 | return status; | ||
1049 | first = snd_buf->page_base >> PAGE_CACHE_SHIFT; | ||
1050 | inpages = snd_buf->pages + first; | ||
1051 | snd_buf->pages = rqstp->rq_enc_pages; | ||
1052 | snd_buf->page_base -= first << PAGE_CACHE_SHIFT; | ||
1053 | /* Give the tail its own page, in case we need extra space in the | ||
1054 | * head when wrapping: */ | ||
1055 | if (snd_buf->page_len || snd_buf->tail[0].iov_len) { | ||
1056 | tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]); | ||
1057 | memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len); | ||
1058 | snd_buf->tail[0].iov_base = tmp; | ||
1059 | } | ||
1060 | maj_stat = gss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, offset, | ||
1061 | snd_buf, inpages); | ||
1062 | /* RPC_SLACK_SPACE should prevent this ever happening: */ | ||
1063 | BUG_ON(snd_buf->len > snd_buf->buflen); | ||
1064 | status = -EIO; | ||
1065 | /* We're assuming that when GSS_S_CONTEXT_EXPIRED, the encryption was | ||
1066 | * done anyway, so it's safe to put the request on the wire: */ | ||
1067 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | ||
1068 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | ||
1069 | else if (maj_stat) | ||
1070 | return status; | ||
1071 | |||
1072 | *opaque_len = htonl(snd_buf->len - offset); | ||
1073 | /* guess whether we're in the head or the tail: */ | ||
1074 | if (snd_buf->page_len || snd_buf->tail[0].iov_len) | ||
1075 | iov = snd_buf->tail; | ||
1076 | else | ||
1077 | iov = snd_buf->head; | ||
1078 | p = iov->iov_base + iov->iov_len; | ||
1079 | pad = 3 - ((snd_buf->len - offset - 1) & 3); | ||
1080 | memset(p, 0, pad); | ||
1081 | iov->iov_len += pad; | ||
1082 | snd_buf->len += pad; | ||
1083 | |||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
978 | static int | 1087 | static int |
979 | gss_wrap_req(struct rpc_task *task, | 1088 | gss_wrap_req(struct rpc_task *task, |
980 | kxdrproc_t encode, void *rqstp, u32 *p, void *obj) | 1089 | kxdrproc_t encode, void *rqstp, u32 *p, void *obj) |
@@ -1002,6 +1111,8 @@ gss_wrap_req(struct rpc_task *task, | |||
1002 | rqstp, p, obj); | 1111 | rqstp, p, obj); |
1003 | break; | 1112 | break; |
1004 | case RPC_GSS_SVC_PRIVACY: | 1113 | case RPC_GSS_SVC_PRIVACY: |
1114 | status = gss_wrap_req_priv(cred, ctx, encode, | ||
1115 | rqstp, p, obj); | ||
1005 | break; | 1116 | break; |
1006 | } | 1117 | } |
1007 | out: | 1118 | out: |
@@ -1048,6 +1159,36 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | |||
1048 | return 0; | 1159 | return 0; |
1049 | } | 1160 | } |
1050 | 1161 | ||
1162 | static inline int | ||
1163 | gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx, | ||
1164 | struct rpc_rqst *rqstp, u32 **p) | ||
1165 | { | ||
1166 | struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf; | ||
1167 | u32 offset; | ||
1168 | u32 opaque_len; | ||
1169 | u32 maj_stat; | ||
1170 | int status = -EIO; | ||
1171 | |||
1172 | opaque_len = ntohl(*(*p)++); | ||
1173 | offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base; | ||
1174 | if (offset + opaque_len > rcv_buf->len) | ||
1175 | return status; | ||
1176 | /* remove padding: */ | ||
1177 | rcv_buf->len = offset + opaque_len; | ||
1178 | |||
1179 | maj_stat = gss_unwrap(ctx->gc_gss_ctx, NULL, | ||
1180 | offset, rcv_buf); | ||
1181 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | ||
1182 | cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE; | ||
1183 | if (maj_stat != GSS_S_COMPLETE) | ||
1184 | return status; | ||
1185 | if (ntohl(*(*p)++) != rqstp->rq_seqno) | ||
1186 | return status; | ||
1187 | |||
1188 | return 0; | ||
1189 | } | ||
1190 | |||
1191 | |||
1051 | static int | 1192 | static int |
1052 | gss_unwrap_resp(struct rpc_task *task, | 1193 | gss_unwrap_resp(struct rpc_task *task, |
1053 | kxdrproc_t decode, void *rqstp, u32 *p, void *obj) | 1194 | kxdrproc_t decode, void *rqstp, u32 *p, void *obj) |
@@ -1057,6 +1198,8 @@ gss_unwrap_resp(struct rpc_task *task, | |||
1057 | gc_base); | 1198 | gc_base); |
1058 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); | 1199 | struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); |
1059 | u32 *savedp = p; | 1200 | u32 *savedp = p; |
1201 | struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head; | ||
1202 | int savedlen = head->iov_len; | ||
1060 | int status = -EIO; | 1203 | int status = -EIO; |
1061 | 1204 | ||
1062 | if (ctx->gc_proc != RPC_GSS_PROC_DATA) | 1205 | if (ctx->gc_proc != RPC_GSS_PROC_DATA) |
@@ -1070,10 +1213,14 @@ gss_unwrap_resp(struct rpc_task *task, | |||
1070 | goto out; | 1213 | goto out; |
1071 | break; | 1214 | break; |
1072 | case RPC_GSS_SVC_PRIVACY: | 1215 | case RPC_GSS_SVC_PRIVACY: |
1216 | status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p); | ||
1217 | if (status) | ||
1218 | goto out; | ||
1073 | break; | 1219 | break; |
1074 | } | 1220 | } |
1075 | /* take into account extra slack for integrity and privacy cases: */ | 1221 | /* take into account extra slack for integrity and privacy cases: */ |
1076 | task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp); | 1222 | task->tk_auth->au_rslack = task->tk_auth->au_verfsize + (p - savedp) |
1223 | + (savedlen - head->iov_len); | ||
1077 | out_decode: | 1224 | out_decode: |
1078 | status = decode(rqstp, p, obj); | 1225 | status = decode(rqstp, p, obj); |
1079 | out: | 1226 | out: |