1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Neil Brown <neilb@cse.unsw.edu.au>
4*4882a593Smuzhiyun * J. Bruce Fields <bfields@umich.edu>
5*4882a593Smuzhiyun * Andy Adamson <andros@umich.edu>
6*4882a593Smuzhiyun * Dug Song <dugsong@monkey.org>
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * RPCSEC_GSS server authentication.
9*4882a593Smuzhiyun * This implements RPCSEC_GSS as defined in rfc2203 (rpcsec_gss) and rfc2078
10*4882a593Smuzhiyun * (gssapi)
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * The RPCSEC_GSS involves three stages:
13*4882a593Smuzhiyun * 1/ context creation
14*4882a593Smuzhiyun * 2/ data exchange
15*4882a593Smuzhiyun * 3/ context destruction
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * Context creation is handled largely by upcalls to user-space.
18*4882a593Smuzhiyun * In particular, GSS_Accept_sec_context is handled by an upcall
19*4882a593Smuzhiyun * Data exchange is handled entirely within the kernel
20*4882a593Smuzhiyun * In particular, GSS_GetMIC, GSS_VerifyMIC, GSS_Seal, GSS_Unseal are in-kernel.
21*4882a593Smuzhiyun * Context destruction is handled in-kernel
22*4882a593Smuzhiyun * GSS_Delete_sec_context is in-kernel
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * Context creation is initiated by a RPCSEC_GSS_INIT request arriving.
25*4882a593Smuzhiyun * The context handle and gss_token are used as a key into the rpcsec_init cache.
26*4882a593Smuzhiyun * The content of this cache includes some of the outputs of GSS_Accept_sec_context,
27*4882a593Smuzhiyun * being major_status, minor_status, context_handle, reply_token.
28*4882a593Smuzhiyun * These are sent back to the client.
29*4882a593Smuzhiyun * Sequence window management is handled by the kernel. The window size if currently
30*4882a593Smuzhiyun * a compile time constant.
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * When user-space is happy that a context is established, it places an entry
33*4882a593Smuzhiyun * in the rpcsec_context cache. The key for this cache is the context_handle.
34*4882a593Smuzhiyun * The content includes:
35*4882a593Smuzhiyun * uid/gidlist - for determining access rights
36*4882a593Smuzhiyun * mechanism type
37*4882a593Smuzhiyun * mechanism specific information, such as a key
38*4882a593Smuzhiyun *
39*4882a593Smuzhiyun */
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #include <linux/slab.h>
42*4882a593Smuzhiyun #include <linux/types.h>
43*4882a593Smuzhiyun #include <linux/module.h>
44*4882a593Smuzhiyun #include <linux/pagemap.h>
45*4882a593Smuzhiyun #include <linux/user_namespace.h>
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #include <linux/sunrpc/auth_gss.h>
48*4882a593Smuzhiyun #include <linux/sunrpc/gss_err.h>
49*4882a593Smuzhiyun #include <linux/sunrpc/svcauth.h>
50*4882a593Smuzhiyun #include <linux/sunrpc/svcauth_gss.h>
51*4882a593Smuzhiyun #include <linux/sunrpc/cache.h>
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun #include <trace/events/rpcgss.h>
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun #include "gss_rpc_upcall.h"
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests
59*4882a593Smuzhiyun * into replies.
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * Key is context handle (\x if empty) and gss_token.
62*4882a593Smuzhiyun * Content is major_status minor_status (integers) context_handle, reply_token.
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun */
65*4882a593Smuzhiyun
netobj_equal(struct xdr_netobj * a,struct xdr_netobj * b)66*4882a593Smuzhiyun static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun return a->len == b->len && 0 == memcmp(a->data, b->data, a->len);
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun #define RSI_HASHBITS 6
72*4882a593Smuzhiyun #define RSI_HASHMAX (1<<RSI_HASHBITS)
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun struct rsi {
75*4882a593Smuzhiyun struct cache_head h;
76*4882a593Smuzhiyun struct xdr_netobj in_handle, in_token;
77*4882a593Smuzhiyun struct xdr_netobj out_handle, out_token;
78*4882a593Smuzhiyun int major_status, minor_status;
79*4882a593Smuzhiyun struct rcu_head rcu_head;
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old);
83*4882a593Smuzhiyun static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item);
84*4882a593Smuzhiyun
rsi_free(struct rsi * rsii)85*4882a593Smuzhiyun static void rsi_free(struct rsi *rsii)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun kfree(rsii->in_handle.data);
88*4882a593Smuzhiyun kfree(rsii->in_token.data);
89*4882a593Smuzhiyun kfree(rsii->out_handle.data);
90*4882a593Smuzhiyun kfree(rsii->out_token.data);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
rsi_free_rcu(struct rcu_head * head)93*4882a593Smuzhiyun static void rsi_free_rcu(struct rcu_head *head)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun struct rsi *rsii = container_of(head, struct rsi, rcu_head);
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun rsi_free(rsii);
98*4882a593Smuzhiyun kfree(rsii);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
rsi_put(struct kref * ref)101*4882a593Smuzhiyun static void rsi_put(struct kref *ref)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun struct rsi *rsii = container_of(ref, struct rsi, h.ref);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun call_rcu(&rsii->rcu_head, rsi_free_rcu);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
rsi_hash(struct rsi * item)108*4882a593Smuzhiyun static inline int rsi_hash(struct rsi *item)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun return hash_mem(item->in_handle.data, item->in_handle.len, RSI_HASHBITS)
111*4882a593Smuzhiyun ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS);
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
rsi_match(struct cache_head * a,struct cache_head * b)114*4882a593Smuzhiyun static int rsi_match(struct cache_head *a, struct cache_head *b)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun struct rsi *item = container_of(a, struct rsi, h);
117*4882a593Smuzhiyun struct rsi *tmp = container_of(b, struct rsi, h);
118*4882a593Smuzhiyun return netobj_equal(&item->in_handle, &tmp->in_handle) &&
119*4882a593Smuzhiyun netobj_equal(&item->in_token, &tmp->in_token);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
dup_to_netobj(struct xdr_netobj * dst,char * src,int len)122*4882a593Smuzhiyun static int dup_to_netobj(struct xdr_netobj *dst, char *src, int len)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun dst->len = len;
125*4882a593Smuzhiyun dst->data = (len ? kmemdup(src, len, GFP_KERNEL) : NULL);
126*4882a593Smuzhiyun if (len && !dst->data)
127*4882a593Smuzhiyun return -ENOMEM;
128*4882a593Smuzhiyun return 0;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
dup_netobj(struct xdr_netobj * dst,struct xdr_netobj * src)131*4882a593Smuzhiyun static inline int dup_netobj(struct xdr_netobj *dst, struct xdr_netobj *src)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun return dup_to_netobj(dst, src->data, src->len);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
rsi_init(struct cache_head * cnew,struct cache_head * citem)136*4882a593Smuzhiyun static void rsi_init(struct cache_head *cnew, struct cache_head *citem)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun struct rsi *new = container_of(cnew, struct rsi, h);
139*4882a593Smuzhiyun struct rsi *item = container_of(citem, struct rsi, h);
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun new->out_handle.data = NULL;
142*4882a593Smuzhiyun new->out_handle.len = 0;
143*4882a593Smuzhiyun new->out_token.data = NULL;
144*4882a593Smuzhiyun new->out_token.len = 0;
145*4882a593Smuzhiyun new->in_handle.len = item->in_handle.len;
146*4882a593Smuzhiyun item->in_handle.len = 0;
147*4882a593Smuzhiyun new->in_token.len = item->in_token.len;
148*4882a593Smuzhiyun item->in_token.len = 0;
149*4882a593Smuzhiyun new->in_handle.data = item->in_handle.data;
150*4882a593Smuzhiyun item->in_handle.data = NULL;
151*4882a593Smuzhiyun new->in_token.data = item->in_token.data;
152*4882a593Smuzhiyun item->in_token.data = NULL;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
update_rsi(struct cache_head * cnew,struct cache_head * citem)155*4882a593Smuzhiyun static void update_rsi(struct cache_head *cnew, struct cache_head *citem)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun struct rsi *new = container_of(cnew, struct rsi, h);
158*4882a593Smuzhiyun struct rsi *item = container_of(citem, struct rsi, h);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun BUG_ON(new->out_handle.data || new->out_token.data);
161*4882a593Smuzhiyun new->out_handle.len = item->out_handle.len;
162*4882a593Smuzhiyun item->out_handle.len = 0;
163*4882a593Smuzhiyun new->out_token.len = item->out_token.len;
164*4882a593Smuzhiyun item->out_token.len = 0;
165*4882a593Smuzhiyun new->out_handle.data = item->out_handle.data;
166*4882a593Smuzhiyun item->out_handle.data = NULL;
167*4882a593Smuzhiyun new->out_token.data = item->out_token.data;
168*4882a593Smuzhiyun item->out_token.data = NULL;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun new->major_status = item->major_status;
171*4882a593Smuzhiyun new->minor_status = item->minor_status;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
rsi_alloc(void)174*4882a593Smuzhiyun static struct cache_head *rsi_alloc(void)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun struct rsi *rsii = kmalloc(sizeof(*rsii), GFP_KERNEL);
177*4882a593Smuzhiyun if (rsii)
178*4882a593Smuzhiyun return &rsii->h;
179*4882a593Smuzhiyun else
180*4882a593Smuzhiyun return NULL;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
rsi_upcall(struct cache_detail * cd,struct cache_head * h)183*4882a593Smuzhiyun static int rsi_upcall(struct cache_detail *cd, struct cache_head *h)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun return sunrpc_cache_pipe_upcall_timeout(cd, h);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
rsi_request(struct cache_detail * cd,struct cache_head * h,char ** bpp,int * blen)188*4882a593Smuzhiyun static void rsi_request(struct cache_detail *cd,
189*4882a593Smuzhiyun struct cache_head *h,
190*4882a593Smuzhiyun char **bpp, int *blen)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun struct rsi *rsii = container_of(h, struct rsi, h);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun qword_addhex(bpp, blen, rsii->in_handle.data, rsii->in_handle.len);
195*4882a593Smuzhiyun qword_addhex(bpp, blen, rsii->in_token.data, rsii->in_token.len);
196*4882a593Smuzhiyun (*bpp)[-1] = '\n';
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
rsi_parse(struct cache_detail * cd,char * mesg,int mlen)199*4882a593Smuzhiyun static int rsi_parse(struct cache_detail *cd,
200*4882a593Smuzhiyun char *mesg, int mlen)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun /* context token expiry major minor context token */
203*4882a593Smuzhiyun char *buf = mesg;
204*4882a593Smuzhiyun char *ep;
205*4882a593Smuzhiyun int len;
206*4882a593Smuzhiyun struct rsi rsii, *rsip = NULL;
207*4882a593Smuzhiyun time64_t expiry;
208*4882a593Smuzhiyun int status = -EINVAL;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun memset(&rsii, 0, sizeof(rsii));
211*4882a593Smuzhiyun /* handle */
212*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
213*4882a593Smuzhiyun if (len < 0)
214*4882a593Smuzhiyun goto out;
215*4882a593Smuzhiyun status = -ENOMEM;
216*4882a593Smuzhiyun if (dup_to_netobj(&rsii.in_handle, buf, len))
217*4882a593Smuzhiyun goto out;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* token */
220*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
221*4882a593Smuzhiyun status = -EINVAL;
222*4882a593Smuzhiyun if (len < 0)
223*4882a593Smuzhiyun goto out;
224*4882a593Smuzhiyun status = -ENOMEM;
225*4882a593Smuzhiyun if (dup_to_netobj(&rsii.in_token, buf, len))
226*4882a593Smuzhiyun goto out;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun rsip = rsi_lookup(cd, &rsii);
229*4882a593Smuzhiyun if (!rsip)
230*4882a593Smuzhiyun goto out;
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun rsii.h.flags = 0;
233*4882a593Smuzhiyun /* expiry */
234*4882a593Smuzhiyun expiry = get_expiry(&mesg);
235*4882a593Smuzhiyun status = -EINVAL;
236*4882a593Smuzhiyun if (expiry == 0)
237*4882a593Smuzhiyun goto out;
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun /* major/minor */
240*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
241*4882a593Smuzhiyun if (len <= 0)
242*4882a593Smuzhiyun goto out;
243*4882a593Smuzhiyun rsii.major_status = simple_strtoul(buf, &ep, 10);
244*4882a593Smuzhiyun if (*ep)
245*4882a593Smuzhiyun goto out;
246*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
247*4882a593Smuzhiyun if (len <= 0)
248*4882a593Smuzhiyun goto out;
249*4882a593Smuzhiyun rsii.minor_status = simple_strtoul(buf, &ep, 10);
250*4882a593Smuzhiyun if (*ep)
251*4882a593Smuzhiyun goto out;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /* out_handle */
254*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
255*4882a593Smuzhiyun if (len < 0)
256*4882a593Smuzhiyun goto out;
257*4882a593Smuzhiyun status = -ENOMEM;
258*4882a593Smuzhiyun if (dup_to_netobj(&rsii.out_handle, buf, len))
259*4882a593Smuzhiyun goto out;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun /* out_token */
262*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
263*4882a593Smuzhiyun status = -EINVAL;
264*4882a593Smuzhiyun if (len < 0)
265*4882a593Smuzhiyun goto out;
266*4882a593Smuzhiyun status = -ENOMEM;
267*4882a593Smuzhiyun if (dup_to_netobj(&rsii.out_token, buf, len))
268*4882a593Smuzhiyun goto out;
269*4882a593Smuzhiyun rsii.h.expiry_time = expiry;
270*4882a593Smuzhiyun rsip = rsi_update(cd, &rsii, rsip);
271*4882a593Smuzhiyun status = 0;
272*4882a593Smuzhiyun out:
273*4882a593Smuzhiyun rsi_free(&rsii);
274*4882a593Smuzhiyun if (rsip)
275*4882a593Smuzhiyun cache_put(&rsip->h, cd);
276*4882a593Smuzhiyun else
277*4882a593Smuzhiyun status = -ENOMEM;
278*4882a593Smuzhiyun return status;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun static const struct cache_detail rsi_cache_template = {
282*4882a593Smuzhiyun .owner = THIS_MODULE,
283*4882a593Smuzhiyun .hash_size = RSI_HASHMAX,
284*4882a593Smuzhiyun .name = "auth.rpcsec.init",
285*4882a593Smuzhiyun .cache_put = rsi_put,
286*4882a593Smuzhiyun .cache_upcall = rsi_upcall,
287*4882a593Smuzhiyun .cache_request = rsi_request,
288*4882a593Smuzhiyun .cache_parse = rsi_parse,
289*4882a593Smuzhiyun .match = rsi_match,
290*4882a593Smuzhiyun .init = rsi_init,
291*4882a593Smuzhiyun .update = update_rsi,
292*4882a593Smuzhiyun .alloc = rsi_alloc,
293*4882a593Smuzhiyun };
294*4882a593Smuzhiyun
rsi_lookup(struct cache_detail * cd,struct rsi * item)295*4882a593Smuzhiyun static struct rsi *rsi_lookup(struct cache_detail *cd, struct rsi *item)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun struct cache_head *ch;
298*4882a593Smuzhiyun int hash = rsi_hash(item);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun ch = sunrpc_cache_lookup_rcu(cd, &item->h, hash);
301*4882a593Smuzhiyun if (ch)
302*4882a593Smuzhiyun return container_of(ch, struct rsi, h);
303*4882a593Smuzhiyun else
304*4882a593Smuzhiyun return NULL;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
rsi_update(struct cache_detail * cd,struct rsi * new,struct rsi * old)307*4882a593Smuzhiyun static struct rsi *rsi_update(struct cache_detail *cd, struct rsi *new, struct rsi *old)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun struct cache_head *ch;
310*4882a593Smuzhiyun int hash = rsi_hash(new);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun ch = sunrpc_cache_update(cd, &new->h,
313*4882a593Smuzhiyun &old->h, hash);
314*4882a593Smuzhiyun if (ch)
315*4882a593Smuzhiyun return container_of(ch, struct rsi, h);
316*4882a593Smuzhiyun else
317*4882a593Smuzhiyun return NULL;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun * The rpcsec_context cache is used to store a context that is
323*4882a593Smuzhiyun * used in data exchange.
324*4882a593Smuzhiyun * The key is a context handle. The content is:
325*4882a593Smuzhiyun * uid, gidlist, mechanism, service-set, mech-specific-data
326*4882a593Smuzhiyun */
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun #define RSC_HASHBITS 10
329*4882a593Smuzhiyun #define RSC_HASHMAX (1<<RSC_HASHBITS)
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun #define GSS_SEQ_WIN 128
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun struct gss_svc_seq_data {
334*4882a593Smuzhiyun /* highest seq number seen so far: */
335*4882a593Smuzhiyun u32 sd_max;
336*4882a593Smuzhiyun /* for i such that sd_max-GSS_SEQ_WIN < i <= sd_max, the i-th bit of
337*4882a593Smuzhiyun * sd_win is nonzero iff sequence number i has been seen already: */
338*4882a593Smuzhiyun unsigned long sd_win[GSS_SEQ_WIN/BITS_PER_LONG];
339*4882a593Smuzhiyun spinlock_t sd_lock;
340*4882a593Smuzhiyun };
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun struct rsc {
343*4882a593Smuzhiyun struct cache_head h;
344*4882a593Smuzhiyun struct xdr_netobj handle;
345*4882a593Smuzhiyun struct svc_cred cred;
346*4882a593Smuzhiyun struct gss_svc_seq_data seqdata;
347*4882a593Smuzhiyun struct gss_ctx *mechctx;
348*4882a593Smuzhiyun struct rcu_head rcu_head;
349*4882a593Smuzhiyun };
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old);
352*4882a593Smuzhiyun static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item);
353*4882a593Smuzhiyun
rsc_free(struct rsc * rsci)354*4882a593Smuzhiyun static void rsc_free(struct rsc *rsci)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun kfree(rsci->handle.data);
357*4882a593Smuzhiyun if (rsci->mechctx)
358*4882a593Smuzhiyun gss_delete_sec_context(&rsci->mechctx);
359*4882a593Smuzhiyun free_svc_cred(&rsci->cred);
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
rsc_free_rcu(struct rcu_head * head)362*4882a593Smuzhiyun static void rsc_free_rcu(struct rcu_head *head)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct rsc *rsci = container_of(head, struct rsc, rcu_head);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun kfree(rsci->handle.data);
367*4882a593Smuzhiyun kfree(rsci);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun
rsc_put(struct kref * ref)370*4882a593Smuzhiyun static void rsc_put(struct kref *ref)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun struct rsc *rsci = container_of(ref, struct rsc, h.ref);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (rsci->mechctx)
375*4882a593Smuzhiyun gss_delete_sec_context(&rsci->mechctx);
376*4882a593Smuzhiyun free_svc_cred(&rsci->cred);
377*4882a593Smuzhiyun call_rcu(&rsci->rcu_head, rsc_free_rcu);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun static inline int
rsc_hash(struct rsc * rsci)381*4882a593Smuzhiyun rsc_hash(struct rsc *rsci)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun static int
rsc_match(struct cache_head * a,struct cache_head * b)387*4882a593Smuzhiyun rsc_match(struct cache_head *a, struct cache_head *b)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun struct rsc *new = container_of(a, struct rsc, h);
390*4882a593Smuzhiyun struct rsc *tmp = container_of(b, struct rsc, h);
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun return netobj_equal(&new->handle, &tmp->handle);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun static void
rsc_init(struct cache_head * cnew,struct cache_head * ctmp)396*4882a593Smuzhiyun rsc_init(struct cache_head *cnew, struct cache_head *ctmp)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct rsc *new = container_of(cnew, struct rsc, h);
399*4882a593Smuzhiyun struct rsc *tmp = container_of(ctmp, struct rsc, h);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun new->handle.len = tmp->handle.len;
402*4882a593Smuzhiyun tmp->handle.len = 0;
403*4882a593Smuzhiyun new->handle.data = tmp->handle.data;
404*4882a593Smuzhiyun tmp->handle.data = NULL;
405*4882a593Smuzhiyun new->mechctx = NULL;
406*4882a593Smuzhiyun init_svc_cred(&new->cred);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun static void
update_rsc(struct cache_head * cnew,struct cache_head * ctmp)410*4882a593Smuzhiyun update_rsc(struct cache_head *cnew, struct cache_head *ctmp)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun struct rsc *new = container_of(cnew, struct rsc, h);
413*4882a593Smuzhiyun struct rsc *tmp = container_of(ctmp, struct rsc, h);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun new->mechctx = tmp->mechctx;
416*4882a593Smuzhiyun tmp->mechctx = NULL;
417*4882a593Smuzhiyun memset(&new->seqdata, 0, sizeof(new->seqdata));
418*4882a593Smuzhiyun spin_lock_init(&new->seqdata.sd_lock);
419*4882a593Smuzhiyun new->cred = tmp->cred;
420*4882a593Smuzhiyun init_svc_cred(&tmp->cred);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun static struct cache_head *
rsc_alloc(void)424*4882a593Smuzhiyun rsc_alloc(void)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun struct rsc *rsci = kmalloc(sizeof(*rsci), GFP_KERNEL);
427*4882a593Smuzhiyun if (rsci)
428*4882a593Smuzhiyun return &rsci->h;
429*4882a593Smuzhiyun else
430*4882a593Smuzhiyun return NULL;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
rsc_upcall(struct cache_detail * cd,struct cache_head * h)433*4882a593Smuzhiyun static int rsc_upcall(struct cache_detail *cd, struct cache_head *h)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun return -EINVAL;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
rsc_parse(struct cache_detail * cd,char * mesg,int mlen)438*4882a593Smuzhiyun static int rsc_parse(struct cache_detail *cd,
439*4882a593Smuzhiyun char *mesg, int mlen)
440*4882a593Smuzhiyun {
441*4882a593Smuzhiyun /* contexthandle expiry [ uid gid N <n gids> mechname ...mechdata... ] */
442*4882a593Smuzhiyun char *buf = mesg;
443*4882a593Smuzhiyun int id;
444*4882a593Smuzhiyun int len, rv;
445*4882a593Smuzhiyun struct rsc rsci, *rscp = NULL;
446*4882a593Smuzhiyun time64_t expiry;
447*4882a593Smuzhiyun int status = -EINVAL;
448*4882a593Smuzhiyun struct gss_api_mech *gm = NULL;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun memset(&rsci, 0, sizeof(rsci));
451*4882a593Smuzhiyun /* context handle */
452*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
453*4882a593Smuzhiyun if (len < 0) goto out;
454*4882a593Smuzhiyun status = -ENOMEM;
455*4882a593Smuzhiyun if (dup_to_netobj(&rsci.handle, buf, len))
456*4882a593Smuzhiyun goto out;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun rsci.h.flags = 0;
459*4882a593Smuzhiyun /* expiry */
460*4882a593Smuzhiyun expiry = get_expiry(&mesg);
461*4882a593Smuzhiyun status = -EINVAL;
462*4882a593Smuzhiyun if (expiry == 0)
463*4882a593Smuzhiyun goto out;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun rscp = rsc_lookup(cd, &rsci);
466*4882a593Smuzhiyun if (!rscp)
467*4882a593Smuzhiyun goto out;
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* uid, or NEGATIVE */
470*4882a593Smuzhiyun rv = get_int(&mesg, &id);
471*4882a593Smuzhiyun if (rv == -EINVAL)
472*4882a593Smuzhiyun goto out;
473*4882a593Smuzhiyun if (rv == -ENOENT)
474*4882a593Smuzhiyun set_bit(CACHE_NEGATIVE, &rsci.h.flags);
475*4882a593Smuzhiyun else {
476*4882a593Smuzhiyun int N, i;
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /*
479*4882a593Smuzhiyun * NOTE: we skip uid_valid()/gid_valid() checks here:
480*4882a593Smuzhiyun * instead, * -1 id's are later mapped to the
481*4882a593Smuzhiyun * (export-specific) anonymous id by nfsd_setuser.
482*4882a593Smuzhiyun *
483*4882a593Smuzhiyun * (But supplementary gid's get no such special
484*4882a593Smuzhiyun * treatment so are checked for validity here.)
485*4882a593Smuzhiyun */
486*4882a593Smuzhiyun /* uid */
487*4882a593Smuzhiyun rsci.cred.cr_uid = make_kuid(current_user_ns(), id);
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /* gid */
490*4882a593Smuzhiyun if (get_int(&mesg, &id))
491*4882a593Smuzhiyun goto out;
492*4882a593Smuzhiyun rsci.cred.cr_gid = make_kgid(current_user_ns(), id);
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun /* number of additional gid's */
495*4882a593Smuzhiyun if (get_int(&mesg, &N))
496*4882a593Smuzhiyun goto out;
497*4882a593Smuzhiyun if (N < 0 || N > NGROUPS_MAX)
498*4882a593Smuzhiyun goto out;
499*4882a593Smuzhiyun status = -ENOMEM;
500*4882a593Smuzhiyun rsci.cred.cr_group_info = groups_alloc(N);
501*4882a593Smuzhiyun if (rsci.cred.cr_group_info == NULL)
502*4882a593Smuzhiyun goto out;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun /* gid's */
505*4882a593Smuzhiyun status = -EINVAL;
506*4882a593Smuzhiyun for (i=0; i<N; i++) {
507*4882a593Smuzhiyun kgid_t kgid;
508*4882a593Smuzhiyun if (get_int(&mesg, &id))
509*4882a593Smuzhiyun goto out;
510*4882a593Smuzhiyun kgid = make_kgid(current_user_ns(), id);
511*4882a593Smuzhiyun if (!gid_valid(kgid))
512*4882a593Smuzhiyun goto out;
513*4882a593Smuzhiyun rsci.cred.cr_group_info->gid[i] = kgid;
514*4882a593Smuzhiyun }
515*4882a593Smuzhiyun groups_sort(rsci.cred.cr_group_info);
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun /* mech name */
518*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
519*4882a593Smuzhiyun if (len < 0)
520*4882a593Smuzhiyun goto out;
521*4882a593Smuzhiyun gm = rsci.cred.cr_gss_mech = gss_mech_get_by_name(buf);
522*4882a593Smuzhiyun status = -EOPNOTSUPP;
523*4882a593Smuzhiyun if (!gm)
524*4882a593Smuzhiyun goto out;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun status = -EINVAL;
527*4882a593Smuzhiyun /* mech-specific data: */
528*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
529*4882a593Smuzhiyun if (len < 0)
530*4882a593Smuzhiyun goto out;
531*4882a593Smuzhiyun status = gss_import_sec_context(buf, len, gm, &rsci.mechctx,
532*4882a593Smuzhiyun NULL, GFP_KERNEL);
533*4882a593Smuzhiyun if (status)
534*4882a593Smuzhiyun goto out;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun /* get client name */
537*4882a593Smuzhiyun len = qword_get(&mesg, buf, mlen);
538*4882a593Smuzhiyun if (len > 0) {
539*4882a593Smuzhiyun rsci.cred.cr_principal = kstrdup(buf, GFP_KERNEL);
540*4882a593Smuzhiyun if (!rsci.cred.cr_principal) {
541*4882a593Smuzhiyun status = -ENOMEM;
542*4882a593Smuzhiyun goto out;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun rsci.h.expiry_time = expiry;
548*4882a593Smuzhiyun rscp = rsc_update(cd, &rsci, rscp);
549*4882a593Smuzhiyun status = 0;
550*4882a593Smuzhiyun out:
551*4882a593Smuzhiyun rsc_free(&rsci);
552*4882a593Smuzhiyun if (rscp)
553*4882a593Smuzhiyun cache_put(&rscp->h, cd);
554*4882a593Smuzhiyun else
555*4882a593Smuzhiyun status = -ENOMEM;
556*4882a593Smuzhiyun return status;
557*4882a593Smuzhiyun }
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun static const struct cache_detail rsc_cache_template = {
560*4882a593Smuzhiyun .owner = THIS_MODULE,
561*4882a593Smuzhiyun .hash_size = RSC_HASHMAX,
562*4882a593Smuzhiyun .name = "auth.rpcsec.context",
563*4882a593Smuzhiyun .cache_put = rsc_put,
564*4882a593Smuzhiyun .cache_upcall = rsc_upcall,
565*4882a593Smuzhiyun .cache_parse = rsc_parse,
566*4882a593Smuzhiyun .match = rsc_match,
567*4882a593Smuzhiyun .init = rsc_init,
568*4882a593Smuzhiyun .update = update_rsc,
569*4882a593Smuzhiyun .alloc = rsc_alloc,
570*4882a593Smuzhiyun };
571*4882a593Smuzhiyun
rsc_lookup(struct cache_detail * cd,struct rsc * item)572*4882a593Smuzhiyun static struct rsc *rsc_lookup(struct cache_detail *cd, struct rsc *item)
573*4882a593Smuzhiyun {
574*4882a593Smuzhiyun struct cache_head *ch;
575*4882a593Smuzhiyun int hash = rsc_hash(item);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun ch = sunrpc_cache_lookup_rcu(cd, &item->h, hash);
578*4882a593Smuzhiyun if (ch)
579*4882a593Smuzhiyun return container_of(ch, struct rsc, h);
580*4882a593Smuzhiyun else
581*4882a593Smuzhiyun return NULL;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
rsc_update(struct cache_detail * cd,struct rsc * new,struct rsc * old)584*4882a593Smuzhiyun static struct rsc *rsc_update(struct cache_detail *cd, struct rsc *new, struct rsc *old)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun struct cache_head *ch;
587*4882a593Smuzhiyun int hash = rsc_hash(new);
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun ch = sunrpc_cache_update(cd, &new->h,
590*4882a593Smuzhiyun &old->h, hash);
591*4882a593Smuzhiyun if (ch)
592*4882a593Smuzhiyun return container_of(ch, struct rsc, h);
593*4882a593Smuzhiyun else
594*4882a593Smuzhiyun return NULL;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun static struct rsc *
gss_svc_searchbyctx(struct cache_detail * cd,struct xdr_netobj * handle)599*4882a593Smuzhiyun gss_svc_searchbyctx(struct cache_detail *cd, struct xdr_netobj *handle)
600*4882a593Smuzhiyun {
601*4882a593Smuzhiyun struct rsc rsci;
602*4882a593Smuzhiyun struct rsc *found;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun memset(&rsci, 0, sizeof(rsci));
605*4882a593Smuzhiyun if (dup_to_netobj(&rsci.handle, handle->data, handle->len))
606*4882a593Smuzhiyun return NULL;
607*4882a593Smuzhiyun found = rsc_lookup(cd, &rsci);
608*4882a593Smuzhiyun rsc_free(&rsci);
609*4882a593Smuzhiyun if (!found)
610*4882a593Smuzhiyun return NULL;
611*4882a593Smuzhiyun if (cache_check(cd, &found->h, NULL))
612*4882a593Smuzhiyun return NULL;
613*4882a593Smuzhiyun return found;
614*4882a593Smuzhiyun }
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun /**
617*4882a593Smuzhiyun * gss_check_seq_num - GSS sequence number window check
618*4882a593Smuzhiyun * @rqstp: RPC Call to use when reporting errors
619*4882a593Smuzhiyun * @rsci: cached GSS context state (updated on return)
620*4882a593Smuzhiyun * @seq_num: sequence number to check
621*4882a593Smuzhiyun *
622*4882a593Smuzhiyun * Implements sequence number algorithm as specified in
623*4882a593Smuzhiyun * RFC 2203, Section 5.3.3.1. "Context Management".
624*4882a593Smuzhiyun *
625*4882a593Smuzhiyun * Return values:
626*4882a593Smuzhiyun * %true: @rqstp's GSS sequence number is inside the window
627*4882a593Smuzhiyun * %false: @rqstp's GSS sequence number is outside the window
628*4882a593Smuzhiyun */
gss_check_seq_num(const struct svc_rqst * rqstp,struct rsc * rsci,u32 seq_num)629*4882a593Smuzhiyun static bool gss_check_seq_num(const struct svc_rqst *rqstp, struct rsc *rsci,
630*4882a593Smuzhiyun u32 seq_num)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun struct gss_svc_seq_data *sd = &rsci->seqdata;
633*4882a593Smuzhiyun bool result = false;
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun spin_lock(&sd->sd_lock);
636*4882a593Smuzhiyun if (seq_num > sd->sd_max) {
637*4882a593Smuzhiyun if (seq_num >= sd->sd_max + GSS_SEQ_WIN) {
638*4882a593Smuzhiyun memset(sd->sd_win, 0, sizeof(sd->sd_win));
639*4882a593Smuzhiyun sd->sd_max = seq_num;
640*4882a593Smuzhiyun } else while (sd->sd_max < seq_num) {
641*4882a593Smuzhiyun sd->sd_max++;
642*4882a593Smuzhiyun __clear_bit(sd->sd_max % GSS_SEQ_WIN, sd->sd_win);
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun __set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win);
645*4882a593Smuzhiyun goto ok;
646*4882a593Smuzhiyun } else if (seq_num + GSS_SEQ_WIN <= sd->sd_max) {
647*4882a593Smuzhiyun goto toolow;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun if (__test_and_set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win))
650*4882a593Smuzhiyun goto alreadyseen;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun ok:
653*4882a593Smuzhiyun result = true;
654*4882a593Smuzhiyun out:
655*4882a593Smuzhiyun spin_unlock(&sd->sd_lock);
656*4882a593Smuzhiyun return result;
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun toolow:
659*4882a593Smuzhiyun trace_rpcgss_svc_seqno_low(rqstp, seq_num,
660*4882a593Smuzhiyun sd->sd_max - GSS_SEQ_WIN,
661*4882a593Smuzhiyun sd->sd_max);
662*4882a593Smuzhiyun goto out;
663*4882a593Smuzhiyun alreadyseen:
664*4882a593Smuzhiyun trace_rpcgss_svc_seqno_seen(rqstp, seq_num);
665*4882a593Smuzhiyun goto out;
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
round_up_to_quad(u32 i)668*4882a593Smuzhiyun static inline u32 round_up_to_quad(u32 i)
669*4882a593Smuzhiyun {
670*4882a593Smuzhiyun return (i + 3 ) & ~3;
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun static inline int
svc_safe_getnetobj(struct kvec * argv,struct xdr_netobj * o)674*4882a593Smuzhiyun svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o)
675*4882a593Smuzhiyun {
676*4882a593Smuzhiyun int l;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun if (argv->iov_len < 4)
679*4882a593Smuzhiyun return -1;
680*4882a593Smuzhiyun o->len = svc_getnl(argv);
681*4882a593Smuzhiyun l = round_up_to_quad(o->len);
682*4882a593Smuzhiyun if (argv->iov_len < l)
683*4882a593Smuzhiyun return -1;
684*4882a593Smuzhiyun o->data = argv->iov_base;
685*4882a593Smuzhiyun argv->iov_base += l;
686*4882a593Smuzhiyun argv->iov_len -= l;
687*4882a593Smuzhiyun return 0;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun static inline int
svc_safe_putnetobj(struct kvec * resv,struct xdr_netobj * o)691*4882a593Smuzhiyun svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun u8 *p;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun if (resv->iov_len + 4 > PAGE_SIZE)
696*4882a593Smuzhiyun return -1;
697*4882a593Smuzhiyun svc_putnl(resv, o->len);
698*4882a593Smuzhiyun p = resv->iov_base + resv->iov_len;
699*4882a593Smuzhiyun resv->iov_len += round_up_to_quad(o->len);
700*4882a593Smuzhiyun if (resv->iov_len > PAGE_SIZE)
701*4882a593Smuzhiyun return -1;
702*4882a593Smuzhiyun memcpy(p, o->data, o->len);
703*4882a593Smuzhiyun memset(p + o->len, 0, round_up_to_quad(o->len) - o->len);
704*4882a593Smuzhiyun return 0;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun /*
708*4882a593Smuzhiyun * Verify the checksum on the header and return SVC_OK on success.
709*4882a593Smuzhiyun * Otherwise, return SVC_DROP (in the case of a bad sequence number)
710*4882a593Smuzhiyun * or return SVC_DENIED and indicate error in authp.
711*4882a593Smuzhiyun */
712*4882a593Smuzhiyun static int
gss_verify_header(struct svc_rqst * rqstp,struct rsc * rsci,__be32 * rpcstart,struct rpc_gss_wire_cred * gc,__be32 * authp)713*4882a593Smuzhiyun gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
714*4882a593Smuzhiyun __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp)
715*4882a593Smuzhiyun {
716*4882a593Smuzhiyun struct gss_ctx *ctx_id = rsci->mechctx;
717*4882a593Smuzhiyun struct xdr_buf rpchdr;
718*4882a593Smuzhiyun struct xdr_netobj checksum;
719*4882a593Smuzhiyun u32 flavor = 0;
720*4882a593Smuzhiyun struct kvec *argv = &rqstp->rq_arg.head[0];
721*4882a593Smuzhiyun struct kvec iov;
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun /* data to compute the checksum over: */
724*4882a593Smuzhiyun iov.iov_base = rpcstart;
725*4882a593Smuzhiyun iov.iov_len = (u8 *)argv->iov_base - (u8 *)rpcstart;
726*4882a593Smuzhiyun xdr_buf_from_iov(&iov, &rpchdr);
727*4882a593Smuzhiyun
728*4882a593Smuzhiyun *authp = rpc_autherr_badverf;
729*4882a593Smuzhiyun if (argv->iov_len < 4)
730*4882a593Smuzhiyun return SVC_DENIED;
731*4882a593Smuzhiyun flavor = svc_getnl(argv);
732*4882a593Smuzhiyun if (flavor != RPC_AUTH_GSS)
733*4882a593Smuzhiyun return SVC_DENIED;
734*4882a593Smuzhiyun if (svc_safe_getnetobj(argv, &checksum))
735*4882a593Smuzhiyun return SVC_DENIED;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun if (rqstp->rq_deferred) /* skip verification of revisited request */
738*4882a593Smuzhiyun return SVC_OK;
739*4882a593Smuzhiyun if (gss_verify_mic(ctx_id, &rpchdr, &checksum) != GSS_S_COMPLETE) {
740*4882a593Smuzhiyun *authp = rpcsec_gsserr_credproblem;
741*4882a593Smuzhiyun return SVC_DENIED;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun if (gc->gc_seq > MAXSEQ) {
745*4882a593Smuzhiyun trace_rpcgss_svc_seqno_large(rqstp, gc->gc_seq);
746*4882a593Smuzhiyun *authp = rpcsec_gsserr_ctxproblem;
747*4882a593Smuzhiyun return SVC_DENIED;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun if (!gss_check_seq_num(rqstp, rsci, gc->gc_seq))
750*4882a593Smuzhiyun return SVC_DROP;
751*4882a593Smuzhiyun return SVC_OK;
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun static int
gss_write_null_verf(struct svc_rqst * rqstp)755*4882a593Smuzhiyun gss_write_null_verf(struct svc_rqst *rqstp)
756*4882a593Smuzhiyun {
757*4882a593Smuzhiyun __be32 *p;
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun svc_putnl(rqstp->rq_res.head, RPC_AUTH_NULL);
760*4882a593Smuzhiyun p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
761*4882a593Smuzhiyun /* don't really need to check if head->iov_len > PAGE_SIZE ... */
762*4882a593Smuzhiyun *p++ = 0;
763*4882a593Smuzhiyun if (!xdr_ressize_check(rqstp, p))
764*4882a593Smuzhiyun return -1;
765*4882a593Smuzhiyun return 0;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun static int
gss_write_verf(struct svc_rqst * rqstp,struct gss_ctx * ctx_id,u32 seq)769*4882a593Smuzhiyun gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun __be32 *xdr_seq;
772*4882a593Smuzhiyun u32 maj_stat;
773*4882a593Smuzhiyun struct xdr_buf verf_data;
774*4882a593Smuzhiyun struct xdr_netobj mic;
775*4882a593Smuzhiyun __be32 *p;
776*4882a593Smuzhiyun struct kvec iov;
777*4882a593Smuzhiyun int err = -1;
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS);
780*4882a593Smuzhiyun xdr_seq = kmalloc(4, GFP_KERNEL);
781*4882a593Smuzhiyun if (!xdr_seq)
782*4882a593Smuzhiyun return -1;
783*4882a593Smuzhiyun *xdr_seq = htonl(seq);
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun iov.iov_base = xdr_seq;
786*4882a593Smuzhiyun iov.iov_len = 4;
787*4882a593Smuzhiyun xdr_buf_from_iov(&iov, &verf_data);
788*4882a593Smuzhiyun p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
789*4882a593Smuzhiyun mic.data = (u8 *)(p + 1);
790*4882a593Smuzhiyun maj_stat = gss_get_mic(ctx_id, &verf_data, &mic);
791*4882a593Smuzhiyun if (maj_stat != GSS_S_COMPLETE)
792*4882a593Smuzhiyun goto out;
793*4882a593Smuzhiyun *p++ = htonl(mic.len);
794*4882a593Smuzhiyun memset((u8 *)p + mic.len, 0, round_up_to_quad(mic.len) - mic.len);
795*4882a593Smuzhiyun p += XDR_QUADLEN(mic.len);
796*4882a593Smuzhiyun if (!xdr_ressize_check(rqstp, p))
797*4882a593Smuzhiyun goto out;
798*4882a593Smuzhiyun err = 0;
799*4882a593Smuzhiyun out:
800*4882a593Smuzhiyun kfree(xdr_seq);
801*4882a593Smuzhiyun return err;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun struct gss_domain {
805*4882a593Smuzhiyun struct auth_domain h;
806*4882a593Smuzhiyun u32 pseudoflavor;
807*4882a593Smuzhiyun };
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun static struct auth_domain *
find_gss_auth_domain(struct gss_ctx * ctx,u32 svc)810*4882a593Smuzhiyun find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun char *name;
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun name = gss_service_to_auth_domain_name(ctx->mech_type, svc);
815*4882a593Smuzhiyun if (!name)
816*4882a593Smuzhiyun return NULL;
817*4882a593Smuzhiyun return auth_domain_find(name);
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun static struct auth_ops svcauthops_gss;
821*4882a593Smuzhiyun
svcauth_gss_flavor(struct auth_domain * dom)822*4882a593Smuzhiyun u32 svcauth_gss_flavor(struct auth_domain *dom)
823*4882a593Smuzhiyun {
824*4882a593Smuzhiyun struct gss_domain *gd = container_of(dom, struct gss_domain, h);
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun return gd->pseudoflavor;
827*4882a593Smuzhiyun }
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(svcauth_gss_flavor);
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun struct auth_domain *
svcauth_gss_register_pseudoflavor(u32 pseudoflavor,char * name)832*4882a593Smuzhiyun svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
833*4882a593Smuzhiyun {
834*4882a593Smuzhiyun struct gss_domain *new;
835*4882a593Smuzhiyun struct auth_domain *test;
836*4882a593Smuzhiyun int stat = -ENOMEM;
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun new = kmalloc(sizeof(*new), GFP_KERNEL);
839*4882a593Smuzhiyun if (!new)
840*4882a593Smuzhiyun goto out;
841*4882a593Smuzhiyun kref_init(&new->h.ref);
842*4882a593Smuzhiyun new->h.name = kstrdup(name, GFP_KERNEL);
843*4882a593Smuzhiyun if (!new->h.name)
844*4882a593Smuzhiyun goto out_free_dom;
845*4882a593Smuzhiyun new->h.flavour = &svcauthops_gss;
846*4882a593Smuzhiyun new->pseudoflavor = pseudoflavor;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun test = auth_domain_lookup(name, &new->h);
849*4882a593Smuzhiyun if (test != &new->h) {
850*4882a593Smuzhiyun pr_warn("svc: duplicate registration of gss pseudo flavour %s.\n",
851*4882a593Smuzhiyun name);
852*4882a593Smuzhiyun stat = -EADDRINUSE;
853*4882a593Smuzhiyun auth_domain_put(test);
854*4882a593Smuzhiyun goto out_free_name;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun return test;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun out_free_name:
859*4882a593Smuzhiyun kfree(new->h.name);
860*4882a593Smuzhiyun out_free_dom:
861*4882a593Smuzhiyun kfree(new);
862*4882a593Smuzhiyun out:
863*4882a593Smuzhiyun return ERR_PTR(stat);
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(svcauth_gss_register_pseudoflavor);
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun static inline int
read_u32_from_xdr_buf(struct xdr_buf * buf,int base,u32 * obj)868*4882a593Smuzhiyun read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun __be32 raw;
871*4882a593Smuzhiyun int status;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
874*4882a593Smuzhiyun if (status)
875*4882a593Smuzhiyun return status;
876*4882a593Smuzhiyun *obj = ntohl(raw);
877*4882a593Smuzhiyun return 0;
878*4882a593Smuzhiyun }
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun /* It would be nice if this bit of code could be shared with the client.
881*4882a593Smuzhiyun * Obstacles:
882*4882a593Smuzhiyun * The client shouldn't malloc(), would have to pass in own memory.
883*4882a593Smuzhiyun * The server uses base of head iovec as read pointer, while the
884*4882a593Smuzhiyun * client uses separate pointer. */
885*4882a593Smuzhiyun static int
unwrap_integ_data(struct svc_rqst * rqstp,struct xdr_buf * buf,u32 seq,struct gss_ctx * ctx)886*4882a593Smuzhiyun unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
887*4882a593Smuzhiyun {
888*4882a593Smuzhiyun u32 integ_len, rseqno, maj_stat;
889*4882a593Smuzhiyun int stat = -EINVAL;
890*4882a593Smuzhiyun struct xdr_netobj mic;
891*4882a593Smuzhiyun struct xdr_buf integ_buf;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun mic.data = NULL;
894*4882a593Smuzhiyun
895*4882a593Smuzhiyun /* NFS READ normally uses splice to send data in-place. However
896*4882a593Smuzhiyun * the data in cache can change after the reply's MIC is computed
897*4882a593Smuzhiyun * but before the RPC reply is sent. To prevent the client from
898*4882a593Smuzhiyun * rejecting the server-computed MIC in this somewhat rare case,
899*4882a593Smuzhiyun * do not use splice with the GSS integrity service.
900*4882a593Smuzhiyun */
901*4882a593Smuzhiyun clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun /* Did we already verify the signature on the original pass through? */
904*4882a593Smuzhiyun if (rqstp->rq_deferred)
905*4882a593Smuzhiyun return 0;
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun integ_len = svc_getnl(&buf->head[0]);
908*4882a593Smuzhiyun if (integ_len & 3)
909*4882a593Smuzhiyun goto unwrap_failed;
910*4882a593Smuzhiyun if (integ_len > buf->len)
911*4882a593Smuzhiyun goto unwrap_failed;
912*4882a593Smuzhiyun if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len))
913*4882a593Smuzhiyun goto unwrap_failed;
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun /* copy out mic... */
916*4882a593Smuzhiyun if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
917*4882a593Smuzhiyun goto unwrap_failed;
918*4882a593Smuzhiyun if (mic.len > RPC_MAX_AUTH_SIZE)
919*4882a593Smuzhiyun goto unwrap_failed;
920*4882a593Smuzhiyun mic.data = kmalloc(mic.len, GFP_KERNEL);
921*4882a593Smuzhiyun if (!mic.data)
922*4882a593Smuzhiyun goto unwrap_failed;
923*4882a593Smuzhiyun if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len))
924*4882a593Smuzhiyun goto unwrap_failed;
925*4882a593Smuzhiyun maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
926*4882a593Smuzhiyun if (maj_stat != GSS_S_COMPLETE)
927*4882a593Smuzhiyun goto bad_mic;
928*4882a593Smuzhiyun rseqno = svc_getnl(&buf->head[0]);
929*4882a593Smuzhiyun if (rseqno != seq)
930*4882a593Smuzhiyun goto bad_seqno;
931*4882a593Smuzhiyun /* trim off the mic and padding at the end before returning */
932*4882a593Smuzhiyun xdr_buf_trim(buf, round_up_to_quad(mic.len) + 4);
933*4882a593Smuzhiyun stat = 0;
934*4882a593Smuzhiyun out:
935*4882a593Smuzhiyun kfree(mic.data);
936*4882a593Smuzhiyun return stat;
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun unwrap_failed:
939*4882a593Smuzhiyun trace_rpcgss_svc_unwrap_failed(rqstp);
940*4882a593Smuzhiyun goto out;
941*4882a593Smuzhiyun bad_seqno:
942*4882a593Smuzhiyun trace_rpcgss_svc_seqno_bad(rqstp, seq, rseqno);
943*4882a593Smuzhiyun goto out;
944*4882a593Smuzhiyun bad_mic:
945*4882a593Smuzhiyun trace_rpcgss_svc_mic(rqstp, maj_stat);
946*4882a593Smuzhiyun goto out;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun static inline int
total_buf_len(struct xdr_buf * buf)950*4882a593Smuzhiyun total_buf_len(struct xdr_buf *buf)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun return buf->head[0].iov_len + buf->page_len + buf->tail[0].iov_len;
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun static void
fix_priv_head(struct xdr_buf * buf,int pad)956*4882a593Smuzhiyun fix_priv_head(struct xdr_buf *buf, int pad)
957*4882a593Smuzhiyun {
958*4882a593Smuzhiyun if (buf->page_len == 0) {
959*4882a593Smuzhiyun /* We need to adjust head and buf->len in tandem in this
960*4882a593Smuzhiyun * case to make svc_defer() work--it finds the original
961*4882a593Smuzhiyun * buffer start using buf->len - buf->head[0].iov_len. */
962*4882a593Smuzhiyun buf->head[0].iov_len -= pad;
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun static int
unwrap_priv_data(struct svc_rqst * rqstp,struct xdr_buf * buf,u32 seq,struct gss_ctx * ctx)967*4882a593Smuzhiyun unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
968*4882a593Smuzhiyun {
969*4882a593Smuzhiyun u32 priv_len, maj_stat;
970*4882a593Smuzhiyun int pad, remaining_len, offset;
971*4882a593Smuzhiyun u32 rseqno;
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun priv_len = svc_getnl(&buf->head[0]);
976*4882a593Smuzhiyun if (rqstp->rq_deferred) {
977*4882a593Smuzhiyun /* Already decrypted last time through! The sequence number
978*4882a593Smuzhiyun * check at out_seq is unnecessary but harmless: */
979*4882a593Smuzhiyun goto out_seq;
980*4882a593Smuzhiyun }
981*4882a593Smuzhiyun /* buf->len is the number of bytes from the original start of the
982*4882a593Smuzhiyun * request to the end, where head[0].iov_len is just the bytes
983*4882a593Smuzhiyun * not yet read from the head, so these two values are different: */
984*4882a593Smuzhiyun remaining_len = total_buf_len(buf);
985*4882a593Smuzhiyun if (priv_len > remaining_len)
986*4882a593Smuzhiyun goto unwrap_failed;
987*4882a593Smuzhiyun pad = remaining_len - priv_len;
988*4882a593Smuzhiyun buf->len -= pad;
989*4882a593Smuzhiyun fix_priv_head(buf, pad);
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun maj_stat = gss_unwrap(ctx, 0, priv_len, buf);
992*4882a593Smuzhiyun pad = priv_len - buf->len;
993*4882a593Smuzhiyun /* The upper layers assume the buffer is aligned on 4-byte boundaries.
994*4882a593Smuzhiyun * In the krb5p case, at least, the data ends up offset, so we need to
995*4882a593Smuzhiyun * move it around. */
996*4882a593Smuzhiyun /* XXX: This is very inefficient. It would be better to either do
997*4882a593Smuzhiyun * this while we encrypt, or maybe in the receive code, if we can peak
998*4882a593Smuzhiyun * ahead and work out the service and mechanism there. */
999*4882a593Smuzhiyun offset = xdr_pad_size(buf->head[0].iov_len);
1000*4882a593Smuzhiyun if (offset) {
1001*4882a593Smuzhiyun buf->buflen = RPCSVC_MAXPAYLOAD;
1002*4882a593Smuzhiyun xdr_shift_buf(buf, offset);
1003*4882a593Smuzhiyun fix_priv_head(buf, pad);
1004*4882a593Smuzhiyun }
1005*4882a593Smuzhiyun if (maj_stat != GSS_S_COMPLETE)
1006*4882a593Smuzhiyun goto bad_unwrap;
1007*4882a593Smuzhiyun out_seq:
1008*4882a593Smuzhiyun rseqno = svc_getnl(&buf->head[0]);
1009*4882a593Smuzhiyun if (rseqno != seq)
1010*4882a593Smuzhiyun goto bad_seqno;
1011*4882a593Smuzhiyun return 0;
1012*4882a593Smuzhiyun
1013*4882a593Smuzhiyun unwrap_failed:
1014*4882a593Smuzhiyun trace_rpcgss_svc_unwrap_failed(rqstp);
1015*4882a593Smuzhiyun return -EINVAL;
1016*4882a593Smuzhiyun bad_seqno:
1017*4882a593Smuzhiyun trace_rpcgss_svc_seqno_bad(rqstp, seq, rseqno);
1018*4882a593Smuzhiyun return -EINVAL;
1019*4882a593Smuzhiyun bad_unwrap:
1020*4882a593Smuzhiyun trace_rpcgss_svc_unwrap(rqstp, maj_stat);
1021*4882a593Smuzhiyun return -EINVAL;
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun struct gss_svc_data {
1025*4882a593Smuzhiyun /* decoded gss client cred: */
1026*4882a593Smuzhiyun struct rpc_gss_wire_cred clcred;
1027*4882a593Smuzhiyun /* save a pointer to the beginning of the encoded verifier,
1028*4882a593Smuzhiyun * for use in encryption/checksumming in svcauth_gss_release: */
1029*4882a593Smuzhiyun __be32 *verf_start;
1030*4882a593Smuzhiyun struct rsc *rsci;
1031*4882a593Smuzhiyun };
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun static int
svcauth_gss_set_client(struct svc_rqst * rqstp)1034*4882a593Smuzhiyun svcauth_gss_set_client(struct svc_rqst *rqstp)
1035*4882a593Smuzhiyun {
1036*4882a593Smuzhiyun struct gss_svc_data *svcdata = rqstp->rq_auth_data;
1037*4882a593Smuzhiyun struct rsc *rsci = svcdata->rsci;
1038*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc = &svcdata->clcred;
1039*4882a593Smuzhiyun int stat;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun /*
1042*4882a593Smuzhiyun * A gss export can be specified either by:
1043*4882a593Smuzhiyun * export *(sec=krb5,rw)
1044*4882a593Smuzhiyun * or by
1045*4882a593Smuzhiyun * export gss/krb5(rw)
1046*4882a593Smuzhiyun * The latter is deprecated; but for backwards compatibility reasons
1047*4882a593Smuzhiyun * the nfsd code will still fall back on trying it if the former
1048*4882a593Smuzhiyun * doesn't work; so we try to make both available to nfsd, below.
1049*4882a593Smuzhiyun */
1050*4882a593Smuzhiyun rqstp->rq_gssclient = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
1051*4882a593Smuzhiyun if (rqstp->rq_gssclient == NULL)
1052*4882a593Smuzhiyun return SVC_DENIED;
1053*4882a593Smuzhiyun stat = svcauth_unix_set_client(rqstp);
1054*4882a593Smuzhiyun if (stat == SVC_DROP || stat == SVC_CLOSE)
1055*4882a593Smuzhiyun return stat;
1056*4882a593Smuzhiyun return SVC_OK;
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun static inline int
gss_write_init_verf(struct cache_detail * cd,struct svc_rqst * rqstp,struct xdr_netobj * out_handle,int * major_status)1060*4882a593Smuzhiyun gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp,
1061*4882a593Smuzhiyun struct xdr_netobj *out_handle, int *major_status)
1062*4882a593Smuzhiyun {
1063*4882a593Smuzhiyun struct rsc *rsci;
1064*4882a593Smuzhiyun int rc;
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun if (*major_status != GSS_S_COMPLETE)
1067*4882a593Smuzhiyun return gss_write_null_verf(rqstp);
1068*4882a593Smuzhiyun rsci = gss_svc_searchbyctx(cd, out_handle);
1069*4882a593Smuzhiyun if (rsci == NULL) {
1070*4882a593Smuzhiyun *major_status = GSS_S_NO_CONTEXT;
1071*4882a593Smuzhiyun return gss_write_null_verf(rqstp);
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
1074*4882a593Smuzhiyun cache_put(&rsci->h, cd);
1075*4882a593Smuzhiyun return rc;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
1078*4882a593Smuzhiyun static inline int
gss_read_common_verf(struct rpc_gss_wire_cred * gc,struct kvec * argv,__be32 * authp,struct xdr_netobj * in_handle)1079*4882a593Smuzhiyun gss_read_common_verf(struct rpc_gss_wire_cred *gc,
1080*4882a593Smuzhiyun struct kvec *argv, __be32 *authp,
1081*4882a593Smuzhiyun struct xdr_netobj *in_handle)
1082*4882a593Smuzhiyun {
1083*4882a593Smuzhiyun /* Read the verifier; should be NULL: */
1084*4882a593Smuzhiyun *authp = rpc_autherr_badverf;
1085*4882a593Smuzhiyun if (argv->iov_len < 2 * 4)
1086*4882a593Smuzhiyun return SVC_DENIED;
1087*4882a593Smuzhiyun if (svc_getnl(argv) != RPC_AUTH_NULL)
1088*4882a593Smuzhiyun return SVC_DENIED;
1089*4882a593Smuzhiyun if (svc_getnl(argv) != 0)
1090*4882a593Smuzhiyun return SVC_DENIED;
1091*4882a593Smuzhiyun /* Martial context handle and token for upcall: */
1092*4882a593Smuzhiyun *authp = rpc_autherr_badcred;
1093*4882a593Smuzhiyun if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
1094*4882a593Smuzhiyun return SVC_DENIED;
1095*4882a593Smuzhiyun if (dup_netobj(in_handle, &gc->gc_ctx))
1096*4882a593Smuzhiyun return SVC_CLOSE;
1097*4882a593Smuzhiyun *authp = rpc_autherr_badverf;
1098*4882a593Smuzhiyun
1099*4882a593Smuzhiyun return 0;
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun static inline int
gss_read_verf(struct rpc_gss_wire_cred * gc,struct kvec * argv,__be32 * authp,struct xdr_netobj * in_handle,struct xdr_netobj * in_token)1103*4882a593Smuzhiyun gss_read_verf(struct rpc_gss_wire_cred *gc,
1104*4882a593Smuzhiyun struct kvec *argv, __be32 *authp,
1105*4882a593Smuzhiyun struct xdr_netobj *in_handle,
1106*4882a593Smuzhiyun struct xdr_netobj *in_token)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun struct xdr_netobj tmpobj;
1109*4882a593Smuzhiyun int res;
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun res = gss_read_common_verf(gc, argv, authp, in_handle);
1112*4882a593Smuzhiyun if (res)
1113*4882a593Smuzhiyun return res;
1114*4882a593Smuzhiyun
1115*4882a593Smuzhiyun if (svc_safe_getnetobj(argv, &tmpobj)) {
1116*4882a593Smuzhiyun kfree(in_handle->data);
1117*4882a593Smuzhiyun return SVC_DENIED;
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun if (dup_netobj(in_token, &tmpobj)) {
1120*4882a593Smuzhiyun kfree(in_handle->data);
1121*4882a593Smuzhiyun return SVC_CLOSE;
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun return 0;
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun
gss_free_in_token_pages(struct gssp_in_token * in_token)1127*4882a593Smuzhiyun static void gss_free_in_token_pages(struct gssp_in_token *in_token)
1128*4882a593Smuzhiyun {
1129*4882a593Smuzhiyun u32 inlen;
1130*4882a593Smuzhiyun int i;
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun i = 0;
1133*4882a593Smuzhiyun inlen = in_token->page_len;
1134*4882a593Smuzhiyun while (inlen) {
1135*4882a593Smuzhiyun if (in_token->pages[i])
1136*4882a593Smuzhiyun put_page(in_token->pages[i]);
1137*4882a593Smuzhiyun inlen -= inlen > PAGE_SIZE ? PAGE_SIZE : inlen;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun kfree(in_token->pages);
1141*4882a593Smuzhiyun in_token->pages = NULL;
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun
gss_read_proxy_verf(struct svc_rqst * rqstp,struct rpc_gss_wire_cred * gc,__be32 * authp,struct xdr_netobj * in_handle,struct gssp_in_token * in_token)1144*4882a593Smuzhiyun static int gss_read_proxy_verf(struct svc_rqst *rqstp,
1145*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc, __be32 *authp,
1146*4882a593Smuzhiyun struct xdr_netobj *in_handle,
1147*4882a593Smuzhiyun struct gssp_in_token *in_token)
1148*4882a593Smuzhiyun {
1149*4882a593Smuzhiyun struct kvec *argv = &rqstp->rq_arg.head[0];
1150*4882a593Smuzhiyun unsigned int length, pgto_offs, pgfrom_offs;
1151*4882a593Smuzhiyun int pages, i, res, pgto, pgfrom;
1152*4882a593Smuzhiyun size_t inlen, to_offs, from_offs;
1153*4882a593Smuzhiyun
1154*4882a593Smuzhiyun res = gss_read_common_verf(gc, argv, authp, in_handle);
1155*4882a593Smuzhiyun if (res)
1156*4882a593Smuzhiyun return res;
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun inlen = svc_getnl(argv);
1159*4882a593Smuzhiyun if (inlen > (argv->iov_len + rqstp->rq_arg.page_len))
1160*4882a593Smuzhiyun return SVC_DENIED;
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun pages = DIV_ROUND_UP(inlen, PAGE_SIZE);
1163*4882a593Smuzhiyun in_token->pages = kcalloc(pages, sizeof(struct page *), GFP_KERNEL);
1164*4882a593Smuzhiyun if (!in_token->pages)
1165*4882a593Smuzhiyun return SVC_DENIED;
1166*4882a593Smuzhiyun in_token->page_base = 0;
1167*4882a593Smuzhiyun in_token->page_len = inlen;
1168*4882a593Smuzhiyun for (i = 0; i < pages; i++) {
1169*4882a593Smuzhiyun in_token->pages[i] = alloc_page(GFP_KERNEL);
1170*4882a593Smuzhiyun if (!in_token->pages[i]) {
1171*4882a593Smuzhiyun gss_free_in_token_pages(in_token);
1172*4882a593Smuzhiyun return SVC_DENIED;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun }
1175*4882a593Smuzhiyun
1176*4882a593Smuzhiyun length = min_t(unsigned int, inlen, argv->iov_len);
1177*4882a593Smuzhiyun memcpy(page_address(in_token->pages[0]), argv->iov_base, length);
1178*4882a593Smuzhiyun inlen -= length;
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun to_offs = length;
1181*4882a593Smuzhiyun from_offs = rqstp->rq_arg.page_base;
1182*4882a593Smuzhiyun while (inlen) {
1183*4882a593Smuzhiyun pgto = to_offs >> PAGE_SHIFT;
1184*4882a593Smuzhiyun pgfrom = from_offs >> PAGE_SHIFT;
1185*4882a593Smuzhiyun pgto_offs = to_offs & ~PAGE_MASK;
1186*4882a593Smuzhiyun pgfrom_offs = from_offs & ~PAGE_MASK;
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun length = min_t(unsigned int, inlen,
1189*4882a593Smuzhiyun min_t(unsigned int, PAGE_SIZE - pgto_offs,
1190*4882a593Smuzhiyun PAGE_SIZE - pgfrom_offs));
1191*4882a593Smuzhiyun memcpy(page_address(in_token->pages[pgto]) + pgto_offs,
1192*4882a593Smuzhiyun page_address(rqstp->rq_arg.pages[pgfrom]) + pgfrom_offs,
1193*4882a593Smuzhiyun length);
1194*4882a593Smuzhiyun
1195*4882a593Smuzhiyun to_offs += length;
1196*4882a593Smuzhiyun from_offs += length;
1197*4882a593Smuzhiyun inlen -= length;
1198*4882a593Smuzhiyun }
1199*4882a593Smuzhiyun return 0;
1200*4882a593Smuzhiyun }
1201*4882a593Smuzhiyun
1202*4882a593Smuzhiyun static inline int
gss_write_resv(struct kvec * resv,size_t size_limit,struct xdr_netobj * out_handle,struct xdr_netobj * out_token,int major_status,int minor_status)1203*4882a593Smuzhiyun gss_write_resv(struct kvec *resv, size_t size_limit,
1204*4882a593Smuzhiyun struct xdr_netobj *out_handle, struct xdr_netobj *out_token,
1205*4882a593Smuzhiyun int major_status, int minor_status)
1206*4882a593Smuzhiyun {
1207*4882a593Smuzhiyun if (resv->iov_len + 4 > size_limit)
1208*4882a593Smuzhiyun return -1;
1209*4882a593Smuzhiyun svc_putnl(resv, RPC_SUCCESS);
1210*4882a593Smuzhiyun if (svc_safe_putnetobj(resv, out_handle))
1211*4882a593Smuzhiyun return -1;
1212*4882a593Smuzhiyun if (resv->iov_len + 3 * 4 > size_limit)
1213*4882a593Smuzhiyun return -1;
1214*4882a593Smuzhiyun svc_putnl(resv, major_status);
1215*4882a593Smuzhiyun svc_putnl(resv, minor_status);
1216*4882a593Smuzhiyun svc_putnl(resv, GSS_SEQ_WIN);
1217*4882a593Smuzhiyun if (svc_safe_putnetobj(resv, out_token))
1218*4882a593Smuzhiyun return -1;
1219*4882a593Smuzhiyun return 0;
1220*4882a593Smuzhiyun }
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun /*
1223*4882a593Smuzhiyun * Having read the cred already and found we're in the context
1224*4882a593Smuzhiyun * initiation case, read the verifier and initiate (or check the results
1225*4882a593Smuzhiyun * of) upcalls to userspace for help with context initiation. If
1226*4882a593Smuzhiyun * the upcall results are available, write the verifier and result.
1227*4882a593Smuzhiyun * Otherwise, drop the request pending an answer to the upcall.
1228*4882a593Smuzhiyun */
svcauth_gss_legacy_init(struct svc_rqst * rqstp,struct rpc_gss_wire_cred * gc,__be32 * authp)1229*4882a593Smuzhiyun static int svcauth_gss_legacy_init(struct svc_rqst *rqstp,
1230*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc, __be32 *authp)
1231*4882a593Smuzhiyun {
1232*4882a593Smuzhiyun struct kvec *argv = &rqstp->rq_arg.head[0];
1233*4882a593Smuzhiyun struct kvec *resv = &rqstp->rq_res.head[0];
1234*4882a593Smuzhiyun struct rsi *rsip, rsikey;
1235*4882a593Smuzhiyun int ret;
1236*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
1237*4882a593Smuzhiyun
1238*4882a593Smuzhiyun memset(&rsikey, 0, sizeof(rsikey));
1239*4882a593Smuzhiyun ret = gss_read_verf(gc, argv, authp,
1240*4882a593Smuzhiyun &rsikey.in_handle, &rsikey.in_token);
1241*4882a593Smuzhiyun if (ret)
1242*4882a593Smuzhiyun return ret;
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun /* Perform upcall, or find upcall result: */
1245*4882a593Smuzhiyun rsip = rsi_lookup(sn->rsi_cache, &rsikey);
1246*4882a593Smuzhiyun rsi_free(&rsikey);
1247*4882a593Smuzhiyun if (!rsip)
1248*4882a593Smuzhiyun return SVC_CLOSE;
1249*4882a593Smuzhiyun if (cache_check(sn->rsi_cache, &rsip->h, &rqstp->rq_chandle) < 0)
1250*4882a593Smuzhiyun /* No upcall result: */
1251*4882a593Smuzhiyun return SVC_CLOSE;
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun ret = SVC_CLOSE;
1254*4882a593Smuzhiyun /* Got an answer to the upcall; use it: */
1255*4882a593Smuzhiyun if (gss_write_init_verf(sn->rsc_cache, rqstp,
1256*4882a593Smuzhiyun &rsip->out_handle, &rsip->major_status))
1257*4882a593Smuzhiyun goto out;
1258*4882a593Smuzhiyun if (gss_write_resv(resv, PAGE_SIZE,
1259*4882a593Smuzhiyun &rsip->out_handle, &rsip->out_token,
1260*4882a593Smuzhiyun rsip->major_status, rsip->minor_status))
1261*4882a593Smuzhiyun goto out;
1262*4882a593Smuzhiyun
1263*4882a593Smuzhiyun ret = SVC_COMPLETE;
1264*4882a593Smuzhiyun out:
1265*4882a593Smuzhiyun cache_put(&rsip->h, sn->rsi_cache);
1266*4882a593Smuzhiyun return ret;
1267*4882a593Smuzhiyun }
1268*4882a593Smuzhiyun
gss_proxy_save_rsc(struct cache_detail * cd,struct gssp_upcall_data * ud,uint64_t * handle)1269*4882a593Smuzhiyun static int gss_proxy_save_rsc(struct cache_detail *cd,
1270*4882a593Smuzhiyun struct gssp_upcall_data *ud,
1271*4882a593Smuzhiyun uint64_t *handle)
1272*4882a593Smuzhiyun {
1273*4882a593Smuzhiyun struct rsc rsci, *rscp = NULL;
1274*4882a593Smuzhiyun static atomic64_t ctxhctr;
1275*4882a593Smuzhiyun long long ctxh;
1276*4882a593Smuzhiyun struct gss_api_mech *gm = NULL;
1277*4882a593Smuzhiyun time64_t expiry;
1278*4882a593Smuzhiyun int status = -EINVAL;
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun memset(&rsci, 0, sizeof(rsci));
1281*4882a593Smuzhiyun /* context handle */
1282*4882a593Smuzhiyun status = -ENOMEM;
1283*4882a593Smuzhiyun /* the handle needs to be just a unique id,
1284*4882a593Smuzhiyun * use a static counter */
1285*4882a593Smuzhiyun ctxh = atomic64_inc_return(&ctxhctr);
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun /* make a copy for the caller */
1288*4882a593Smuzhiyun *handle = ctxh;
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun /* make a copy for the rsc cache */
1291*4882a593Smuzhiyun if (dup_to_netobj(&rsci.handle, (char *)handle, sizeof(uint64_t)))
1292*4882a593Smuzhiyun goto out;
1293*4882a593Smuzhiyun rscp = rsc_lookup(cd, &rsci);
1294*4882a593Smuzhiyun if (!rscp)
1295*4882a593Smuzhiyun goto out;
1296*4882a593Smuzhiyun
1297*4882a593Smuzhiyun /* creds */
1298*4882a593Smuzhiyun if (!ud->found_creds) {
1299*4882a593Smuzhiyun /* userspace seem buggy, we should always get at least a
1300*4882a593Smuzhiyun * mapping to nobody */
1301*4882a593Smuzhiyun goto out;
1302*4882a593Smuzhiyun } else {
1303*4882a593Smuzhiyun struct timespec64 boot;
1304*4882a593Smuzhiyun
1305*4882a593Smuzhiyun /* steal creds */
1306*4882a593Smuzhiyun rsci.cred = ud->creds;
1307*4882a593Smuzhiyun memset(&ud->creds, 0, sizeof(struct svc_cred));
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun status = -EOPNOTSUPP;
1310*4882a593Smuzhiyun /* get mech handle from OID */
1311*4882a593Smuzhiyun gm = gss_mech_get_by_OID(&ud->mech_oid);
1312*4882a593Smuzhiyun if (!gm)
1313*4882a593Smuzhiyun goto out;
1314*4882a593Smuzhiyun rsci.cred.cr_gss_mech = gm;
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun status = -EINVAL;
1317*4882a593Smuzhiyun /* mech-specific data: */
1318*4882a593Smuzhiyun status = gss_import_sec_context(ud->out_handle.data,
1319*4882a593Smuzhiyun ud->out_handle.len,
1320*4882a593Smuzhiyun gm, &rsci.mechctx,
1321*4882a593Smuzhiyun &expiry, GFP_KERNEL);
1322*4882a593Smuzhiyun if (status)
1323*4882a593Smuzhiyun goto out;
1324*4882a593Smuzhiyun
1325*4882a593Smuzhiyun getboottime64(&boot);
1326*4882a593Smuzhiyun expiry -= boot.tv_sec;
1327*4882a593Smuzhiyun }
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun rsci.h.expiry_time = expiry;
1330*4882a593Smuzhiyun rscp = rsc_update(cd, &rsci, rscp);
1331*4882a593Smuzhiyun status = 0;
1332*4882a593Smuzhiyun out:
1333*4882a593Smuzhiyun rsc_free(&rsci);
1334*4882a593Smuzhiyun if (rscp)
1335*4882a593Smuzhiyun cache_put(&rscp->h, cd);
1336*4882a593Smuzhiyun else
1337*4882a593Smuzhiyun status = -ENOMEM;
1338*4882a593Smuzhiyun return status;
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun
svcauth_gss_proxy_init(struct svc_rqst * rqstp,struct rpc_gss_wire_cred * gc,__be32 * authp)1341*4882a593Smuzhiyun static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
1342*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc, __be32 *authp)
1343*4882a593Smuzhiyun {
1344*4882a593Smuzhiyun struct kvec *resv = &rqstp->rq_res.head[0];
1345*4882a593Smuzhiyun struct xdr_netobj cli_handle;
1346*4882a593Smuzhiyun struct gssp_upcall_data ud;
1347*4882a593Smuzhiyun uint64_t handle;
1348*4882a593Smuzhiyun int status;
1349*4882a593Smuzhiyun int ret;
1350*4882a593Smuzhiyun struct net *net = SVC_NET(rqstp);
1351*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun memset(&ud, 0, sizeof(ud));
1354*4882a593Smuzhiyun ret = gss_read_proxy_verf(rqstp, gc, authp,
1355*4882a593Smuzhiyun &ud.in_handle, &ud.in_token);
1356*4882a593Smuzhiyun if (ret)
1357*4882a593Smuzhiyun return ret;
1358*4882a593Smuzhiyun
1359*4882a593Smuzhiyun ret = SVC_CLOSE;
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun /* Perform synchronous upcall to gss-proxy */
1362*4882a593Smuzhiyun status = gssp_accept_sec_context_upcall(net, &ud);
1363*4882a593Smuzhiyun if (status)
1364*4882a593Smuzhiyun goto out;
1365*4882a593Smuzhiyun
1366*4882a593Smuzhiyun trace_rpcgss_svc_accept_upcall(rqstp, ud.major_status, ud.minor_status);
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun switch (ud.major_status) {
1369*4882a593Smuzhiyun case GSS_S_CONTINUE_NEEDED:
1370*4882a593Smuzhiyun cli_handle = ud.out_handle;
1371*4882a593Smuzhiyun break;
1372*4882a593Smuzhiyun case GSS_S_COMPLETE:
1373*4882a593Smuzhiyun status = gss_proxy_save_rsc(sn->rsc_cache, &ud, &handle);
1374*4882a593Smuzhiyun if (status)
1375*4882a593Smuzhiyun goto out;
1376*4882a593Smuzhiyun cli_handle.data = (u8 *)&handle;
1377*4882a593Smuzhiyun cli_handle.len = sizeof(handle);
1378*4882a593Smuzhiyun break;
1379*4882a593Smuzhiyun default:
1380*4882a593Smuzhiyun goto out;
1381*4882a593Smuzhiyun }
1382*4882a593Smuzhiyun
1383*4882a593Smuzhiyun /* Got an answer to the upcall; use it: */
1384*4882a593Smuzhiyun if (gss_write_init_verf(sn->rsc_cache, rqstp,
1385*4882a593Smuzhiyun &cli_handle, &ud.major_status))
1386*4882a593Smuzhiyun goto out;
1387*4882a593Smuzhiyun if (gss_write_resv(resv, PAGE_SIZE,
1388*4882a593Smuzhiyun &cli_handle, &ud.out_token,
1389*4882a593Smuzhiyun ud.major_status, ud.minor_status))
1390*4882a593Smuzhiyun goto out;
1391*4882a593Smuzhiyun
1392*4882a593Smuzhiyun ret = SVC_COMPLETE;
1393*4882a593Smuzhiyun out:
1394*4882a593Smuzhiyun gss_free_in_token_pages(&ud.in_token);
1395*4882a593Smuzhiyun gssp_free_upcall_data(&ud);
1396*4882a593Smuzhiyun return ret;
1397*4882a593Smuzhiyun }
1398*4882a593Smuzhiyun
1399*4882a593Smuzhiyun /*
1400*4882a593Smuzhiyun * Try to set the sn->use_gss_proxy variable to a new value. We only allow
1401*4882a593Smuzhiyun * it to be changed if it's currently undefined (-1). If it's any other value
1402*4882a593Smuzhiyun * then return -EBUSY unless the type wouldn't have changed anyway.
1403*4882a593Smuzhiyun */
set_gss_proxy(struct net * net,int type)1404*4882a593Smuzhiyun static int set_gss_proxy(struct net *net, int type)
1405*4882a593Smuzhiyun {
1406*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1407*4882a593Smuzhiyun int ret;
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun WARN_ON_ONCE(type != 0 && type != 1);
1410*4882a593Smuzhiyun ret = cmpxchg(&sn->use_gss_proxy, -1, type);
1411*4882a593Smuzhiyun if (ret != -1 && ret != type)
1412*4882a593Smuzhiyun return -EBUSY;
1413*4882a593Smuzhiyun return 0;
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun
use_gss_proxy(struct net * net)1416*4882a593Smuzhiyun static bool use_gss_proxy(struct net *net)
1417*4882a593Smuzhiyun {
1418*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1419*4882a593Smuzhiyun
1420*4882a593Smuzhiyun /* If use_gss_proxy is still undefined, then try to disable it */
1421*4882a593Smuzhiyun if (sn->use_gss_proxy == -1)
1422*4882a593Smuzhiyun set_gss_proxy(net, 0);
1423*4882a593Smuzhiyun return sn->use_gss_proxy;
1424*4882a593Smuzhiyun }
1425*4882a593Smuzhiyun
1426*4882a593Smuzhiyun #ifdef CONFIG_PROC_FS
1427*4882a593Smuzhiyun
write_gssp(struct file * file,const char __user * buf,size_t count,loff_t * ppos)1428*4882a593Smuzhiyun static ssize_t write_gssp(struct file *file, const char __user *buf,
1429*4882a593Smuzhiyun size_t count, loff_t *ppos)
1430*4882a593Smuzhiyun {
1431*4882a593Smuzhiyun struct net *net = PDE_DATA(file_inode(file));
1432*4882a593Smuzhiyun char tbuf[20];
1433*4882a593Smuzhiyun unsigned long i;
1434*4882a593Smuzhiyun int res;
1435*4882a593Smuzhiyun
1436*4882a593Smuzhiyun if (*ppos || count > sizeof(tbuf)-1)
1437*4882a593Smuzhiyun return -EINVAL;
1438*4882a593Smuzhiyun if (copy_from_user(tbuf, buf, count))
1439*4882a593Smuzhiyun return -EFAULT;
1440*4882a593Smuzhiyun
1441*4882a593Smuzhiyun tbuf[count] = 0;
1442*4882a593Smuzhiyun res = kstrtoul(tbuf, 0, &i);
1443*4882a593Smuzhiyun if (res)
1444*4882a593Smuzhiyun return res;
1445*4882a593Smuzhiyun if (i != 1)
1446*4882a593Smuzhiyun return -EINVAL;
1447*4882a593Smuzhiyun res = set_gssp_clnt(net);
1448*4882a593Smuzhiyun if (res)
1449*4882a593Smuzhiyun return res;
1450*4882a593Smuzhiyun res = set_gss_proxy(net, 1);
1451*4882a593Smuzhiyun if (res)
1452*4882a593Smuzhiyun return res;
1453*4882a593Smuzhiyun return count;
1454*4882a593Smuzhiyun }
1455*4882a593Smuzhiyun
read_gssp(struct file * file,char __user * buf,size_t count,loff_t * ppos)1456*4882a593Smuzhiyun static ssize_t read_gssp(struct file *file, char __user *buf,
1457*4882a593Smuzhiyun size_t count, loff_t *ppos)
1458*4882a593Smuzhiyun {
1459*4882a593Smuzhiyun struct net *net = PDE_DATA(file_inode(file));
1460*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1461*4882a593Smuzhiyun unsigned long p = *ppos;
1462*4882a593Smuzhiyun char tbuf[10];
1463*4882a593Smuzhiyun size_t len;
1464*4882a593Smuzhiyun
1465*4882a593Smuzhiyun snprintf(tbuf, sizeof(tbuf), "%d\n", sn->use_gss_proxy);
1466*4882a593Smuzhiyun len = strlen(tbuf);
1467*4882a593Smuzhiyun if (p >= len)
1468*4882a593Smuzhiyun return 0;
1469*4882a593Smuzhiyun len -= p;
1470*4882a593Smuzhiyun if (len > count)
1471*4882a593Smuzhiyun len = count;
1472*4882a593Smuzhiyun if (copy_to_user(buf, (void *)(tbuf+p), len))
1473*4882a593Smuzhiyun return -EFAULT;
1474*4882a593Smuzhiyun *ppos += len;
1475*4882a593Smuzhiyun return len;
1476*4882a593Smuzhiyun }
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun static const struct proc_ops use_gss_proxy_proc_ops = {
1479*4882a593Smuzhiyun .proc_open = nonseekable_open,
1480*4882a593Smuzhiyun .proc_write = write_gssp,
1481*4882a593Smuzhiyun .proc_read = read_gssp,
1482*4882a593Smuzhiyun };
1483*4882a593Smuzhiyun
create_use_gss_proxy_proc_entry(struct net * net)1484*4882a593Smuzhiyun static int create_use_gss_proxy_proc_entry(struct net *net)
1485*4882a593Smuzhiyun {
1486*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1487*4882a593Smuzhiyun struct proc_dir_entry **p = &sn->use_gssp_proc;
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun sn->use_gss_proxy = -1;
1490*4882a593Smuzhiyun *p = proc_create_data("use-gss-proxy", S_IFREG | 0600,
1491*4882a593Smuzhiyun sn->proc_net_rpc,
1492*4882a593Smuzhiyun &use_gss_proxy_proc_ops, net);
1493*4882a593Smuzhiyun if (!*p)
1494*4882a593Smuzhiyun return -ENOMEM;
1495*4882a593Smuzhiyun init_gssp_clnt(sn);
1496*4882a593Smuzhiyun return 0;
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun
destroy_use_gss_proxy_proc_entry(struct net * net)1499*4882a593Smuzhiyun static void destroy_use_gss_proxy_proc_entry(struct net *net)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1502*4882a593Smuzhiyun
1503*4882a593Smuzhiyun if (sn->use_gssp_proc) {
1504*4882a593Smuzhiyun remove_proc_entry("use-gss-proxy", sn->proc_net_rpc);
1505*4882a593Smuzhiyun clear_gssp_clnt(sn);
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun #else /* CONFIG_PROC_FS */
1509*4882a593Smuzhiyun
create_use_gss_proxy_proc_entry(struct net * net)1510*4882a593Smuzhiyun static int create_use_gss_proxy_proc_entry(struct net *net)
1511*4882a593Smuzhiyun {
1512*4882a593Smuzhiyun return 0;
1513*4882a593Smuzhiyun }
1514*4882a593Smuzhiyun
destroy_use_gss_proxy_proc_entry(struct net * net)1515*4882a593Smuzhiyun static void destroy_use_gss_proxy_proc_entry(struct net *net) {}
1516*4882a593Smuzhiyun
1517*4882a593Smuzhiyun #endif /* CONFIG_PROC_FS */
1518*4882a593Smuzhiyun
1519*4882a593Smuzhiyun /*
1520*4882a593Smuzhiyun * Accept an rpcsec packet.
1521*4882a593Smuzhiyun * If context establishment, punt to user space
1522*4882a593Smuzhiyun * If data exchange, verify/decrypt
1523*4882a593Smuzhiyun * If context destruction, handle here
1524*4882a593Smuzhiyun * In the context establishment and destruction case we encode
1525*4882a593Smuzhiyun * response here and return SVC_COMPLETE.
1526*4882a593Smuzhiyun */
1527*4882a593Smuzhiyun static int
svcauth_gss_accept(struct svc_rqst * rqstp,__be32 * authp)1528*4882a593Smuzhiyun svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1529*4882a593Smuzhiyun {
1530*4882a593Smuzhiyun struct kvec *argv = &rqstp->rq_arg.head[0];
1531*4882a593Smuzhiyun struct kvec *resv = &rqstp->rq_res.head[0];
1532*4882a593Smuzhiyun u32 crlen;
1533*4882a593Smuzhiyun struct gss_svc_data *svcdata = rqstp->rq_auth_data;
1534*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc;
1535*4882a593Smuzhiyun struct rsc *rsci = NULL;
1536*4882a593Smuzhiyun __be32 *rpcstart;
1537*4882a593Smuzhiyun __be32 *reject_stat = resv->iov_base + resv->iov_len;
1538*4882a593Smuzhiyun int ret;
1539*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
1540*4882a593Smuzhiyun
1541*4882a593Smuzhiyun *authp = rpc_autherr_badcred;
1542*4882a593Smuzhiyun if (!svcdata)
1543*4882a593Smuzhiyun svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
1544*4882a593Smuzhiyun if (!svcdata)
1545*4882a593Smuzhiyun goto auth_err;
1546*4882a593Smuzhiyun rqstp->rq_auth_data = svcdata;
1547*4882a593Smuzhiyun svcdata->verf_start = NULL;
1548*4882a593Smuzhiyun svcdata->rsci = NULL;
1549*4882a593Smuzhiyun gc = &svcdata->clcred;
1550*4882a593Smuzhiyun
1551*4882a593Smuzhiyun /* start of rpc packet is 7 u32's back from here:
1552*4882a593Smuzhiyun * xid direction rpcversion prog vers proc flavour
1553*4882a593Smuzhiyun */
1554*4882a593Smuzhiyun rpcstart = argv->iov_base;
1555*4882a593Smuzhiyun rpcstart -= 7;
1556*4882a593Smuzhiyun
1557*4882a593Smuzhiyun /* credential is:
1558*4882a593Smuzhiyun * version(==1), proc(0,1,2,3), seq, service (1,2,3), handle
1559*4882a593Smuzhiyun * at least 5 u32s, and is preceded by length, so that makes 6.
1560*4882a593Smuzhiyun */
1561*4882a593Smuzhiyun
1562*4882a593Smuzhiyun if (argv->iov_len < 5 * 4)
1563*4882a593Smuzhiyun goto auth_err;
1564*4882a593Smuzhiyun crlen = svc_getnl(argv);
1565*4882a593Smuzhiyun if (svc_getnl(argv) != RPC_GSS_VERSION)
1566*4882a593Smuzhiyun goto auth_err;
1567*4882a593Smuzhiyun gc->gc_proc = svc_getnl(argv);
1568*4882a593Smuzhiyun gc->gc_seq = svc_getnl(argv);
1569*4882a593Smuzhiyun gc->gc_svc = svc_getnl(argv);
1570*4882a593Smuzhiyun if (svc_safe_getnetobj(argv, &gc->gc_ctx))
1571*4882a593Smuzhiyun goto auth_err;
1572*4882a593Smuzhiyun if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
1573*4882a593Smuzhiyun goto auth_err;
1574*4882a593Smuzhiyun
1575*4882a593Smuzhiyun if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
1576*4882a593Smuzhiyun goto auth_err;
1577*4882a593Smuzhiyun
1578*4882a593Smuzhiyun *authp = rpc_autherr_badverf;
1579*4882a593Smuzhiyun switch (gc->gc_proc) {
1580*4882a593Smuzhiyun case RPC_GSS_PROC_INIT:
1581*4882a593Smuzhiyun case RPC_GSS_PROC_CONTINUE_INIT:
1582*4882a593Smuzhiyun if (use_gss_proxy(SVC_NET(rqstp)))
1583*4882a593Smuzhiyun return svcauth_gss_proxy_init(rqstp, gc, authp);
1584*4882a593Smuzhiyun else
1585*4882a593Smuzhiyun return svcauth_gss_legacy_init(rqstp, gc, authp);
1586*4882a593Smuzhiyun case RPC_GSS_PROC_DATA:
1587*4882a593Smuzhiyun case RPC_GSS_PROC_DESTROY:
1588*4882a593Smuzhiyun /* Look up the context, and check the verifier: */
1589*4882a593Smuzhiyun *authp = rpcsec_gsserr_credproblem;
1590*4882a593Smuzhiyun rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx);
1591*4882a593Smuzhiyun if (!rsci)
1592*4882a593Smuzhiyun goto auth_err;
1593*4882a593Smuzhiyun switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {
1594*4882a593Smuzhiyun case SVC_OK:
1595*4882a593Smuzhiyun break;
1596*4882a593Smuzhiyun case SVC_DENIED:
1597*4882a593Smuzhiyun goto auth_err;
1598*4882a593Smuzhiyun case SVC_DROP:
1599*4882a593Smuzhiyun goto drop;
1600*4882a593Smuzhiyun }
1601*4882a593Smuzhiyun break;
1602*4882a593Smuzhiyun default:
1603*4882a593Smuzhiyun *authp = rpc_autherr_rejectedcred;
1604*4882a593Smuzhiyun goto auth_err;
1605*4882a593Smuzhiyun }
1606*4882a593Smuzhiyun
1607*4882a593Smuzhiyun /* now act upon the command: */
1608*4882a593Smuzhiyun switch (gc->gc_proc) {
1609*4882a593Smuzhiyun case RPC_GSS_PROC_DESTROY:
1610*4882a593Smuzhiyun if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
1611*4882a593Smuzhiyun goto auth_err;
1612*4882a593Smuzhiyun /* Delete the entry from the cache_list and call cache_put */
1613*4882a593Smuzhiyun sunrpc_cache_unhash(sn->rsc_cache, &rsci->h);
1614*4882a593Smuzhiyun if (resv->iov_len + 4 > PAGE_SIZE)
1615*4882a593Smuzhiyun goto drop;
1616*4882a593Smuzhiyun svc_putnl(resv, RPC_SUCCESS);
1617*4882a593Smuzhiyun goto complete;
1618*4882a593Smuzhiyun case RPC_GSS_PROC_DATA:
1619*4882a593Smuzhiyun *authp = rpcsec_gsserr_ctxproblem;
1620*4882a593Smuzhiyun svcdata->verf_start = resv->iov_base + resv->iov_len;
1621*4882a593Smuzhiyun if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
1622*4882a593Smuzhiyun goto auth_err;
1623*4882a593Smuzhiyun rqstp->rq_cred = rsci->cred;
1624*4882a593Smuzhiyun get_group_info(rsci->cred.cr_group_info);
1625*4882a593Smuzhiyun *authp = rpc_autherr_badcred;
1626*4882a593Smuzhiyun switch (gc->gc_svc) {
1627*4882a593Smuzhiyun case RPC_GSS_SVC_NONE:
1628*4882a593Smuzhiyun break;
1629*4882a593Smuzhiyun case RPC_GSS_SVC_INTEGRITY:
1630*4882a593Smuzhiyun /* placeholders for length and seq. number: */
1631*4882a593Smuzhiyun svc_putnl(resv, 0);
1632*4882a593Smuzhiyun svc_putnl(resv, 0);
1633*4882a593Smuzhiyun if (unwrap_integ_data(rqstp, &rqstp->rq_arg,
1634*4882a593Smuzhiyun gc->gc_seq, rsci->mechctx))
1635*4882a593Smuzhiyun goto garbage_args;
1636*4882a593Smuzhiyun rqstp->rq_auth_slack = RPC_MAX_AUTH_SIZE;
1637*4882a593Smuzhiyun break;
1638*4882a593Smuzhiyun case RPC_GSS_SVC_PRIVACY:
1639*4882a593Smuzhiyun /* placeholders for length and seq. number: */
1640*4882a593Smuzhiyun svc_putnl(resv, 0);
1641*4882a593Smuzhiyun svc_putnl(resv, 0);
1642*4882a593Smuzhiyun if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
1643*4882a593Smuzhiyun gc->gc_seq, rsci->mechctx))
1644*4882a593Smuzhiyun goto garbage_args;
1645*4882a593Smuzhiyun rqstp->rq_auth_slack = RPC_MAX_AUTH_SIZE * 2;
1646*4882a593Smuzhiyun break;
1647*4882a593Smuzhiyun default:
1648*4882a593Smuzhiyun goto auth_err;
1649*4882a593Smuzhiyun }
1650*4882a593Smuzhiyun svcdata->rsci = rsci;
1651*4882a593Smuzhiyun cache_get(&rsci->h);
1652*4882a593Smuzhiyun rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor(
1653*4882a593Smuzhiyun rsci->mechctx->mech_type,
1654*4882a593Smuzhiyun GSS_C_QOP_DEFAULT,
1655*4882a593Smuzhiyun gc->gc_svc);
1656*4882a593Smuzhiyun ret = SVC_OK;
1657*4882a593Smuzhiyun trace_rpcgss_svc_authenticate(rqstp, gc);
1658*4882a593Smuzhiyun goto out;
1659*4882a593Smuzhiyun }
1660*4882a593Smuzhiyun garbage_args:
1661*4882a593Smuzhiyun ret = SVC_GARBAGE;
1662*4882a593Smuzhiyun goto out;
1663*4882a593Smuzhiyun auth_err:
1664*4882a593Smuzhiyun /* Restore write pointer to its original value: */
1665*4882a593Smuzhiyun xdr_ressize_check(rqstp, reject_stat);
1666*4882a593Smuzhiyun ret = SVC_DENIED;
1667*4882a593Smuzhiyun goto out;
1668*4882a593Smuzhiyun complete:
1669*4882a593Smuzhiyun ret = SVC_COMPLETE;
1670*4882a593Smuzhiyun goto out;
1671*4882a593Smuzhiyun drop:
1672*4882a593Smuzhiyun ret = SVC_CLOSE;
1673*4882a593Smuzhiyun out:
1674*4882a593Smuzhiyun if (rsci)
1675*4882a593Smuzhiyun cache_put(&rsci->h, sn->rsc_cache);
1676*4882a593Smuzhiyun return ret;
1677*4882a593Smuzhiyun }
1678*4882a593Smuzhiyun
1679*4882a593Smuzhiyun static __be32 *
svcauth_gss_prepare_to_wrap(struct xdr_buf * resbuf,struct gss_svc_data * gsd)1680*4882a593Smuzhiyun svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd)
1681*4882a593Smuzhiyun {
1682*4882a593Smuzhiyun __be32 *p;
1683*4882a593Smuzhiyun u32 verf_len;
1684*4882a593Smuzhiyun
1685*4882a593Smuzhiyun p = gsd->verf_start;
1686*4882a593Smuzhiyun gsd->verf_start = NULL;
1687*4882a593Smuzhiyun
1688*4882a593Smuzhiyun /* If the reply stat is nonzero, don't wrap: */
1689*4882a593Smuzhiyun if (*(p-1) != rpc_success)
1690*4882a593Smuzhiyun return NULL;
1691*4882a593Smuzhiyun /* Skip the verifier: */
1692*4882a593Smuzhiyun p += 1;
1693*4882a593Smuzhiyun verf_len = ntohl(*p++);
1694*4882a593Smuzhiyun p += XDR_QUADLEN(verf_len);
1695*4882a593Smuzhiyun /* move accept_stat to right place: */
1696*4882a593Smuzhiyun memcpy(p, p + 2, 4);
1697*4882a593Smuzhiyun /* Also don't wrap if the accept stat is nonzero: */
1698*4882a593Smuzhiyun if (*p != rpc_success) {
1699*4882a593Smuzhiyun resbuf->head[0].iov_len -= 2 * 4;
1700*4882a593Smuzhiyun return NULL;
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun p++;
1703*4882a593Smuzhiyun return p;
1704*4882a593Smuzhiyun }
1705*4882a593Smuzhiyun
1706*4882a593Smuzhiyun static inline int
svcauth_gss_wrap_resp_integ(struct svc_rqst * rqstp)1707*4882a593Smuzhiyun svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
1708*4882a593Smuzhiyun {
1709*4882a593Smuzhiyun struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
1710*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc = &gsd->clcred;
1711*4882a593Smuzhiyun struct xdr_buf *resbuf = &rqstp->rq_res;
1712*4882a593Smuzhiyun struct xdr_buf integ_buf;
1713*4882a593Smuzhiyun struct xdr_netobj mic;
1714*4882a593Smuzhiyun struct kvec *resv;
1715*4882a593Smuzhiyun __be32 *p;
1716*4882a593Smuzhiyun int integ_offset, integ_len;
1717*4882a593Smuzhiyun int stat = -EINVAL;
1718*4882a593Smuzhiyun
1719*4882a593Smuzhiyun p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
1720*4882a593Smuzhiyun if (p == NULL)
1721*4882a593Smuzhiyun goto out;
1722*4882a593Smuzhiyun integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
1723*4882a593Smuzhiyun integ_len = resbuf->len - integ_offset;
1724*4882a593Smuzhiyun if (integ_len & 3)
1725*4882a593Smuzhiyun goto out;
1726*4882a593Smuzhiyun *p++ = htonl(integ_len);
1727*4882a593Smuzhiyun *p++ = htonl(gc->gc_seq);
1728*4882a593Smuzhiyun if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, integ_len)) {
1729*4882a593Smuzhiyun WARN_ON_ONCE(1);
1730*4882a593Smuzhiyun goto out_err;
1731*4882a593Smuzhiyun }
1732*4882a593Smuzhiyun if (resbuf->tail[0].iov_base == NULL) {
1733*4882a593Smuzhiyun if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
1734*4882a593Smuzhiyun goto out_err;
1735*4882a593Smuzhiyun resbuf->tail[0].iov_base = resbuf->head[0].iov_base
1736*4882a593Smuzhiyun + resbuf->head[0].iov_len;
1737*4882a593Smuzhiyun resbuf->tail[0].iov_len = 0;
1738*4882a593Smuzhiyun }
1739*4882a593Smuzhiyun resv = &resbuf->tail[0];
1740*4882a593Smuzhiyun mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
1741*4882a593Smuzhiyun if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
1742*4882a593Smuzhiyun goto out_err;
1743*4882a593Smuzhiyun svc_putnl(resv, mic.len);
1744*4882a593Smuzhiyun memset(mic.data + mic.len, 0,
1745*4882a593Smuzhiyun round_up_to_quad(mic.len) - mic.len);
1746*4882a593Smuzhiyun resv->iov_len += XDR_QUADLEN(mic.len) << 2;
1747*4882a593Smuzhiyun /* not strictly required: */
1748*4882a593Smuzhiyun resbuf->len += XDR_QUADLEN(mic.len) << 2;
1749*4882a593Smuzhiyun if (resv->iov_len > PAGE_SIZE)
1750*4882a593Smuzhiyun goto out_err;
1751*4882a593Smuzhiyun out:
1752*4882a593Smuzhiyun stat = 0;
1753*4882a593Smuzhiyun out_err:
1754*4882a593Smuzhiyun return stat;
1755*4882a593Smuzhiyun }
1756*4882a593Smuzhiyun
1757*4882a593Smuzhiyun static inline int
svcauth_gss_wrap_resp_priv(struct svc_rqst * rqstp)1758*4882a593Smuzhiyun svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
1759*4882a593Smuzhiyun {
1760*4882a593Smuzhiyun struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
1761*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc = &gsd->clcred;
1762*4882a593Smuzhiyun struct xdr_buf *resbuf = &rqstp->rq_res;
1763*4882a593Smuzhiyun struct page **inpages = NULL;
1764*4882a593Smuzhiyun __be32 *p, *len;
1765*4882a593Smuzhiyun int offset;
1766*4882a593Smuzhiyun int pad;
1767*4882a593Smuzhiyun
1768*4882a593Smuzhiyun p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
1769*4882a593Smuzhiyun if (p == NULL)
1770*4882a593Smuzhiyun return 0;
1771*4882a593Smuzhiyun len = p++;
1772*4882a593Smuzhiyun offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
1773*4882a593Smuzhiyun *p++ = htonl(gc->gc_seq);
1774*4882a593Smuzhiyun inpages = resbuf->pages;
1775*4882a593Smuzhiyun /* XXX: Would be better to write some xdr helper functions for
1776*4882a593Smuzhiyun * nfs{2,3,4}xdr.c that place the data right, instead of copying: */
1777*4882a593Smuzhiyun
1778*4882a593Smuzhiyun /*
1779*4882a593Smuzhiyun * If there is currently tail data, make sure there is
1780*4882a593Smuzhiyun * room for the head, tail, and 2 * RPC_MAX_AUTH_SIZE in
1781*4882a593Smuzhiyun * the page, and move the current tail data such that
1782*4882a593Smuzhiyun * there is RPC_MAX_AUTH_SIZE slack space available in
1783*4882a593Smuzhiyun * both the head and tail.
1784*4882a593Smuzhiyun */
1785*4882a593Smuzhiyun if (resbuf->tail[0].iov_base) {
1786*4882a593Smuzhiyun if (resbuf->tail[0].iov_base >=
1787*4882a593Smuzhiyun resbuf->head[0].iov_base + PAGE_SIZE)
1788*4882a593Smuzhiyun return -EINVAL;
1789*4882a593Smuzhiyun if (resbuf->tail[0].iov_base < resbuf->head[0].iov_base)
1790*4882a593Smuzhiyun return -EINVAL;
1791*4882a593Smuzhiyun if (resbuf->tail[0].iov_len + resbuf->head[0].iov_len
1792*4882a593Smuzhiyun + 2 * RPC_MAX_AUTH_SIZE > PAGE_SIZE)
1793*4882a593Smuzhiyun return -ENOMEM;
1794*4882a593Smuzhiyun memmove(resbuf->tail[0].iov_base + RPC_MAX_AUTH_SIZE,
1795*4882a593Smuzhiyun resbuf->tail[0].iov_base,
1796*4882a593Smuzhiyun resbuf->tail[0].iov_len);
1797*4882a593Smuzhiyun resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE;
1798*4882a593Smuzhiyun }
1799*4882a593Smuzhiyun /*
1800*4882a593Smuzhiyun * If there is no current tail data, make sure there is
1801*4882a593Smuzhiyun * room for the head data, and 2 * RPC_MAX_AUTH_SIZE in the
1802*4882a593Smuzhiyun * allotted page, and set up tail information such that there
1803*4882a593Smuzhiyun * is RPC_MAX_AUTH_SIZE slack space available in both the
1804*4882a593Smuzhiyun * head and tail.
1805*4882a593Smuzhiyun */
1806*4882a593Smuzhiyun if (resbuf->tail[0].iov_base == NULL) {
1807*4882a593Smuzhiyun if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE)
1808*4882a593Smuzhiyun return -ENOMEM;
1809*4882a593Smuzhiyun resbuf->tail[0].iov_base = resbuf->head[0].iov_base
1810*4882a593Smuzhiyun + resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
1811*4882a593Smuzhiyun resbuf->tail[0].iov_len = 0;
1812*4882a593Smuzhiyun }
1813*4882a593Smuzhiyun if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
1814*4882a593Smuzhiyun return -ENOMEM;
1815*4882a593Smuzhiyun *len = htonl(resbuf->len - offset);
1816*4882a593Smuzhiyun pad = 3 - ((resbuf->len - offset - 1)&3);
1817*4882a593Smuzhiyun p = (__be32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
1818*4882a593Smuzhiyun memset(p, 0, pad);
1819*4882a593Smuzhiyun resbuf->tail[0].iov_len += pad;
1820*4882a593Smuzhiyun resbuf->len += pad;
1821*4882a593Smuzhiyun return 0;
1822*4882a593Smuzhiyun }
1823*4882a593Smuzhiyun
1824*4882a593Smuzhiyun static int
svcauth_gss_release(struct svc_rqst * rqstp)1825*4882a593Smuzhiyun svcauth_gss_release(struct svc_rqst *rqstp)
1826*4882a593Smuzhiyun {
1827*4882a593Smuzhiyun struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
1828*4882a593Smuzhiyun struct rpc_gss_wire_cred *gc;
1829*4882a593Smuzhiyun struct xdr_buf *resbuf = &rqstp->rq_res;
1830*4882a593Smuzhiyun int stat = -EINVAL;
1831*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id);
1832*4882a593Smuzhiyun
1833*4882a593Smuzhiyun if (!gsd)
1834*4882a593Smuzhiyun goto out;
1835*4882a593Smuzhiyun gc = &gsd->clcred;
1836*4882a593Smuzhiyun if (gc->gc_proc != RPC_GSS_PROC_DATA)
1837*4882a593Smuzhiyun goto out;
1838*4882a593Smuzhiyun /* Release can be called twice, but we only wrap once. */
1839*4882a593Smuzhiyun if (gsd->verf_start == NULL)
1840*4882a593Smuzhiyun goto out;
1841*4882a593Smuzhiyun /* normally not set till svc_send, but we need it here: */
1842*4882a593Smuzhiyun /* XXX: what for? Do we mess it up the moment we call svc_putu32
1843*4882a593Smuzhiyun * or whatever? */
1844*4882a593Smuzhiyun resbuf->len = total_buf_len(resbuf);
1845*4882a593Smuzhiyun switch (gc->gc_svc) {
1846*4882a593Smuzhiyun case RPC_GSS_SVC_NONE:
1847*4882a593Smuzhiyun break;
1848*4882a593Smuzhiyun case RPC_GSS_SVC_INTEGRITY:
1849*4882a593Smuzhiyun stat = svcauth_gss_wrap_resp_integ(rqstp);
1850*4882a593Smuzhiyun if (stat)
1851*4882a593Smuzhiyun goto out_err;
1852*4882a593Smuzhiyun break;
1853*4882a593Smuzhiyun case RPC_GSS_SVC_PRIVACY:
1854*4882a593Smuzhiyun stat = svcauth_gss_wrap_resp_priv(rqstp);
1855*4882a593Smuzhiyun if (stat)
1856*4882a593Smuzhiyun goto out_err;
1857*4882a593Smuzhiyun break;
1858*4882a593Smuzhiyun /*
1859*4882a593Smuzhiyun * For any other gc_svc value, svcauth_gss_accept() already set
1860*4882a593Smuzhiyun * the auth_error appropriately; just fall through:
1861*4882a593Smuzhiyun */
1862*4882a593Smuzhiyun }
1863*4882a593Smuzhiyun
1864*4882a593Smuzhiyun out:
1865*4882a593Smuzhiyun stat = 0;
1866*4882a593Smuzhiyun out_err:
1867*4882a593Smuzhiyun if (rqstp->rq_client)
1868*4882a593Smuzhiyun auth_domain_put(rqstp->rq_client);
1869*4882a593Smuzhiyun rqstp->rq_client = NULL;
1870*4882a593Smuzhiyun if (rqstp->rq_gssclient)
1871*4882a593Smuzhiyun auth_domain_put(rqstp->rq_gssclient);
1872*4882a593Smuzhiyun rqstp->rq_gssclient = NULL;
1873*4882a593Smuzhiyun if (rqstp->rq_cred.cr_group_info)
1874*4882a593Smuzhiyun put_group_info(rqstp->rq_cred.cr_group_info);
1875*4882a593Smuzhiyun rqstp->rq_cred.cr_group_info = NULL;
1876*4882a593Smuzhiyun if (gsd && gsd->rsci) {
1877*4882a593Smuzhiyun cache_put(&gsd->rsci->h, sn->rsc_cache);
1878*4882a593Smuzhiyun gsd->rsci = NULL;
1879*4882a593Smuzhiyun }
1880*4882a593Smuzhiyun return stat;
1881*4882a593Smuzhiyun }
1882*4882a593Smuzhiyun
1883*4882a593Smuzhiyun static void
svcauth_gss_domain_release_rcu(struct rcu_head * head)1884*4882a593Smuzhiyun svcauth_gss_domain_release_rcu(struct rcu_head *head)
1885*4882a593Smuzhiyun {
1886*4882a593Smuzhiyun struct auth_domain *dom = container_of(head, struct auth_domain, rcu_head);
1887*4882a593Smuzhiyun struct gss_domain *gd = container_of(dom, struct gss_domain, h);
1888*4882a593Smuzhiyun
1889*4882a593Smuzhiyun kfree(dom->name);
1890*4882a593Smuzhiyun kfree(gd);
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun static void
svcauth_gss_domain_release(struct auth_domain * dom)1894*4882a593Smuzhiyun svcauth_gss_domain_release(struct auth_domain *dom)
1895*4882a593Smuzhiyun {
1896*4882a593Smuzhiyun call_rcu(&dom->rcu_head, svcauth_gss_domain_release_rcu);
1897*4882a593Smuzhiyun }
1898*4882a593Smuzhiyun
1899*4882a593Smuzhiyun static struct auth_ops svcauthops_gss = {
1900*4882a593Smuzhiyun .name = "rpcsec_gss",
1901*4882a593Smuzhiyun .owner = THIS_MODULE,
1902*4882a593Smuzhiyun .flavour = RPC_AUTH_GSS,
1903*4882a593Smuzhiyun .accept = svcauth_gss_accept,
1904*4882a593Smuzhiyun .release = svcauth_gss_release,
1905*4882a593Smuzhiyun .domain_release = svcauth_gss_domain_release,
1906*4882a593Smuzhiyun .set_client = svcauth_gss_set_client,
1907*4882a593Smuzhiyun };
1908*4882a593Smuzhiyun
rsi_cache_create_net(struct net * net)1909*4882a593Smuzhiyun static int rsi_cache_create_net(struct net *net)
1910*4882a593Smuzhiyun {
1911*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1912*4882a593Smuzhiyun struct cache_detail *cd;
1913*4882a593Smuzhiyun int err;
1914*4882a593Smuzhiyun
1915*4882a593Smuzhiyun cd = cache_create_net(&rsi_cache_template, net);
1916*4882a593Smuzhiyun if (IS_ERR(cd))
1917*4882a593Smuzhiyun return PTR_ERR(cd);
1918*4882a593Smuzhiyun err = cache_register_net(cd, net);
1919*4882a593Smuzhiyun if (err) {
1920*4882a593Smuzhiyun cache_destroy_net(cd, net);
1921*4882a593Smuzhiyun return err;
1922*4882a593Smuzhiyun }
1923*4882a593Smuzhiyun sn->rsi_cache = cd;
1924*4882a593Smuzhiyun return 0;
1925*4882a593Smuzhiyun }
1926*4882a593Smuzhiyun
rsi_cache_destroy_net(struct net * net)1927*4882a593Smuzhiyun static void rsi_cache_destroy_net(struct net *net)
1928*4882a593Smuzhiyun {
1929*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1930*4882a593Smuzhiyun struct cache_detail *cd = sn->rsi_cache;
1931*4882a593Smuzhiyun
1932*4882a593Smuzhiyun sn->rsi_cache = NULL;
1933*4882a593Smuzhiyun cache_purge(cd);
1934*4882a593Smuzhiyun cache_unregister_net(cd, net);
1935*4882a593Smuzhiyun cache_destroy_net(cd, net);
1936*4882a593Smuzhiyun }
1937*4882a593Smuzhiyun
rsc_cache_create_net(struct net * net)1938*4882a593Smuzhiyun static int rsc_cache_create_net(struct net *net)
1939*4882a593Smuzhiyun {
1940*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1941*4882a593Smuzhiyun struct cache_detail *cd;
1942*4882a593Smuzhiyun int err;
1943*4882a593Smuzhiyun
1944*4882a593Smuzhiyun cd = cache_create_net(&rsc_cache_template, net);
1945*4882a593Smuzhiyun if (IS_ERR(cd))
1946*4882a593Smuzhiyun return PTR_ERR(cd);
1947*4882a593Smuzhiyun err = cache_register_net(cd, net);
1948*4882a593Smuzhiyun if (err) {
1949*4882a593Smuzhiyun cache_destroy_net(cd, net);
1950*4882a593Smuzhiyun return err;
1951*4882a593Smuzhiyun }
1952*4882a593Smuzhiyun sn->rsc_cache = cd;
1953*4882a593Smuzhiyun return 0;
1954*4882a593Smuzhiyun }
1955*4882a593Smuzhiyun
rsc_cache_destroy_net(struct net * net)1956*4882a593Smuzhiyun static void rsc_cache_destroy_net(struct net *net)
1957*4882a593Smuzhiyun {
1958*4882a593Smuzhiyun struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1959*4882a593Smuzhiyun struct cache_detail *cd = sn->rsc_cache;
1960*4882a593Smuzhiyun
1961*4882a593Smuzhiyun sn->rsc_cache = NULL;
1962*4882a593Smuzhiyun cache_purge(cd);
1963*4882a593Smuzhiyun cache_unregister_net(cd, net);
1964*4882a593Smuzhiyun cache_destroy_net(cd, net);
1965*4882a593Smuzhiyun }
1966*4882a593Smuzhiyun
1967*4882a593Smuzhiyun int
gss_svc_init_net(struct net * net)1968*4882a593Smuzhiyun gss_svc_init_net(struct net *net)
1969*4882a593Smuzhiyun {
1970*4882a593Smuzhiyun int rv;
1971*4882a593Smuzhiyun
1972*4882a593Smuzhiyun rv = rsc_cache_create_net(net);
1973*4882a593Smuzhiyun if (rv)
1974*4882a593Smuzhiyun return rv;
1975*4882a593Smuzhiyun rv = rsi_cache_create_net(net);
1976*4882a593Smuzhiyun if (rv)
1977*4882a593Smuzhiyun goto out1;
1978*4882a593Smuzhiyun rv = create_use_gss_proxy_proc_entry(net);
1979*4882a593Smuzhiyun if (rv)
1980*4882a593Smuzhiyun goto out2;
1981*4882a593Smuzhiyun return 0;
1982*4882a593Smuzhiyun out2:
1983*4882a593Smuzhiyun rsi_cache_destroy_net(net);
1984*4882a593Smuzhiyun out1:
1985*4882a593Smuzhiyun rsc_cache_destroy_net(net);
1986*4882a593Smuzhiyun return rv;
1987*4882a593Smuzhiyun }
1988*4882a593Smuzhiyun
1989*4882a593Smuzhiyun void
gss_svc_shutdown_net(struct net * net)1990*4882a593Smuzhiyun gss_svc_shutdown_net(struct net *net)
1991*4882a593Smuzhiyun {
1992*4882a593Smuzhiyun destroy_use_gss_proxy_proc_entry(net);
1993*4882a593Smuzhiyun rsi_cache_destroy_net(net);
1994*4882a593Smuzhiyun rsc_cache_destroy_net(net);
1995*4882a593Smuzhiyun }
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun int
gss_svc_init(void)1998*4882a593Smuzhiyun gss_svc_init(void)
1999*4882a593Smuzhiyun {
2000*4882a593Smuzhiyun return svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
2001*4882a593Smuzhiyun }
2002*4882a593Smuzhiyun
2003*4882a593Smuzhiyun void
gss_svc_shutdown(void)2004*4882a593Smuzhiyun gss_svc_shutdown(void)
2005*4882a593Smuzhiyun {
2006*4882a593Smuzhiyun svc_auth_unregister(RPC_AUTH_GSS);
2007*4882a593Smuzhiyun }
2008