aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@fieldses.org>2005-10-13 16:54:58 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-19 02:19:44 -0400
commit2d2da60c63b67174add32f06e8d54c3a0c5cd9cf (patch)
tree4b9df421a02217e1cd23b601b6c05c592d0bdf02 /net/sunrpc
parent24b2605becc10ca63c4c30808fa59a8abbf68727 (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')
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c149
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
979static void
980priv_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
989static int
990alloc_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;
1015out_free:
1016 for (i--; i >= 0; i--) {
1017 __free_page(rqstp->rq_enc_pages[i]);
1018 }
1019out:
1020 return -EAGAIN;
1021}
1022
1023static inline int
1024gss_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
978static int 1087static int
979gss_wrap_req(struct rpc_task *task, 1088gss_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 }
1007out: 1118out:
@@ -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
1162static inline int
1163gss_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
1051static int 1192static int
1052gss_unwrap_resp(struct rpc_task *task, 1193gss_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);
1077out_decode: 1224out_decode:
1078 status = decode(rqstp, p, obj); 1225 status = decode(rqstp, p, obj);
1079out: 1226out: