OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [tags/] [linux-2.6/] [linux-2.6.24_or32_unified_v2.3/] [net/] [sunrpc/] [auth_gss/] [svcauth_gss.c] - Blame information for rev 8

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Neil Brown <neilb@cse.unsw.edu.au>
3
 * J. Bruce Fields <bfields@umich.edu>
4
 * Andy Adamson <andros@umich.edu>
5
 * Dug Song <dugsong@monkey.org>
6
 *
7
 * RPCSEC_GSS server authentication.
8
 * This implements RPCSEC_GSS as defined in rfc2203 (rpcsec_gss) and rfc2078
9
 * (gssapi)
10
 *
11
 * The RPCSEC_GSS involves three stages:
12
 *  1/ context creation
13
 *  2/ data exchange
14
 *  3/ context destruction
15
 *
16
 * Context creation is handled largely by upcalls to user-space.
17
 *  In particular, GSS_Accept_sec_context is handled by an upcall
18
 * Data exchange is handled entirely within the kernel
19
 *  In particular, GSS_GetMIC, GSS_VerifyMIC, GSS_Seal, GSS_Unseal are in-kernel.
20
 * Context destruction is handled in-kernel
21
 *  GSS_Delete_sec_context is in-kernel
22
 *
23
 * Context creation is initiated by a RPCSEC_GSS_INIT request arriving.
24
 * The context handle and gss_token are used as a key into the rpcsec_init cache.
25
 * The content of this cache includes some of the outputs of GSS_Accept_sec_context,
26
 * being major_status, minor_status, context_handle, reply_token.
27
 * These are sent back to the client.
28
 * Sequence window management is handled by the kernel.  The window size if currently
29
 * a compile time constant.
30
 *
31
 * When user-space is happy that a context is established, it places an entry
32
 * in the rpcsec_context cache. The key for this cache is the context_handle.
33
 * The content includes:
34
 *   uid/gidlist - for determining access rights
35
 *   mechanism type
36
 *   mechanism specific information, such as a key
37
 *
38
 */
39
 
40
#include <linux/types.h>
41
#include <linux/module.h>
42
#include <linux/pagemap.h>
43
 
44
#include <linux/sunrpc/auth_gss.h>
45
#include <linux/sunrpc/gss_err.h>
46
#include <linux/sunrpc/svcauth.h>
47
#include <linux/sunrpc/svcauth_gss.h>
48
#include <linux/sunrpc/cache.h>
49
 
50
#ifdef RPC_DEBUG
51
# define RPCDBG_FACILITY        RPCDBG_AUTH
52
#endif
53
 
54
/* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests
55
 * into replies.
56
 *
57
 * Key is context handle (\x if empty) and gss_token.
58
 * Content is major_status minor_status (integers) context_handle, reply_token.
59
 *
60
 */
61
 
62
static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
63
{
64
        return a->len == b->len && 0 == memcmp(a->data, b->data, a->len);
65
}
66
 
67
#define RSI_HASHBITS    6
68
#define RSI_HASHMAX     (1<<RSI_HASHBITS)
69
#define RSI_HASHMASK    (RSI_HASHMAX-1)
70
 
71
struct rsi {
72
        struct cache_head       h;
73
        struct xdr_netobj       in_handle, in_token;
74
        struct xdr_netobj       out_handle, out_token;
75
        int                     major_status, minor_status;
76
};
77
 
78
static struct cache_head *rsi_table[RSI_HASHMAX];
79
static struct cache_detail rsi_cache;
80
static struct rsi *rsi_update(struct rsi *new, struct rsi *old);
81
static struct rsi *rsi_lookup(struct rsi *item);
82
 
83
static void rsi_free(struct rsi *rsii)
84
{
85
        kfree(rsii->in_handle.data);
86
        kfree(rsii->in_token.data);
87
        kfree(rsii->out_handle.data);
88
        kfree(rsii->out_token.data);
89
}
90
 
91
static void rsi_put(struct kref *ref)
92
{
93
        struct rsi *rsii = container_of(ref, struct rsi, h.ref);
94
        rsi_free(rsii);
95
        kfree(rsii);
96
}
97
 
98
static inline int rsi_hash(struct rsi *item)
99
{
100
        return hash_mem(item->in_handle.data, item->in_handle.len, RSI_HASHBITS)
101
             ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS);
102
}
103
 
104
static int rsi_match(struct cache_head *a, struct cache_head *b)
105
{
106
        struct rsi *item = container_of(a, struct rsi, h);
107
        struct rsi *tmp = container_of(b, struct rsi, h);
108
        return netobj_equal(&item->in_handle, &tmp->in_handle)
109
                && netobj_equal(&item->in_token, &tmp->in_token);
110
}
111
 
112
static int dup_to_netobj(struct xdr_netobj *dst, char *src, int len)
113
{
114
        dst->len = len;
115
        dst->data = (len ? kmemdup(src, len, GFP_KERNEL) : NULL);
116
        if (len && !dst->data)
117
                return -ENOMEM;
118
        return 0;
119
}
120
 
121
static inline int dup_netobj(struct xdr_netobj *dst, struct xdr_netobj *src)
122
{
123
        return dup_to_netobj(dst, src->data, src->len);
124
}
125
 
126
static void rsi_init(struct cache_head *cnew, struct cache_head *citem)
127
{
128
        struct rsi *new = container_of(cnew, struct rsi, h);
129
        struct rsi *item = container_of(citem, struct rsi, h);
130
 
131
        new->out_handle.data = NULL;
132
        new->out_handle.len = 0;
133
        new->out_token.data = NULL;
134
        new->out_token.len = 0;
135
        new->in_handle.len = item->in_handle.len;
136
        item->in_handle.len = 0;
137
        new->in_token.len = item->in_token.len;
138
        item->in_token.len = 0;
139
        new->in_handle.data = item->in_handle.data;
140
        item->in_handle.data = NULL;
141
        new->in_token.data = item->in_token.data;
142
        item->in_token.data = NULL;
143
}
144
 
145
static void update_rsi(struct cache_head *cnew, struct cache_head *citem)
146
{
147
        struct rsi *new = container_of(cnew, struct rsi, h);
148
        struct rsi *item = container_of(citem, struct rsi, h);
149
 
150
        BUG_ON(new->out_handle.data || new->out_token.data);
151
        new->out_handle.len = item->out_handle.len;
152
        item->out_handle.len = 0;
153
        new->out_token.len = item->out_token.len;
154
        item->out_token.len = 0;
155
        new->out_handle.data = item->out_handle.data;
156
        item->out_handle.data = NULL;
157
        new->out_token.data = item->out_token.data;
158
        item->out_token.data = NULL;
159
 
160
        new->major_status = item->major_status;
161
        new->minor_status = item->minor_status;
162
}
163
 
164
static struct cache_head *rsi_alloc(void)
165
{
166
        struct rsi *rsii = kmalloc(sizeof(*rsii), GFP_KERNEL);
167
        if (rsii)
168
                return &rsii->h;
169
        else
170
                return NULL;
171
}
172
 
173
static void rsi_request(struct cache_detail *cd,
174
                       struct cache_head *h,
175
                       char **bpp, int *blen)
176
{
177
        struct rsi *rsii = container_of(h, struct rsi, h);
178
 
179
        qword_addhex(bpp, blen, rsii->in_handle.data, rsii->in_handle.len);
180
        qword_addhex(bpp, blen, rsii->in_token.data, rsii->in_token.len);
181
        (*bpp)[-1] = '\n';
182
}
183
 
184
 
185
static int rsi_parse(struct cache_detail *cd,
186
                    char *mesg, int mlen)
187
{
188
        /* context token expiry major minor context token */
189
        char *buf = mesg;
190
        char *ep;
191
        int len;
192
        struct rsi rsii, *rsip = NULL;
193
        time_t expiry;
194
        int status = -EINVAL;
195
 
196
        memset(&rsii, 0, sizeof(rsii));
197
        /* handle */
198
        len = qword_get(&mesg, buf, mlen);
199
        if (len < 0)
200
                goto out;
201
        status = -ENOMEM;
202
        if (dup_to_netobj(&rsii.in_handle, buf, len))
203
                goto out;
204
 
205
        /* token */
206
        len = qword_get(&mesg, buf, mlen);
207
        status = -EINVAL;
208
        if (len < 0)
209
                goto out;
210
        status = -ENOMEM;
211
        if (dup_to_netobj(&rsii.in_token, buf, len))
212
                goto out;
213
 
214
        rsip = rsi_lookup(&rsii);
215
        if (!rsip)
216
                goto out;
217
 
218
        rsii.h.flags = 0;
219
        /* expiry */
220
        expiry = get_expiry(&mesg);
221
        status = -EINVAL;
222
        if (expiry == 0)
223
                goto out;
224
 
225
        /* major/minor */
226
        len = qword_get(&mesg, buf, mlen);
227
        if (len < 0)
228
                goto out;
229
        if (len == 0) {
230
                goto out;
231
        } else {
232
                rsii.major_status = simple_strtoul(buf, &ep, 10);
233
                if (*ep)
234
                        goto out;
235
                len = qword_get(&mesg, buf, mlen);
236
                if (len <= 0)
237
                        goto out;
238
                rsii.minor_status = simple_strtoul(buf, &ep, 10);
239
                if (*ep)
240
                        goto out;
241
 
242
                /* out_handle */
243
                len = qword_get(&mesg, buf, mlen);
244
                if (len < 0)
245
                        goto out;
246
                status = -ENOMEM;
247
                if (dup_to_netobj(&rsii.out_handle, buf, len))
248
                        goto out;
249
 
250
                /* out_token */
251
                len = qword_get(&mesg, buf, mlen);
252
                status = -EINVAL;
253
                if (len < 0)
254
                        goto out;
255
                status = -ENOMEM;
256
                if (dup_to_netobj(&rsii.out_token, buf, len))
257
                        goto out;
258
        }
259
        rsii.h.expiry_time = expiry;
260
        rsip = rsi_update(&rsii, rsip);
261
        status = 0;
262
out:
263
        rsi_free(&rsii);
264
        if (rsip)
265
                cache_put(&rsip->h, &rsi_cache);
266
        else
267
                status = -ENOMEM;
268
        return status;
269
}
270
 
271
static struct cache_detail rsi_cache = {
272
        .owner          = THIS_MODULE,
273
        .hash_size      = RSI_HASHMAX,
274
        .hash_table     = rsi_table,
275
        .name           = "auth.rpcsec.init",
276
        .cache_put      = rsi_put,
277
        .cache_request  = rsi_request,
278
        .cache_parse    = rsi_parse,
279
        .match          = rsi_match,
280
        .init           = rsi_init,
281
        .update         = update_rsi,
282
        .alloc          = rsi_alloc,
283
};
284
 
285
static struct rsi *rsi_lookup(struct rsi *item)
286
{
287
        struct cache_head *ch;
288
        int hash = rsi_hash(item);
289
 
290
        ch = sunrpc_cache_lookup(&rsi_cache, &item->h, hash);
291
        if (ch)
292
                return container_of(ch, struct rsi, h);
293
        else
294
                return NULL;
295
}
296
 
297
static struct rsi *rsi_update(struct rsi *new, struct rsi *old)
298
{
299
        struct cache_head *ch;
300
        int hash = rsi_hash(new);
301
 
302
        ch = sunrpc_cache_update(&rsi_cache, &new->h,
303
                                 &old->h, hash);
304
        if (ch)
305
                return container_of(ch, struct rsi, h);
306
        else
307
                return NULL;
308
}
309
 
310
 
311
/*
312
 * The rpcsec_context cache is used to store a context that is
313
 * used in data exchange.
314
 * The key is a context handle. The content is:
315
 *  uid, gidlist, mechanism, service-set, mech-specific-data
316
 */
317
 
318
#define RSC_HASHBITS    10
319
#define RSC_HASHMAX     (1<<RSC_HASHBITS)
320
#define RSC_HASHMASK    (RSC_HASHMAX-1)
321
 
322
#define GSS_SEQ_WIN     128
323
 
324
struct gss_svc_seq_data {
325
        /* highest seq number seen so far: */
326
        int                     sd_max;
327
        /* for i such that sd_max-GSS_SEQ_WIN < i <= sd_max, the i-th bit of
328
         * sd_win is nonzero iff sequence number i has been seen already: */
329
        unsigned long           sd_win[GSS_SEQ_WIN/BITS_PER_LONG];
330
        spinlock_t              sd_lock;
331
};
332
 
333
struct rsc {
334
        struct cache_head       h;
335
        struct xdr_netobj       handle;
336
        struct svc_cred         cred;
337
        struct gss_svc_seq_data seqdata;
338
        struct gss_ctx          *mechctx;
339
};
340
 
341
static struct cache_head *rsc_table[RSC_HASHMAX];
342
static struct cache_detail rsc_cache;
343
static struct rsc *rsc_update(struct rsc *new, struct rsc *old);
344
static struct rsc *rsc_lookup(struct rsc *item);
345
 
346
static void rsc_free(struct rsc *rsci)
347
{
348
        kfree(rsci->handle.data);
349
        if (rsci->mechctx)
350
                gss_delete_sec_context(&rsci->mechctx);
351
        if (rsci->cred.cr_group_info)
352
                put_group_info(rsci->cred.cr_group_info);
353
}
354
 
355
static void rsc_put(struct kref *ref)
356
{
357
        struct rsc *rsci = container_of(ref, struct rsc, h.ref);
358
 
359
        rsc_free(rsci);
360
        kfree(rsci);
361
}
362
 
363
static inline int
364
rsc_hash(struct rsc *rsci)
365
{
366
        return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS);
367
}
368
 
369
static int
370
rsc_match(struct cache_head *a, struct cache_head *b)
371
{
372
        struct rsc *new = container_of(a, struct rsc, h);
373
        struct rsc *tmp = container_of(b, struct rsc, h);
374
 
375
        return netobj_equal(&new->handle, &tmp->handle);
376
}
377
 
378
static void
379
rsc_init(struct cache_head *cnew, struct cache_head *ctmp)
380
{
381
        struct rsc *new = container_of(cnew, struct rsc, h);
382
        struct rsc *tmp = container_of(ctmp, struct rsc, h);
383
 
384
        new->handle.len = tmp->handle.len;
385
        tmp->handle.len = 0;
386
        new->handle.data = tmp->handle.data;
387
        tmp->handle.data = NULL;
388
        new->mechctx = NULL;
389
        new->cred.cr_group_info = NULL;
390
}
391
 
392
static void
393
update_rsc(struct cache_head *cnew, struct cache_head *ctmp)
394
{
395
        struct rsc *new = container_of(cnew, struct rsc, h);
396
        struct rsc *tmp = container_of(ctmp, struct rsc, h);
397
 
398
        new->mechctx = tmp->mechctx;
399
        tmp->mechctx = NULL;
400
        memset(&new->seqdata, 0, sizeof(new->seqdata));
401
        spin_lock_init(&new->seqdata.sd_lock);
402
        new->cred = tmp->cred;
403
        tmp->cred.cr_group_info = NULL;
404
}
405
 
406
static struct cache_head *
407
rsc_alloc(void)
408
{
409
        struct rsc *rsci = kmalloc(sizeof(*rsci), GFP_KERNEL);
410
        if (rsci)
411
                return &rsci->h;
412
        else
413
                return NULL;
414
}
415
 
416
static int rsc_parse(struct cache_detail *cd,
417
                     char *mesg, int mlen)
418
{
419
        /* contexthandle expiry [ uid gid N <n gids> mechname ...mechdata... ] */
420
        char *buf = mesg;
421
        int len, rv;
422
        struct rsc rsci, *rscp = NULL;
423
        time_t expiry;
424
        int status = -EINVAL;
425
        struct gss_api_mech *gm = NULL;
426
 
427
        memset(&rsci, 0, sizeof(rsci));
428
        /* context handle */
429
        len = qword_get(&mesg, buf, mlen);
430
        if (len < 0) goto out;
431
        status = -ENOMEM;
432
        if (dup_to_netobj(&rsci.handle, buf, len))
433
                goto out;
434
 
435
        rsci.h.flags = 0;
436
        /* expiry */
437
        expiry = get_expiry(&mesg);
438
        status = -EINVAL;
439
        if (expiry == 0)
440
                goto out;
441
 
442
        rscp = rsc_lookup(&rsci);
443
        if (!rscp)
444
                goto out;
445
 
446
        /* uid, or NEGATIVE */
447
        rv = get_int(&mesg, &rsci.cred.cr_uid);
448
        if (rv == -EINVAL)
449
                goto out;
450
        if (rv == -ENOENT)
451
                set_bit(CACHE_NEGATIVE, &rsci.h.flags);
452
        else {
453
                int N, i;
454
 
455
                /* gid */
456
                if (get_int(&mesg, &rsci.cred.cr_gid))
457
                        goto out;
458
 
459
                /* number of additional gid's */
460
                if (get_int(&mesg, &N))
461
                        goto out;
462
                status = -ENOMEM;
463
                rsci.cred.cr_group_info = groups_alloc(N);
464
                if (rsci.cred.cr_group_info == NULL)
465
                        goto out;
466
 
467
                /* gid's */
468
                status = -EINVAL;
469
                for (i=0; i<N; i++) {
470
                        gid_t gid;
471
                        if (get_int(&mesg, &gid))
472
                                goto out;
473
                        GROUP_AT(rsci.cred.cr_group_info, i) = gid;
474
                }
475
 
476
                /* mech name */
477
                len = qword_get(&mesg, buf, mlen);
478
                if (len < 0)
479
                        goto out;
480
                gm = gss_mech_get_by_name(buf);
481
                status = -EOPNOTSUPP;
482
                if (!gm)
483
                        goto out;
484
 
485
                status = -EINVAL;
486
                /* mech-specific data: */
487
                len = qword_get(&mesg, buf, mlen);
488
                if (len < 0)
489
                        goto out;
490
                status = gss_import_sec_context(buf, len, gm, &rsci.mechctx);
491
                if (status)
492
                        goto out;
493
        }
494
        rsci.h.expiry_time = expiry;
495
        rscp = rsc_update(&rsci, rscp);
496
        status = 0;
497
out:
498
        gss_mech_put(gm);
499
        rsc_free(&rsci);
500
        if (rscp)
501
                cache_put(&rscp->h, &rsc_cache);
502
        else
503
                status = -ENOMEM;
504
        return status;
505
}
506
 
507
static struct cache_detail rsc_cache = {
508
        .owner          = THIS_MODULE,
509
        .hash_size      = RSC_HASHMAX,
510
        .hash_table     = rsc_table,
511
        .name           = "auth.rpcsec.context",
512
        .cache_put      = rsc_put,
513
        .cache_parse    = rsc_parse,
514
        .match          = rsc_match,
515
        .init           = rsc_init,
516
        .update         = update_rsc,
517
        .alloc          = rsc_alloc,
518
};
519
 
520
static struct rsc *rsc_lookup(struct rsc *item)
521
{
522
        struct cache_head *ch;
523
        int hash = rsc_hash(item);
524
 
525
        ch = sunrpc_cache_lookup(&rsc_cache, &item->h, hash);
526
        if (ch)
527
                return container_of(ch, struct rsc, h);
528
        else
529
                return NULL;
530
}
531
 
532
static struct rsc *rsc_update(struct rsc *new, struct rsc *old)
533
{
534
        struct cache_head *ch;
535
        int hash = rsc_hash(new);
536
 
537
        ch = sunrpc_cache_update(&rsc_cache, &new->h,
538
                                 &old->h, hash);
539
        if (ch)
540
                return container_of(ch, struct rsc, h);
541
        else
542
                return NULL;
543
}
544
 
545
 
546
static struct rsc *
547
gss_svc_searchbyctx(struct xdr_netobj *handle)
548
{
549
        struct rsc rsci;
550
        struct rsc *found;
551
 
552
        memset(&rsci, 0, sizeof(rsci));
553
        if (dup_to_netobj(&rsci.handle, handle->data, handle->len))
554
                return NULL;
555
        found = rsc_lookup(&rsci);
556
        rsc_free(&rsci);
557
        if (!found)
558
                return NULL;
559
        if (cache_check(&rsc_cache, &found->h, NULL))
560
                return NULL;
561
        return found;
562
}
563
 
564
/* Implements sequence number algorithm as specified in RFC 2203. */
565
static int
566
gss_check_seq_num(struct rsc *rsci, int seq_num)
567
{
568
        struct gss_svc_seq_data *sd = &rsci->seqdata;
569
 
570
        spin_lock(&sd->sd_lock);
571
        if (seq_num > sd->sd_max) {
572
                if (seq_num >= sd->sd_max + GSS_SEQ_WIN) {
573
                        memset(sd->sd_win,0,sizeof(sd->sd_win));
574
                        sd->sd_max = seq_num;
575
                } else while (sd->sd_max < seq_num) {
576
                        sd->sd_max++;
577
                        __clear_bit(sd->sd_max % GSS_SEQ_WIN, sd->sd_win);
578
                }
579
                __set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win);
580
                goto ok;
581
        } else if (seq_num <= sd->sd_max - GSS_SEQ_WIN) {
582
                goto drop;
583
        }
584
        /* sd_max - GSS_SEQ_WIN < seq_num <= sd_max */
585
        if (__test_and_set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win))
586
                goto drop;
587
ok:
588
        spin_unlock(&sd->sd_lock);
589
        return 1;
590
drop:
591
        spin_unlock(&sd->sd_lock);
592
        return 0;
593
}
594
 
595
static inline u32 round_up_to_quad(u32 i)
596
{
597
        return (i + 3 ) & ~3;
598
}
599
 
600
static inline int
601
svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o)
602
{
603
        int l;
604
 
605
        if (argv->iov_len < 4)
606
                return -1;
607
        o->len = svc_getnl(argv);
608
        l = round_up_to_quad(o->len);
609
        if (argv->iov_len < l)
610
                return -1;
611
        o->data = argv->iov_base;
612
        argv->iov_base += l;
613
        argv->iov_len -= l;
614
        return 0;
615
}
616
 
617
static inline int
618
svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
619
{
620
        u8 *p;
621
 
622
        if (resv->iov_len + 4 > PAGE_SIZE)
623
                return -1;
624
        svc_putnl(resv, o->len);
625
        p = resv->iov_base + resv->iov_len;
626
        resv->iov_len += round_up_to_quad(o->len);
627
        if (resv->iov_len > PAGE_SIZE)
628
                return -1;
629
        memcpy(p, o->data, o->len);
630
        memset(p + o->len, 0, round_up_to_quad(o->len) - o->len);
631
        return 0;
632
}
633
 
634
/*
635
 * Verify the checksum on the header and return SVC_OK on success.
636
 * Otherwise, return SVC_DROP (in the case of a bad sequence number)
637
 * or return SVC_DENIED and indicate error in authp.
638
 */
639
static int
640
gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
641
                  __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp)
642
{
643
        struct gss_ctx          *ctx_id = rsci->mechctx;
644
        struct xdr_buf          rpchdr;
645
        struct xdr_netobj       checksum;
646
        u32                     flavor = 0;
647
        struct kvec             *argv = &rqstp->rq_arg.head[0];
648
        struct kvec             iov;
649
 
650
        /* data to compute the checksum over: */
651
        iov.iov_base = rpcstart;
652
        iov.iov_len = (u8 *)argv->iov_base - (u8 *)rpcstart;
653
        xdr_buf_from_iov(&iov, &rpchdr);
654
 
655
        *authp = rpc_autherr_badverf;
656
        if (argv->iov_len < 4)
657
                return SVC_DENIED;
658
        flavor = svc_getnl(argv);
659
        if (flavor != RPC_AUTH_GSS)
660
                return SVC_DENIED;
661
        if (svc_safe_getnetobj(argv, &checksum))
662
                return SVC_DENIED;
663
 
664
        if (rqstp->rq_deferred) /* skip verification of revisited request */
665
                return SVC_OK;
666
        if (gss_verify_mic(ctx_id, &rpchdr, &checksum) != GSS_S_COMPLETE) {
667
                *authp = rpcsec_gsserr_credproblem;
668
                return SVC_DENIED;
669
        }
670
 
671
        if (gc->gc_seq > MAXSEQ) {
672
                dprintk("RPC:       svcauth_gss: discarding request with "
673
                                "large sequence number %d\n", gc->gc_seq);
674
                *authp = rpcsec_gsserr_ctxproblem;
675
                return SVC_DENIED;
676
        }
677
        if (!gss_check_seq_num(rsci, gc->gc_seq)) {
678
                dprintk("RPC:       svcauth_gss: discarding request with "
679
                                "old sequence number %d\n", gc->gc_seq);
680
                return SVC_DROP;
681
        }
682
        return SVC_OK;
683
}
684
 
685
static int
686
gss_write_null_verf(struct svc_rqst *rqstp)
687
{
688
        __be32     *p;
689
 
690
        svc_putnl(rqstp->rq_res.head, RPC_AUTH_NULL);
691
        p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
692
        /* don't really need to check if head->iov_len > PAGE_SIZE ... */
693
        *p++ = 0;
694
        if (!xdr_ressize_check(rqstp, p))
695
                return -1;
696
        return 0;
697
}
698
 
699
static int
700
gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
701
{
702
        __be32                  xdr_seq;
703
        u32                     maj_stat;
704
        struct xdr_buf          verf_data;
705
        struct xdr_netobj       mic;
706
        __be32                  *p;
707
        struct kvec             iov;
708
 
709
        svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS);
710
        xdr_seq = htonl(seq);
711
 
712
        iov.iov_base = &xdr_seq;
713
        iov.iov_len = sizeof(xdr_seq);
714
        xdr_buf_from_iov(&iov, &verf_data);
715
        p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
716
        mic.data = (u8 *)(p + 1);
717
        maj_stat = gss_get_mic(ctx_id, &verf_data, &mic);
718
        if (maj_stat != GSS_S_COMPLETE)
719
                return -1;
720
        *p++ = htonl(mic.len);
721
        memset((u8 *)p + mic.len, 0, round_up_to_quad(mic.len) - mic.len);
722
        p += XDR_QUADLEN(mic.len);
723
        if (!xdr_ressize_check(rqstp, p))
724
                return -1;
725
        return 0;
726
}
727
 
728
struct gss_domain {
729
        struct auth_domain      h;
730
        u32                     pseudoflavor;
731
};
732
 
733
static struct auth_domain *
734
find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
735
{
736
        char *name;
737
 
738
        name = gss_service_to_auth_domain_name(ctx->mech_type, svc);
739
        if (!name)
740
                return NULL;
741
        return auth_domain_find(name);
742
}
743
 
744
static struct auth_ops svcauthops_gss;
745
 
746
u32 svcauth_gss_flavor(struct auth_domain *dom)
747
{
748
        struct gss_domain *gd = container_of(dom, struct gss_domain, h);
749
 
750
        return gd->pseudoflavor;
751
}
752
 
753
EXPORT_SYMBOL(svcauth_gss_flavor);
754
 
755
int
756
svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
757
{
758
        struct gss_domain       *new;
759
        struct auth_domain      *test;
760
        int                     stat = -ENOMEM;
761
 
762
        new = kmalloc(sizeof(*new), GFP_KERNEL);
763
        if (!new)
764
                goto out;
765
        kref_init(&new->h.ref);
766
        new->h.name = kstrdup(name, GFP_KERNEL);
767
        if (!new->h.name)
768
                goto out_free_dom;
769
        new->h.flavour = &svcauthops_gss;
770
        new->pseudoflavor = pseudoflavor;
771
 
772
        stat = 0;
773
        test = auth_domain_lookup(name, &new->h);
774
        if (test != &new->h) { /* Duplicate registration */
775
                auth_domain_put(test);
776
                kfree(new->h.name);
777
                goto out_free_dom;
778
        }
779
        return 0;
780
 
781
out_free_dom:
782
        kfree(new);
783
out:
784
        return stat;
785
}
786
 
787
EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor);
788
 
789
static inline int
790
read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
791
{
792
        __be32  raw;
793
        int     status;
794
 
795
        status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
796
        if (status)
797
                return status;
798
        *obj = ntohl(raw);
799
        return 0;
800
}
801
 
802
/* It would be nice if this bit of code could be shared with the client.
803
 * Obstacles:
804
 *      The client shouldn't malloc(), would have to pass in own memory.
805
 *      The server uses base of head iovec as read pointer, while the
806
 *      client uses separate pointer. */
807
static int
808
unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
809
{
810
        int stat = -EINVAL;
811
        u32 integ_len, maj_stat;
812
        struct xdr_netobj mic;
813
        struct xdr_buf integ_buf;
814
 
815
        integ_len = svc_getnl(&buf->head[0]);
816
        if (integ_len & 3)
817
                return stat;
818
        if (integ_len > buf->len)
819
                return stat;
820
        if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len))
821
                BUG();
822
        /* copy out mic... */
823
        if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
824
                BUG();
825
        if (mic.len > RPC_MAX_AUTH_SIZE)
826
                return stat;
827
        mic.data = kmalloc(mic.len, GFP_KERNEL);
828
        if (!mic.data)
829
                return stat;
830
        if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len))
831
                goto out;
832
        maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
833
        if (maj_stat != GSS_S_COMPLETE)
834
                goto out;
835
        if (svc_getnl(&buf->head[0]) != seq)
836
                goto out;
837
        stat = 0;
838
out:
839
        kfree(mic.data);
840
        return stat;
841
}
842
 
843
static inline int
844
total_buf_len(struct xdr_buf *buf)
845
{
846
        return buf->head[0].iov_len + buf->page_len + buf->tail[0].iov_len;
847
}
848
 
849
static void
850
fix_priv_head(struct xdr_buf *buf, int pad)
851
{
852
        if (buf->page_len == 0) {
853
                /* We need to adjust head and buf->len in tandem in this
854
                 * case to make svc_defer() work--it finds the original
855
                 * buffer start using buf->len - buf->head[0].iov_len. */
856
                buf->head[0].iov_len -= pad;
857
        }
858
}
859
 
860
static int
861
unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
862
{
863
        u32 priv_len, maj_stat;
864
        int pad, saved_len, remaining_len, offset;
865
 
866
        rqstp->rq_splice_ok = 0;
867
 
868
        priv_len = svc_getnl(&buf->head[0]);
869
        if (rqstp->rq_deferred) {
870
                /* Already decrypted last time through! The sequence number
871
                 * check at out_seq is unnecessary but harmless: */
872
                goto out_seq;
873
        }
874
        /* buf->len is the number of bytes from the original start of the
875
         * request to the end, where head[0].iov_len is just the bytes
876
         * not yet read from the head, so these two values are different: */
877
        remaining_len = total_buf_len(buf);
878
        if (priv_len > remaining_len)
879
                return -EINVAL;
880
        pad = remaining_len - priv_len;
881
        buf->len -= pad;
882
        fix_priv_head(buf, pad);
883
 
884
        /* Maybe it would be better to give gss_unwrap a length parameter: */
885
        saved_len = buf->len;
886
        buf->len = priv_len;
887
        maj_stat = gss_unwrap(ctx, 0, buf);
888
        pad = priv_len - buf->len;
889
        buf->len = saved_len;
890
        buf->len -= pad;
891
        /* The upper layers assume the buffer is aligned on 4-byte boundaries.
892
         * In the krb5p case, at least, the data ends up offset, so we need to
893
         * move it around. */
894
        /* XXX: This is very inefficient.  It would be better to either do
895
         * this while we encrypt, or maybe in the receive code, if we can peak
896
         * ahead and work out the service and mechanism there. */
897
        offset = buf->head[0].iov_len % 4;
898
        if (offset) {
899
                buf->buflen = RPCSVC_MAXPAYLOAD;
900
                xdr_shift_buf(buf, offset);
901
                fix_priv_head(buf, pad);
902
        }
903
        if (maj_stat != GSS_S_COMPLETE)
904
                return -EINVAL;
905
out_seq:
906
        if (svc_getnl(&buf->head[0]) != seq)
907
                return -EINVAL;
908
        return 0;
909
}
910
 
911
struct gss_svc_data {
912
        /* decoded gss client cred: */
913
        struct rpc_gss_wire_cred        clcred;
914
        /* save a pointer to the beginning of the encoded verifier,
915
         * for use in encryption/checksumming in svcauth_gss_release: */
916
        __be32                          *verf_start;
917
        struct rsc                      *rsci;
918
};
919
 
920
static int
921
svcauth_gss_set_client(struct svc_rqst *rqstp)
922
{
923
        struct gss_svc_data *svcdata = rqstp->rq_auth_data;
924
        struct rsc *rsci = svcdata->rsci;
925
        struct rpc_gss_wire_cred *gc = &svcdata->clcred;
926
        int stat;
927
 
928
        /*
929
         * A gss export can be specified either by:
930
         *      export  *(sec=krb5,rw)
931
         * or by
932
         *      export gss/krb5(rw)
933
         * The latter is deprecated; but for backwards compatibility reasons
934
         * the nfsd code will still fall back on trying it if the former
935
         * doesn't work; so we try to make both available to nfsd, below.
936
         */
937
        rqstp->rq_gssclient = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
938
        if (rqstp->rq_gssclient == NULL)
939
                return SVC_DENIED;
940
        stat = svcauth_unix_set_client(rqstp);
941
        if (stat == SVC_DROP)
942
                return stat;
943
        return SVC_OK;
944
}
945
 
946
static inline int
947
gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
948
{
949
        struct rsc *rsci;
950
        int        rc;
951
 
952
        if (rsip->major_status != GSS_S_COMPLETE)
953
                return gss_write_null_verf(rqstp);
954
        rsci = gss_svc_searchbyctx(&rsip->out_handle);
955
        if (rsci == NULL) {
956
                rsip->major_status = GSS_S_NO_CONTEXT;
957
                return gss_write_null_verf(rqstp);
958
        }
959
        rc = gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN);
960
        cache_put(&rsci->h, &rsc_cache);
961
        return rc;
962
}
963
 
964
/*
965
 * Having read the cred already and found we're in the context
966
 * initiation case, read the verifier and initiate (or check the results
967
 * of) upcalls to userspace for help with context initiation.  If
968
 * the upcall results are available, write the verifier and result.
969
 * Otherwise, drop the request pending an answer to the upcall.
970
 */
971
static int svcauth_gss_handle_init(struct svc_rqst *rqstp,
972
                        struct rpc_gss_wire_cred *gc, __be32 *authp)
973
{
974
        struct kvec *argv = &rqstp->rq_arg.head[0];
975
        struct kvec *resv = &rqstp->rq_res.head[0];
976
        struct xdr_netobj tmpobj;
977
        struct rsi *rsip, rsikey;
978
 
979
        /* Read the verifier; should be NULL: */
980
        *authp = rpc_autherr_badverf;
981
        if (argv->iov_len < 2 * 4)
982
                return SVC_DENIED;
983
        if (svc_getnl(argv) != RPC_AUTH_NULL)
984
                return SVC_DENIED;
985
        if (svc_getnl(argv) != 0)
986
                return SVC_DENIED;
987
 
988
        /* Martial context handle and token for upcall: */
989
        *authp = rpc_autherr_badcred;
990
        if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
991
                return SVC_DENIED;
992
        memset(&rsikey, 0, sizeof(rsikey));
993
        if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
994
                return SVC_DROP;
995
        *authp = rpc_autherr_badverf;
996
        if (svc_safe_getnetobj(argv, &tmpobj)) {
997
                kfree(rsikey.in_handle.data);
998
                return SVC_DENIED;
999
        }
1000
        if (dup_netobj(&rsikey.in_token, &tmpobj)) {
1001
                kfree(rsikey.in_handle.data);
1002
                return SVC_DROP;
1003
        }
1004
 
1005
        /* Perform upcall, or find upcall result: */
1006
        rsip = rsi_lookup(&rsikey);
1007
        rsi_free(&rsikey);
1008
        if (!rsip)
1009
                return SVC_DROP;
1010
        switch (cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
1011
        case -EAGAIN:
1012
        case -ETIMEDOUT:
1013
        case -ENOENT:
1014
                /* No upcall result: */
1015
                return SVC_DROP;
1016
        case 0:
1017
                /* Got an answer to the upcall; use it: */
1018
                if (gss_write_init_verf(rqstp, rsip))
1019
                        return SVC_DROP;
1020
                if (resv->iov_len + 4 > PAGE_SIZE)
1021
                        return SVC_DROP;
1022
                svc_putnl(resv, RPC_SUCCESS);
1023
                if (svc_safe_putnetobj(resv, &rsip->out_handle))
1024
                        return SVC_DROP;
1025
                if (resv->iov_len + 3 * 4 > PAGE_SIZE)
1026
                        return SVC_DROP;
1027
                svc_putnl(resv, rsip->major_status);
1028
                svc_putnl(resv, rsip->minor_status);
1029
                svc_putnl(resv, GSS_SEQ_WIN);
1030
                if (svc_safe_putnetobj(resv, &rsip->out_token))
1031
                        return SVC_DROP;
1032
        }
1033
        return SVC_COMPLETE;
1034
}
1035
 
1036
/*
1037
 * Accept an rpcsec packet.
1038
 * If context establishment, punt to user space
1039
 * If data exchange, verify/decrypt
1040
 * If context destruction, handle here
1041
 * In the context establishment and destruction case we encode
1042
 * response here and return SVC_COMPLETE.
1043
 */
1044
static int
1045
svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1046
{
1047
        struct kvec     *argv = &rqstp->rq_arg.head[0];
1048
        struct kvec     *resv = &rqstp->rq_res.head[0];
1049
        u32             crlen;
1050
        struct gss_svc_data *svcdata = rqstp->rq_auth_data;
1051
        struct rpc_gss_wire_cred *gc;
1052
        struct rsc      *rsci = NULL;
1053
        __be32          *rpcstart;
1054
        __be32          *reject_stat = resv->iov_base + resv->iov_len;
1055
        int             ret;
1056
 
1057
        dprintk("RPC:       svcauth_gss: argv->iov_len = %zd\n",
1058
                        argv->iov_len);
1059
 
1060
        *authp = rpc_autherr_badcred;
1061
        if (!svcdata)
1062
                svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
1063
        if (!svcdata)
1064
                goto auth_err;
1065
        rqstp->rq_auth_data = svcdata;
1066
        svcdata->verf_start = NULL;
1067
        svcdata->rsci = NULL;
1068
        gc = &svcdata->clcred;
1069
 
1070
        /* start of rpc packet is 7 u32's back from here:
1071
         * xid direction rpcversion prog vers proc flavour
1072
         */
1073
        rpcstart = argv->iov_base;
1074
        rpcstart -= 7;
1075
 
1076
        /* credential is:
1077
         *   version(==1), proc(0,1,2,3), seq, service (1,2,3), handle
1078
         * at least 5 u32s, and is preceeded by length, so that makes 6.
1079
         */
1080
 
1081
        if (argv->iov_len < 5 * 4)
1082
                goto auth_err;
1083
        crlen = svc_getnl(argv);
1084
        if (svc_getnl(argv) != RPC_GSS_VERSION)
1085
                goto auth_err;
1086
        gc->gc_proc = svc_getnl(argv);
1087
        gc->gc_seq = svc_getnl(argv);
1088
        gc->gc_svc = svc_getnl(argv);
1089
        if (svc_safe_getnetobj(argv, &gc->gc_ctx))
1090
                goto auth_err;
1091
        if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
1092
                goto auth_err;
1093
 
1094
        if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
1095
                goto auth_err;
1096
 
1097
        *authp = rpc_autherr_badverf;
1098
        switch (gc->gc_proc) {
1099
        case RPC_GSS_PROC_INIT:
1100
        case RPC_GSS_PROC_CONTINUE_INIT:
1101
                return svcauth_gss_handle_init(rqstp, gc, authp);
1102
        case RPC_GSS_PROC_DATA:
1103
        case RPC_GSS_PROC_DESTROY:
1104
                /* Look up the context, and check the verifier: */
1105
                *authp = rpcsec_gsserr_credproblem;
1106
                rsci = gss_svc_searchbyctx(&gc->gc_ctx);
1107
                if (!rsci)
1108
                        goto auth_err;
1109
                switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {
1110
                case SVC_OK:
1111
                        break;
1112
                case SVC_DENIED:
1113
                        goto auth_err;
1114
                case SVC_DROP:
1115
                        goto drop;
1116
                }
1117
                break;
1118
        default:
1119
                *authp = rpc_autherr_rejectedcred;
1120
                goto auth_err;
1121
        }
1122
 
1123
        /* now act upon the command: */
1124
        switch (gc->gc_proc) {
1125
        case RPC_GSS_PROC_DESTROY:
1126
                if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
1127
                        goto auth_err;
1128
                set_bit(CACHE_NEGATIVE, &rsci->h.flags);
1129
                if (resv->iov_len + 4 > PAGE_SIZE)
1130
                        goto drop;
1131
                svc_putnl(resv, RPC_SUCCESS);
1132
                goto complete;
1133
        case RPC_GSS_PROC_DATA:
1134
                *authp = rpcsec_gsserr_ctxproblem;
1135
                svcdata->verf_start = resv->iov_base + resv->iov_len;
1136
                if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
1137
                        goto auth_err;
1138
                rqstp->rq_cred = rsci->cred;
1139
                get_group_info(rsci->cred.cr_group_info);
1140
                *authp = rpc_autherr_badcred;
1141
                switch (gc->gc_svc) {
1142
                case RPC_GSS_SVC_NONE:
1143
                        break;
1144
                case RPC_GSS_SVC_INTEGRITY:
1145
                        if (unwrap_integ_data(&rqstp->rq_arg,
1146
                                        gc->gc_seq, rsci->mechctx))
1147
                                goto auth_err;
1148
                        /* placeholders for length and seq. number: */
1149
                        svc_putnl(resv, 0);
1150
                        svc_putnl(resv, 0);
1151
                        break;
1152
                case RPC_GSS_SVC_PRIVACY:
1153
                        if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
1154
                                        gc->gc_seq, rsci->mechctx))
1155
                                goto auth_err;
1156
                        /* placeholders for length and seq. number: */
1157
                        svc_putnl(resv, 0);
1158
                        svc_putnl(resv, 0);
1159
                        break;
1160
                default:
1161
                        goto auth_err;
1162
                }
1163
                svcdata->rsci = rsci;
1164
                cache_get(&rsci->h);
1165
                rqstp->rq_flavor = gss_svc_to_pseudoflavor(
1166
                                        rsci->mechctx->mech_type, gc->gc_svc);
1167
                ret = SVC_OK;
1168
                goto out;
1169
        }
1170
auth_err:
1171
        /* Restore write pointer to its original value: */
1172
        xdr_ressize_check(rqstp, reject_stat);
1173
        ret = SVC_DENIED;
1174
        goto out;
1175
complete:
1176
        ret = SVC_COMPLETE;
1177
        goto out;
1178
drop:
1179
        ret = SVC_DROP;
1180
out:
1181
        if (rsci)
1182
                cache_put(&rsci->h, &rsc_cache);
1183
        return ret;
1184
}
1185
 
1186
static __be32 *
1187
svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd)
1188
{
1189
        __be32 *p;
1190
        u32 verf_len;
1191
 
1192
        p = gsd->verf_start;
1193
        gsd->verf_start = NULL;
1194
 
1195
        /* If the reply stat is nonzero, don't wrap: */
1196
        if (*(p-1) != rpc_success)
1197
                return NULL;
1198
        /* Skip the verifier: */
1199
        p += 1;
1200
        verf_len = ntohl(*p++);
1201
        p += XDR_QUADLEN(verf_len);
1202
        /* move accept_stat to right place: */
1203
        memcpy(p, p + 2, 4);
1204
        /* Also don't wrap if the accept stat is nonzero: */
1205
        if (*p != rpc_success) {
1206
                resbuf->head[0].iov_len -= 2 * 4;
1207
                return NULL;
1208
        }
1209
        p++;
1210
        return p;
1211
}
1212
 
1213
static inline int
1214
svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
1215
{
1216
        struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
1217
        struct rpc_gss_wire_cred *gc = &gsd->clcred;
1218
        struct xdr_buf *resbuf = &rqstp->rq_res;
1219
        struct xdr_buf integ_buf;
1220
        struct xdr_netobj mic;
1221
        struct kvec *resv;
1222
        __be32 *p;
1223
        int integ_offset, integ_len;
1224
        int stat = -EINVAL;
1225
 
1226
        p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
1227
        if (p == NULL)
1228
                goto out;
1229
        integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
1230
        integ_len = resbuf->len - integ_offset;
1231
        BUG_ON(integ_len % 4);
1232
        *p++ = htonl(integ_len);
1233
        *p++ = htonl(gc->gc_seq);
1234
        if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
1235
                                integ_len))
1236
                BUG();
1237
        if (resbuf->tail[0].iov_base == NULL) {
1238
                if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
1239
                        goto out_err;
1240
                resbuf->tail[0].iov_base = resbuf->head[0].iov_base
1241
                                                + resbuf->head[0].iov_len;
1242
                resbuf->tail[0].iov_len = 0;
1243
                resv = &resbuf->tail[0];
1244
        } else {
1245
                resv = &resbuf->tail[0];
1246
        }
1247
        mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
1248
        if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
1249
                goto out_err;
1250
        svc_putnl(resv, mic.len);
1251
        memset(mic.data + mic.len, 0,
1252
                        round_up_to_quad(mic.len) - mic.len);
1253
        resv->iov_len += XDR_QUADLEN(mic.len) << 2;
1254
        /* not strictly required: */
1255
        resbuf->len += XDR_QUADLEN(mic.len) << 2;
1256
        BUG_ON(resv->iov_len > PAGE_SIZE);
1257
out:
1258
        stat = 0;
1259
out_err:
1260
        return stat;
1261
}
1262
 
1263
static inline int
1264
svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
1265
{
1266
        struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
1267
        struct rpc_gss_wire_cred *gc = &gsd->clcred;
1268
        struct xdr_buf *resbuf = &rqstp->rq_res;
1269
        struct page **inpages = NULL;
1270
        __be32 *p, *len;
1271
        int offset;
1272
        int pad;
1273
 
1274
        p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
1275
        if (p == NULL)
1276
                return 0;
1277
        len = p++;
1278
        offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
1279
        *p++ = htonl(gc->gc_seq);
1280
        inpages = resbuf->pages;
1281
        /* XXX: Would be better to write some xdr helper functions for
1282
         * nfs{2,3,4}xdr.c that place the data right, instead of copying: */
1283
        if (resbuf->tail[0].iov_base) {
1284
                BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
1285
                                                        + PAGE_SIZE);
1286
                BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
1287
                if (resbuf->tail[0].iov_len + resbuf->head[0].iov_len
1288
                                + 2 * RPC_MAX_AUTH_SIZE > PAGE_SIZE)
1289
                        return -ENOMEM;
1290
                memmove(resbuf->tail[0].iov_base + RPC_MAX_AUTH_SIZE,
1291
                        resbuf->tail[0].iov_base,
1292
                        resbuf->tail[0].iov_len);
1293
                resbuf->tail[0].iov_base += RPC_MAX_AUTH_SIZE;
1294
        }
1295
        if (resbuf->tail[0].iov_base == NULL) {
1296
                if (resbuf->head[0].iov_len + 2*RPC_MAX_AUTH_SIZE > PAGE_SIZE)
1297
                        return -ENOMEM;
1298
                resbuf->tail[0].iov_base = resbuf->head[0].iov_base
1299
                        + resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
1300
                resbuf->tail[0].iov_len = 0;
1301
        }
1302
        if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
1303
                return -ENOMEM;
1304
        *len = htonl(resbuf->len - offset);
1305
        pad = 3 - ((resbuf->len - offset - 1)&3);
1306
        p = (__be32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
1307
        memset(p, 0, pad);
1308
        resbuf->tail[0].iov_len += pad;
1309
        resbuf->len += pad;
1310
        return 0;
1311
}
1312
 
1313
static int
1314
svcauth_gss_release(struct svc_rqst *rqstp)
1315
{
1316
        struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
1317
        struct rpc_gss_wire_cred *gc = &gsd->clcred;
1318
        struct xdr_buf *resbuf = &rqstp->rq_res;
1319
        int stat = -EINVAL;
1320
 
1321
        if (gc->gc_proc != RPC_GSS_PROC_DATA)
1322
                goto out;
1323
        /* Release can be called twice, but we only wrap once. */
1324
        if (gsd->verf_start == NULL)
1325
                goto out;
1326
        /* normally not set till svc_send, but we need it here: */
1327
        /* XXX: what for?  Do we mess it up the moment we call svc_putu32
1328
         * or whatever? */
1329
        resbuf->len = total_buf_len(resbuf);
1330
        switch (gc->gc_svc) {
1331
        case RPC_GSS_SVC_NONE:
1332
                break;
1333
        case RPC_GSS_SVC_INTEGRITY:
1334
                stat = svcauth_gss_wrap_resp_integ(rqstp);
1335
                if (stat)
1336
                        goto out_err;
1337
                break;
1338
        case RPC_GSS_SVC_PRIVACY:
1339
                stat = svcauth_gss_wrap_resp_priv(rqstp);
1340
                if (stat)
1341
                        goto out_err;
1342
                break;
1343
        default:
1344
                goto out_err;
1345
        }
1346
 
1347
out:
1348
        stat = 0;
1349
out_err:
1350
        if (rqstp->rq_client)
1351
                auth_domain_put(rqstp->rq_client);
1352
        rqstp->rq_client = NULL;
1353
        if (rqstp->rq_gssclient)
1354
                auth_domain_put(rqstp->rq_gssclient);
1355
        rqstp->rq_gssclient = NULL;
1356
        if (rqstp->rq_cred.cr_group_info)
1357
                put_group_info(rqstp->rq_cred.cr_group_info);
1358
        rqstp->rq_cred.cr_group_info = NULL;
1359
        if (gsd->rsci)
1360
                cache_put(&gsd->rsci->h, &rsc_cache);
1361
        gsd->rsci = NULL;
1362
 
1363
        return stat;
1364
}
1365
 
1366
static void
1367
svcauth_gss_domain_release(struct auth_domain *dom)
1368
{
1369
        struct gss_domain *gd = container_of(dom, struct gss_domain, h);
1370
 
1371
        kfree(dom->name);
1372
        kfree(gd);
1373
}
1374
 
1375
static struct auth_ops svcauthops_gss = {
1376
        .name           = "rpcsec_gss",
1377
        .owner          = THIS_MODULE,
1378
        .flavour        = RPC_AUTH_GSS,
1379
        .accept         = svcauth_gss_accept,
1380
        .release        = svcauth_gss_release,
1381
        .domain_release = svcauth_gss_domain_release,
1382
        .set_client     = svcauth_gss_set_client,
1383
};
1384
 
1385
int
1386
gss_svc_init(void)
1387
{
1388
        int rv = svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
1389
        if (rv == 0) {
1390
                cache_register(&rsc_cache);
1391
                cache_register(&rsi_cache);
1392
        }
1393
        return rv;
1394
}
1395
 
1396
void
1397
gss_svc_shutdown(void)
1398
{
1399
        if (cache_unregister(&rsc_cache))
1400
                printk(KERN_ERR "auth_rpcgss: failed to unregister rsc cache\n");
1401
        if (cache_unregister(&rsi_cache))
1402
                printk(KERN_ERR "auth_rpcgss: failed to unregister rsi cache\n");
1403
        svc_auth_unregister(RPC_AUTH_GSS);
1404
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.