Commit 2d2da60c63b67174add32f06e8d54c3a0c5cd9cf

Authored by J. Bruce Fields
Committed by Trond Myklebust
1 parent 24b2605bec

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>

Showing 1 changed file with 148 additions and 1 deletions Side-by-side Diff

net/sunrpc/auth_gss/auth_gss.c
... ... @@ -43,6 +43,7 @@
43 43 #include <linux/types.h>
44 44 #include <linux/slab.h>
45 45 #include <linux/sched.h>
  46 +#include <linux/pagemap.h>
46 47 #include <linux/sunrpc/clnt.h>
47 48 #include <linux/sunrpc/auth.h>
48 49 #include <linux/sunrpc/auth_gss.h>
49 50  
... ... @@ -975,7 +976,115 @@
975 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 +
978 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 +
  1087 +static int
979 1088 gss_wrap_req(struct rpc_task *task,
980 1089 kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
981 1090 {
... ... @@ -1002,6 +1111,8 @@
1002 1111 rqstp, p, obj);
1003 1112 break;
1004 1113 case RPC_GSS_SVC_PRIVACY:
  1114 + status = gss_wrap_req_priv(cred, ctx, encode,
  1115 + rqstp, p, obj);
1005 1116 break;
1006 1117 }
1007 1118 out:
... ... @@ -1048,6 +1159,36 @@
1048 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 1192 static int
1052 1193 gss_unwrap_resp(struct rpc_task *task,
1053 1194 kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
... ... @@ -1057,6 +1198,8 @@
1057 1198 gc_base);
1058 1199 struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
1059 1200 u32 *savedp = p;
  1201 + struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
  1202 + int savedlen = head->iov_len;
1060 1203 int status = -EIO;
1061 1204  
1062 1205 if (ctx->gc_proc != RPC_GSS_PROC_DATA)
1063 1206  
... ... @@ -1070,10 +1213,14 @@
1070 1213 goto out;
1071 1214 break;
1072 1215 case RPC_GSS_SVC_PRIVACY:
  1216 + status = gss_unwrap_resp_priv(cred, ctx, rqstp, &p);
  1217 + if (status)
  1218 + goto out;
1073 1219 break;
1074 1220 }
1075 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 1224 out_decode:
1078 1225 status = decode(rqstp, p, obj);
1079 1226 out: