Whamcloud - gitweb
45e0b0bf68dad7d13a32e9cf8d17501f244d97d8
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_pipefs.c
1 /*
2  * Modifications for Lustre
3  *
4  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
5  *
6  * Copyright (c) 2012, Intel Corporation.
7  *
8  * Author: Eric Mei <ericm@clusterfs.com>
9  */
10
11 /*
12  * linux/net/sunrpc/auth_gss.c
13  *
14  * RPCSEC_GSS client authentication.
15  *
16  *  Copyright (c) 2000 The Regents of the University of Michigan.
17  *  All rights reserved.
18  *
19  *  Dug Song       <dugsong@monkey.org>
20  *  Andy Adamson   <andros@umich.edu>
21  *
22  *  Redistribution and use in source and binary forms, with or without
23  *  modification, are permitted provided that the following conditions
24  *  are met:
25  *
26  *  1. Redistributions of source code must retain the above copyright
27  *     notice, this list of conditions and the following disclaimer.
28  *  2. Redistributions in binary form must reproduce the above copyright
29  *     notice, this list of conditions and the following disclaimer in the
30  *     documentation and/or other materials provided with the distribution.
31  *  3. Neither the name of the University nor the names of its
32  *     contributors may be used to endorse or promote products derived
33  *     from this software without specific prior written permission.
34  *
35  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
36  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
43  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
44  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46  *
47  */
48
49 #define DEBUG_SUBSYSTEM S_SEC
50 #ifdef __KERNEL__
51 #include <linux/init.h>
52 #include <linux/module.h>
53 #include <linux/slab.h>
54 #include <linux/dcache.h>
55 #include <linux/fs.h>
56 #include <linux/mutex.h>
57 #include <linux/crypto.h>
58 #include <asm/atomic.h>
59 struct rpc_clnt; /* for rpc_pipefs */
60 #include <linux/sunrpc/rpc_pipe_fs.h>
61 #else
62 #include <liblustre.h>
63 #endif
64
65 #include <obd.h>
66 #include <obd_class.h>
67 #include <obd_support.h>
68 #include <lustre/lustre_idl.h>
69 #include <lustre_sec.h>
70 #include <lustre_net.h>
71 #include <lustre_import.h>
72
73 #include "gss_err.h"
74 #include "gss_internal.h"
75 #include "gss_api.h"
76
77 static struct ptlrpc_sec_policy gss_policy_pipefs;
78 static struct ptlrpc_ctx_ops gss_pipefs_ctxops;
79
80 static int gss_cli_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx);
81
82 static int gss_sec_pipe_upcall_init(struct gss_sec *gsec)
83 {
84         return 0;
85 }
86
87 static void gss_sec_pipe_upcall_fini(struct gss_sec *gsec)
88 {
89 }
90
91 /****************************************
92  * internel context helpers             *
93  ****************************************/
94
95 static
96 struct ptlrpc_cli_ctx *ctx_create_pf(struct ptlrpc_sec *sec,
97                                      struct vfs_cred *vcred)
98 {
99         struct gss_cli_ctx *gctx;
100         int                 rc;
101
102         OBD_ALLOC_PTR(gctx);
103         if (gctx == NULL)
104                 return NULL;
105
106         rc = gss_cli_ctx_init_common(sec, &gctx->gc_base,
107                                      &gss_pipefs_ctxops, vcred);
108         if (rc) {
109                 OBD_FREE_PTR(gctx);
110                 return NULL;
111         }
112
113         return &gctx->gc_base;
114 }
115
116 static
117 void ctx_destroy_pf(struct ptlrpc_sec *sec, struct ptlrpc_cli_ctx *ctx)
118 {
119         struct gss_cli_ctx *gctx = ctx2gctx(ctx);
120
121         if (gss_cli_ctx_fini_common(sec, ctx))
122                 return;
123
124         OBD_FREE_PTR(gctx);
125
126         atomic_dec(&sec->ps_nctx);
127         sptlrpc_sec_put(sec);
128 }
129
130 static
131 void ctx_enhash_pf(struct ptlrpc_cli_ctx *ctx, cfs_hlist_head_t *hash)
132 {
133         set_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags);
134         atomic_inc(&ctx->cc_refcount);
135         cfs_hlist_add_head(&ctx->cc_cache, hash);
136 }
137
138 /*
139  * caller must hold spinlock
140  */
141 static
142 void ctx_unhash_pf(struct ptlrpc_cli_ctx *ctx, cfs_hlist_head_t *freelist)
143 {
144         assert_spin_locked(&ctx->cc_sec->ps_lock);
145         LASSERT(atomic_read(&ctx->cc_refcount) > 0);
146         LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags));
147         LASSERT(!cfs_hlist_unhashed(&ctx->cc_cache));
148
149         clear_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags);
150
151         if (atomic_dec_and_test(&ctx->cc_refcount)) {
152                 __cfs_hlist_del(&ctx->cc_cache);
153                 cfs_hlist_add_head(&ctx->cc_cache, freelist);
154         } else {
155                 cfs_hlist_del_init(&ctx->cc_cache);
156         }
157 }
158
159 /*
160  * return 1 if the context is dead.
161  */
162 static
163 int ctx_check_death_pf(struct ptlrpc_cli_ctx *ctx,
164                        cfs_hlist_head_t *freelist)
165 {
166         if (cli_ctx_check_death(ctx)) {
167                 if (freelist)
168                         ctx_unhash_pf(ctx, freelist);
169                 return 1;
170         }
171
172         return 0;
173 }
174
175 static inline
176 int ctx_check_death_locked_pf(struct ptlrpc_cli_ctx *ctx,
177                               cfs_hlist_head_t *freelist)
178 {
179         LASSERT(ctx->cc_sec);
180         LASSERT(atomic_read(&ctx->cc_refcount) > 0);
181         LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags));
182
183         return ctx_check_death_pf(ctx, freelist);
184 }
185
186 static inline
187 int ctx_match_pf(struct ptlrpc_cli_ctx *ctx, struct vfs_cred *vcred)
188 {
189         /* a little bit optimization for null policy */
190         if (!ctx->cc_ops->match)
191                 return 1;
192
193         return ctx->cc_ops->match(ctx, vcred);
194 }
195
196 static
197 void ctx_list_destroy_pf(cfs_hlist_head_t *head)
198 {
199         struct ptlrpc_cli_ctx *ctx;
200
201         while (!cfs_hlist_empty(head)) {
202                 ctx = cfs_hlist_entry(head->first, struct ptlrpc_cli_ctx,
203                                       cc_cache);
204
205                 LASSERT(atomic_read(&ctx->cc_refcount) == 0);
206                 LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT,
207                                  &ctx->cc_flags) == 0);
208
209                 cfs_hlist_del_init(&ctx->cc_cache);
210                 ctx_destroy_pf(ctx->cc_sec, ctx);
211         }
212 }
213
214 /****************************************
215  * context apis                         *
216  ****************************************/
217
218 static
219 int gss_cli_ctx_validate_pf(struct ptlrpc_cli_ctx *ctx)
220 {
221         if (ctx_check_death_pf(ctx, NULL))
222                 return 1;
223         if (cli_ctx_is_ready(ctx))
224                 return 0;
225         return 1;
226 }
227
228 static
229 void gss_cli_ctx_die_pf(struct ptlrpc_cli_ctx *ctx, int grace)
230 {
231         LASSERT(ctx->cc_sec);
232         LASSERT(atomic_read(&ctx->cc_refcount) > 0);
233
234         cli_ctx_expire(ctx);
235
236         spin_lock(&ctx->cc_sec->ps_lock);
237
238         if (test_and_clear_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags)) {
239                 LASSERT(!cfs_hlist_unhashed(&ctx->cc_cache));
240                 LASSERT(atomic_read(&ctx->cc_refcount) > 1);
241
242                 cfs_hlist_del_init(&ctx->cc_cache);
243                 if (atomic_dec_and_test(&ctx->cc_refcount))
244                         LBUG();
245         }
246
247         spin_unlock(&ctx->cc_sec->ps_lock);
248 }
249
250 /****************************************
251  * reverse context installation         *
252  ****************************************/
253
254 static inline
255 unsigned int ctx_hash_index(int hashsize, __u64 key)
256 {
257         return (unsigned int) (key & ((__u64) hashsize - 1));
258 }
259
260 static
261 void gss_sec_ctx_replace_pf(struct gss_sec *gsec,
262                             struct ptlrpc_cli_ctx *new)
263 {
264         struct hlist_node __maybe_unused *pos, *next;
265         struct gss_sec_pipefs *gsec_pf;
266         struct ptlrpc_cli_ctx *ctx;
267         HLIST_HEAD(freelist);
268         unsigned int hash;
269         ENTRY;
270
271         gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base);
272
273         hash = ctx_hash_index(gsec_pf->gsp_chash_size,
274                               (__u64) new->cc_vcred.vc_uid);
275         LASSERT(hash < gsec_pf->gsp_chash_size);
276
277         spin_lock(&gsec->gs_base.ps_lock);
278
279         cfs_hlist_for_each_entry_safe(ctx, pos, next,
280                                       &gsec_pf->gsp_chash[hash], cc_cache) {
281                 if (!ctx_match_pf(ctx, &new->cc_vcred))
282                         continue;
283
284                 cli_ctx_expire(ctx);
285                 ctx_unhash_pf(ctx, &freelist);
286                 break;
287         }
288
289         ctx_enhash_pf(new, &gsec_pf->gsp_chash[hash]);
290
291         spin_unlock(&gsec->gs_base.ps_lock);
292
293         ctx_list_destroy_pf(&freelist);
294         EXIT;
295 }
296
297 static
298 int gss_install_rvs_cli_ctx_pf(struct gss_sec *gsec,
299                                struct ptlrpc_svc_ctx *svc_ctx)
300 {
301         struct vfs_cred          vcred;
302         struct ptlrpc_cli_ctx   *cli_ctx;
303         int                      rc;
304         ENTRY;
305
306         vcred.vc_uid = 0;
307         vcred.vc_gid = 0;
308
309         cli_ctx = ctx_create_pf(&gsec->gs_base, &vcred);
310         if (!cli_ctx)
311                 RETURN(-ENOMEM);
312
313         rc = gss_copy_rvc_cli_ctx(cli_ctx, svc_ctx);
314         if (rc) {
315                 ctx_destroy_pf(cli_ctx->cc_sec, cli_ctx);
316                 RETURN(rc);
317         }
318
319         gss_sec_ctx_replace_pf(gsec, cli_ctx);
320         RETURN(0);
321 }
322
323 static
324 void gss_ctx_cache_gc_pf(struct gss_sec_pipefs *gsec_pf,
325                          cfs_hlist_head_t *freelist)
326 {
327         struct ptlrpc_sec       *sec;
328         struct ptlrpc_cli_ctx   *ctx;
329         struct hlist_node       __maybe_unused *pos;
330         struct hlist_node       *next;
331         int i;
332         ENTRY;
333
334         sec = &gsec_pf->gsp_base.gs_base;
335
336         CDEBUG(D_SEC, "do gc on sec %s@%p\n", sec->ps_policy->sp_name, sec);
337
338         for (i = 0; i < gsec_pf->gsp_chash_size; i++) {
339                 cfs_hlist_for_each_entry_safe(ctx, pos, next,
340                                               &gsec_pf->gsp_chash[i], cc_cache)
341                         ctx_check_death_locked_pf(ctx, freelist);
342         }
343
344         sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval;
345         EXIT;
346 }
347
348 static
349 struct ptlrpc_sec* gss_sec_create_pf(struct obd_import *imp,
350                                      struct ptlrpc_svc_ctx *ctx,
351                                      struct sptlrpc_flavor *sf)
352 {
353         struct gss_sec_pipefs   *gsec_pf;
354         int                      alloc_size, hash_size, i;
355         ENTRY;
356
357 #define GSS_SEC_PIPEFS_CTX_HASH_SIZE    (32)
358
359         if (ctx ||
360             sf->sf_flags & (PTLRPC_SEC_FL_ROOTONLY | PTLRPC_SEC_FL_REVERSE))
361                 hash_size = 1;
362         else
363                 hash_size = GSS_SEC_PIPEFS_CTX_HASH_SIZE;
364
365         alloc_size = sizeof(*gsec_pf) +
366                      sizeof(cfs_hlist_head_t) * hash_size;
367
368         OBD_ALLOC(gsec_pf, alloc_size);
369         if (!gsec_pf)
370                 RETURN(NULL);
371
372         gsec_pf->gsp_chash_size = hash_size;
373         for (i = 0; i < hash_size; i++)
374                 CFS_INIT_HLIST_HEAD(&gsec_pf->gsp_chash[i]);
375
376         if (gss_sec_create_common(&gsec_pf->gsp_base, &gss_policy_pipefs,
377                                   imp, ctx, sf))
378                 goto err_free;
379
380         if (ctx == NULL) {
381                 if (gss_sec_pipe_upcall_init(&gsec_pf->gsp_base))
382                         goto err_destroy;
383         } else {
384                 if (gss_install_rvs_cli_ctx_pf(&gsec_pf->gsp_base, ctx))
385                         goto err_destroy;
386         }
387
388         RETURN(&gsec_pf->gsp_base.gs_base);
389
390 err_destroy:
391         gss_sec_destroy_common(&gsec_pf->gsp_base);
392 err_free:
393         OBD_FREE(gsec_pf, alloc_size);
394         RETURN(NULL);
395 }
396
397 static
398 void gss_sec_destroy_pf(struct ptlrpc_sec *sec)
399 {
400         struct gss_sec_pipefs   *gsec_pf;
401         struct gss_sec          *gsec;
402
403         CWARN("destroy %s@%p\n", sec->ps_policy->sp_name, sec);
404
405         gsec = container_of(sec, struct gss_sec, gs_base);
406         gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base);
407
408         LASSERT(gsec_pf->gsp_chash);
409         LASSERT(gsec_pf->gsp_chash_size);
410
411         gss_sec_pipe_upcall_fini(gsec);
412
413         gss_sec_destroy_common(gsec);
414
415         OBD_FREE(gsec, sizeof(*gsec_pf) +
416                        sizeof(cfs_hlist_head_t) * gsec_pf->gsp_chash_size);
417 }
418
419 static
420 struct ptlrpc_cli_ctx * gss_sec_lookup_ctx_pf(struct ptlrpc_sec *sec,
421                                               struct vfs_cred *vcred,
422                                               int create, int remove_dead)
423 {
424         struct gss_sec          *gsec;
425         struct gss_sec_pipefs   *gsec_pf;
426         struct ptlrpc_cli_ctx   *ctx = NULL, *new = NULL;
427         struct hlist_head       *hash_head;
428         struct hlist_node       __maybe_unused *pos, *next;
429         unsigned int            hash, gc = 0, found = 0;
430         HLIST_HEAD(freelist);
431         ENTRY;
432
433         might_sleep();
434
435         gsec = container_of(sec, struct gss_sec, gs_base);
436         gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base);
437
438         hash = ctx_hash_index(gsec_pf->gsp_chash_size,
439                               (__u64) vcred->vc_uid);
440         hash_head = &gsec_pf->gsp_chash[hash];
441         LASSERT(hash < gsec_pf->gsp_chash_size);
442
443 retry:
444         spin_lock(&sec->ps_lock);
445
446         /* gc_next == 0 means never do gc */
447         if (remove_dead && sec->ps_gc_next &&
448             cfs_time_after(cfs_time_current_sec(), sec->ps_gc_next)) {
449                 gss_ctx_cache_gc_pf(gsec_pf, &freelist);
450                 gc = 1;
451         }
452
453         cfs_hlist_for_each_entry_safe(ctx, pos, next, hash_head, cc_cache) {
454                 if (gc == 0 &&
455                     ctx_check_death_locked_pf(ctx,
456                                               remove_dead ? &freelist : NULL))
457                         continue;
458
459                 if (ctx_match_pf(ctx, vcred)) {
460                         found = 1;
461                         break;
462                 }
463         }
464
465         if (found) {
466                 if (new && new != ctx) {
467                         /* lost the race, just free it */
468                         cfs_hlist_add_head(&new->cc_cache, &freelist);
469                         new = NULL;
470                 }
471
472                 /* hot node, move to head */
473                 if (hash_head->first != &ctx->cc_cache) {
474                         __cfs_hlist_del(&ctx->cc_cache);
475                         cfs_hlist_add_head(&ctx->cc_cache, hash_head);
476                 }
477         } else {
478                 /* don't allocate for reverse sec */
479                 if (sec_is_reverse(sec)) {
480                         spin_unlock(&sec->ps_lock);
481                         RETURN(NULL);
482                 }
483
484                 if (new) {
485                         ctx_enhash_pf(new, hash_head);
486                         ctx = new;
487                 } else if (create) {
488                         spin_unlock(&sec->ps_lock);
489                         new = ctx_create_pf(sec, vcred);
490                         if (new) {
491                                 clear_bit(PTLRPC_CTX_NEW_BIT, &new->cc_flags);
492                                 goto retry;
493                         }
494                 } else {
495                         ctx = NULL;
496                 }
497         }
498
499         /* hold a ref */
500         if (ctx)
501                 atomic_inc(&ctx->cc_refcount);
502
503         spin_unlock(&sec->ps_lock);
504
505         /* the allocator of the context must give the first push to refresh */
506         if (new) {
507                 LASSERT(new == ctx);
508                 gss_cli_ctx_refresh_pf(new);
509         }
510
511         ctx_list_destroy_pf(&freelist);
512         RETURN(ctx);
513 }
514
515 static
516 void gss_sec_release_ctx_pf(struct ptlrpc_sec *sec,
517                             struct ptlrpc_cli_ctx *ctx,
518                             int sync)
519 {
520         LASSERT(test_bit(PTLRPC_CTX_CACHED_BIT, &ctx->cc_flags) == 0);
521         LASSERT(cfs_hlist_unhashed(&ctx->cc_cache));
522
523         /* if required async, we must clear the UPTODATE bit to prevent extra
524          * rpcs during destroy procedure. */
525         if (!sync)
526                 clear_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags);
527
528         /* destroy this context */
529         ctx_destroy_pf(sec, ctx);
530 }
531
532 /*
533  * @uid: which user. "-1" means flush all.
534  * @grace: mark context DEAD, allow graceful destroy like notify
535  *         server side, etc.
536  * @force: also flush busy entries.
537  *
538  * return the number of busy context encountered.
539  *
540  * In any cases, never touch "eternal" contexts.
541  */
542 static
543 int gss_sec_flush_ctx_cache_pf(struct ptlrpc_sec *sec,
544                                uid_t uid,
545                                int grace, int force)
546 {
547         struct gss_sec          *gsec;
548         struct gss_sec_pipefs   *gsec_pf;
549         struct ptlrpc_cli_ctx   *ctx;
550         struct hlist_node       __maybe_unused *pos, *next;
551         HLIST_HEAD(freelist);
552         int i, busy = 0;
553         ENTRY;
554
555         might_sleep_if(grace);
556
557         gsec = container_of(sec, struct gss_sec, gs_base);
558         gsec_pf = container_of(gsec, struct gss_sec_pipefs, gsp_base);
559
560         spin_lock(&sec->ps_lock);
561         for (i = 0; i < gsec_pf->gsp_chash_size; i++) {
562                 cfs_hlist_for_each_entry_safe(ctx, pos, next,
563                                               &gsec_pf->gsp_chash[i],
564                                               cc_cache) {
565                         LASSERT(atomic_read(&ctx->cc_refcount) > 0);
566
567                         if (uid != -1 && uid != ctx->cc_vcred.vc_uid)
568                                 continue;
569
570                         if (atomic_read(&ctx->cc_refcount) > 1) {
571                                 busy++;
572                                 if (!force)
573                                         continue;
574
575                                 CWARN("flush busy(%d) ctx %p(%u->%s) by force, "
576                                       "grace %d\n",
577                                       atomic_read(&ctx->cc_refcount),
578                                       ctx, ctx->cc_vcred.vc_uid,
579                                       sec2target_str(ctx->cc_sec), grace);
580                         }
581                         ctx_unhash_pf(ctx, &freelist);
582
583                         set_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags);
584                         if (!grace)
585                                 clear_bit(PTLRPC_CTX_UPTODATE_BIT,
586                                           &ctx->cc_flags);
587                 }
588         }
589         spin_unlock(&sec->ps_lock);
590
591         ctx_list_destroy_pf(&freelist);
592         RETURN(busy);
593 }
594
595 /****************************************
596  * service apis                         *
597  ****************************************/
598
599 static
600 int gss_svc_accept_pf(struct ptlrpc_request *req)
601 {
602         return gss_svc_accept(&gss_policy_pipefs, req);
603 }
604
605 static
606 int gss_svc_install_rctx_pf(struct obd_import *imp,
607                             struct ptlrpc_svc_ctx *ctx)
608 {
609         struct ptlrpc_sec *sec;
610         int                rc;
611
612         sec = sptlrpc_import_sec_ref(imp);
613         LASSERT(sec);
614         rc = gss_install_rvs_cli_ctx_pf(sec2gsec(sec), ctx);
615
616         sptlrpc_sec_put(sec);
617         return rc;
618 }
619
620 /****************************************
621  * rpc_pipefs definitions               *
622  ****************************************/
623
624 #define LUSTRE_PIPE_ROOT        "/lustre"
625 #define LUSTRE_PIPE_KRB5        LUSTRE_PIPE_ROOT"/krb5"
626
627 struct gss_upcall_msg_data {
628         __u32                           gum_seq;
629         __u32                           gum_uid;
630         __u32                           gum_gid;
631         __u32                           gum_svc;        /* MDS/OSS... */
632         __u64                           gum_nid;        /* peer NID */
633         __u8                            gum_obd[64];    /* client obd name */
634 };
635
636 struct gss_upcall_msg {
637         struct rpc_pipe_msg             gum_base;
638         atomic_t                        gum_refcount;
639         cfs_list_t                      gum_list;
640         __u32                           gum_mechidx;
641         struct gss_sec                  *gum_gsec;
642         struct gss_cli_ctx              *gum_gctx;
643         struct gss_upcall_msg_data      gum_data;
644 };
645
646 static atomic_t upcall_seq = ATOMIC_INIT(0);
647
648 static inline
649 __u32 upcall_get_sequence(void)
650 {
651         return (__u32) atomic_inc_return(&upcall_seq);
652 }
653
654 enum mech_idx_t {
655         MECH_KRB5   = 0,
656         MECH_MAX
657 };
658
659 static inline
660 __u32 mech_name2idx(const char *name)
661 {
662         LASSERT(!strcmp(name, "krb5"));
663         return MECH_KRB5;
664 }
665
666 /* pipefs dentries for each mechanisms */
667 static struct dentry *de_pipes[MECH_MAX] = { NULL, };
668 /* all upcall messgaes linked here */
669 static cfs_list_t upcall_lists[MECH_MAX];
670 /* and protected by this */
671 static spinlock_t upcall_locks[MECH_MAX];
672
673 static inline
674 void upcall_list_lock(int idx)
675 {
676         spin_lock(&upcall_locks[idx]);
677 }
678
679 static inline
680 void upcall_list_unlock(int idx)
681 {
682         spin_unlock(&upcall_locks[idx]);
683 }
684
685 static
686 void upcall_msg_enlist(struct gss_upcall_msg *msg)
687 {
688         __u32 idx = msg->gum_mechidx;
689
690         upcall_list_lock(idx);
691         cfs_list_add(&msg->gum_list, &upcall_lists[idx]);
692         upcall_list_unlock(idx);
693 }
694
695 static
696 void upcall_msg_delist(struct gss_upcall_msg *msg)
697 {
698         __u32 idx = msg->gum_mechidx;
699
700         upcall_list_lock(idx);
701         cfs_list_del_init(&msg->gum_list);
702         upcall_list_unlock(idx);
703 }
704
705 /****************************************
706  * rpc_pipefs upcall helpers            *
707  ****************************************/
708
709 static
710 void gss_release_msg(struct gss_upcall_msg *gmsg)
711 {
712         ENTRY;
713         LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
714
715         if (!atomic_dec_and_test(&gmsg->gum_refcount)) {
716                 EXIT;
717                 return;
718         }
719
720         if (gmsg->gum_gctx) {
721                 sptlrpc_cli_ctx_wakeup(&gmsg->gum_gctx->gc_base);
722                 sptlrpc_cli_ctx_put(&gmsg->gum_gctx->gc_base, 1);
723                 gmsg->gum_gctx = NULL;
724         }
725
726         LASSERT(cfs_list_empty(&gmsg->gum_list));
727         LASSERT(cfs_list_empty(&gmsg->gum_base.list));
728         OBD_FREE_PTR(gmsg);
729         EXIT;
730 }
731
732 static
733 void gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg)
734 {
735         __u32 idx = gmsg->gum_mechidx;
736
737         LASSERT(idx < MECH_MAX);
738         assert_spin_locked(&upcall_locks[idx]);
739
740         if (cfs_list_empty(&gmsg->gum_list))
741                 return;
742
743         cfs_list_del_init(&gmsg->gum_list);
744         LASSERT(atomic_read(&gmsg->gum_refcount) > 1);
745         atomic_dec(&gmsg->gum_refcount);
746 }
747
748 static
749 void gss_unhash_msg(struct gss_upcall_msg *gmsg)
750 {
751         __u32 idx = gmsg->gum_mechidx;
752
753         LASSERT(idx < MECH_MAX);
754         upcall_list_lock(idx);
755         gss_unhash_msg_nolock(gmsg);
756         upcall_list_unlock(idx);
757 }
758
759 static
760 void gss_msg_fail_ctx(struct gss_upcall_msg *gmsg)
761 {
762         if (gmsg->gum_gctx) {
763                 struct ptlrpc_cli_ctx *ctx = &gmsg->gum_gctx->gc_base;
764
765                 LASSERT(atomic_read(&ctx->cc_refcount) > 0);
766                 sptlrpc_cli_ctx_expire(ctx);
767                 set_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags);
768         }
769 }
770
771 static
772 struct gss_upcall_msg * gss_find_upcall(__u32 mechidx, __u32 seq)
773 {
774         struct gss_upcall_msg *gmsg;
775
776         upcall_list_lock(mechidx);
777         cfs_list_for_each_entry(gmsg, &upcall_lists[mechidx], gum_list) {
778                 if (gmsg->gum_data.gum_seq != seq)
779                         continue;
780
781                 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
782                 LASSERT(gmsg->gum_mechidx == mechidx);
783
784                 atomic_inc(&gmsg->gum_refcount);
785                 upcall_list_unlock(mechidx);
786                 return gmsg;
787         }
788         upcall_list_unlock(mechidx);
789         return NULL;
790 }
791
792 static
793 int simple_get_bytes(char **buf, __u32 *buflen, void *res, __u32 reslen)
794 {
795         if (*buflen < reslen) {
796                 CERROR("buflen %u < %u\n", *buflen, reslen);
797                 return -EINVAL;
798         }
799
800         memcpy(res, *buf, reslen);
801         *buf += reslen;
802         *buflen -= reslen;
803         return 0;
804 }
805
806 /****************************************
807  * rpc_pipefs apis                      *
808  ****************************************/
809
810 static
811 ssize_t gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
812                         char *dst, size_t buflen)
813 {
814         char *data = (char *)msg->data + msg->copied;
815         ssize_t mlen = msg->len;
816         ssize_t left;
817         ENTRY;
818
819         if (mlen > buflen)
820                 mlen = buflen;
821         left = copy_to_user(dst, data, mlen);
822         if (left < 0) {
823                 msg->errno = left;
824                 RETURN(left);
825         }
826         mlen -= left;
827         msg->copied += mlen;
828         msg->errno = 0;
829         RETURN(mlen);
830 }
831
832 static
833 ssize_t gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
834 {
835         struct rpc_inode        *rpci = RPC_I(filp->f_dentry->d_inode);
836         struct gss_upcall_msg   *gss_msg;
837         struct ptlrpc_cli_ctx   *ctx;
838         struct gss_cli_ctx      *gctx = NULL;
839         char                    *buf, *data;
840         int                      datalen;
841         int                      timeout, rc;
842         __u32                    mechidx, seq, gss_err;
843         ENTRY;
844
845         mechidx = (__u32) (long) rpci->private;
846         LASSERT(mechidx < MECH_MAX);
847
848         OBD_ALLOC(buf, mlen);
849         if (!buf)
850                 RETURN(-ENOMEM);
851
852         if (copy_from_user(buf, src, mlen)) {
853                 CERROR("failed copy user space data\n");
854                 GOTO(out_free, rc = -EFAULT);
855         }
856         data = buf;
857         datalen = mlen;
858
859         /* data passed down format:
860          *  - seq
861          *  - timeout
862          *  - gc_win / error
863          *  - wire_ctx (rawobj)
864          *  - mech_ctx (rawobj)
865          */
866         if (simple_get_bytes(&data, &datalen, &seq, sizeof(seq))) {
867                 CERROR("fail to get seq\n");
868                 GOTO(out_free, rc = -EFAULT);
869         }
870
871         gss_msg = gss_find_upcall(mechidx, seq);
872         if (!gss_msg) {
873                 CERROR("upcall %u has aborted earlier\n", seq);
874                 GOTO(out_free, rc = -EINVAL);
875         }
876
877         gss_unhash_msg(gss_msg);
878         gctx = gss_msg->gum_gctx;
879         LASSERT(gctx);
880         LASSERT(atomic_read(&gctx->gc_base.cc_refcount) > 0);
881
882         /* timeout is not in use for now */
883         if (simple_get_bytes(&data, &datalen, &timeout, sizeof(timeout)))
884                 GOTO(out_msg, rc = -EFAULT);
885
886         /* lgssd signal an error by gc_win == 0 */
887         if (simple_get_bytes(&data, &datalen, &gctx->gc_win,
888                              sizeof(gctx->gc_win)))
889                 GOTO(out_msg, rc = -EFAULT);
890
891         if (gctx->gc_win == 0) {
892                 /* followed by:
893                  * - rpc error
894                  * - gss error
895                  */
896                 if (simple_get_bytes(&data, &datalen, &rc, sizeof(rc)))
897                         GOTO(out_msg, rc = -EFAULT);
898                 if (simple_get_bytes(&data, &datalen, &gss_err,sizeof(gss_err)))
899                         GOTO(out_msg, rc = -EFAULT);
900
901                 if (rc == 0 && gss_err == GSS_S_COMPLETE) {
902                         CWARN("both rpc & gss error code not set\n");
903                         rc = -EPERM;
904                 }
905         } else {
906                 rawobj_t tmpobj;
907
908                 /* handle */
909                 if (rawobj_extract_local(&tmpobj, (__u32 **) &data, &datalen))
910                         GOTO(out_msg, rc = -EFAULT);
911                 if (rawobj_dup(&gctx->gc_handle, &tmpobj))
912                         GOTO(out_msg, rc = -ENOMEM);
913
914                 /* mechctx */
915                 if (rawobj_extract_local(&tmpobj, (__u32 **) &data, &datalen))
916                         GOTO(out_msg, rc = -EFAULT);
917                 gss_err = lgss_import_sec_context(&tmpobj,
918                                                   gss_msg->gum_gsec->gs_mech,
919                                                   &gctx->gc_mechctx);
920                 rc = 0;
921         }
922
923         if (likely(rc == 0 && gss_err == GSS_S_COMPLETE)) {
924                 gss_cli_ctx_uptodate(gctx);
925         } else {
926                 ctx = &gctx->gc_base;
927                 sptlrpc_cli_ctx_expire(ctx);
928                 if (rc != -ERESTART || gss_err != GSS_S_COMPLETE)
929                         set_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags);
930
931                 CERROR("refresh ctx %p(uid %d) failed: %d/0x%08x: %s\n",
932                        ctx, ctx->cc_vcred.vc_uid, rc, gss_err,
933                        test_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags) ?
934                        "fatal error" : "non-fatal");
935         }
936
937         rc = mlen;
938
939 out_msg:
940         gss_release_msg(gss_msg);
941
942 out_free:
943         OBD_FREE(buf, mlen);
944         /* FIXME
945          * hack pipefs: always return asked length unless all following
946          * downcalls might be messed up. */
947         rc = mlen;
948         RETURN(rc);
949 }
950
951 static
952 void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
953 {
954         struct gss_upcall_msg          *gmsg;
955         struct gss_upcall_msg_data     *gumd;
956         static cfs_time_t               ratelimit = 0;
957         ENTRY;
958
959         LASSERT(cfs_list_empty(&msg->list));
960
961         /* normally errno is >= 0 */
962         if (msg->errno >= 0) {
963                 EXIT;
964                 return;
965         }
966
967         gmsg = container_of(msg, struct gss_upcall_msg, gum_base);
968         gumd = &gmsg->gum_data;
969         LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
970
971         CERROR("failed msg %p (seq %u, uid %u, svc %u, nid "LPX64", obd %.*s): "
972                "errno %d\n", msg, gumd->gum_seq, gumd->gum_uid, gumd->gum_svc,
973                gumd->gum_nid, (int) sizeof(gumd->gum_obd),
974                gumd->gum_obd, msg->errno);
975
976         atomic_inc(&gmsg->gum_refcount);
977         gss_unhash_msg(gmsg);
978         if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
979                 cfs_time_t now = cfs_time_current_sec();
980
981                 if (cfs_time_after(now, ratelimit)) {
982                         CWARN("upcall timed out, is lgssd running?\n");
983                         ratelimit = now + 15;
984                 }
985         }
986         gss_msg_fail_ctx(gmsg);
987         gss_release_msg(gmsg);
988         EXIT;
989 }
990
991 static
992 void gss_pipe_release(struct inode *inode)
993 {
994         struct rpc_inode *rpci = RPC_I(inode);
995         __u32             idx;
996         ENTRY;
997
998         idx = (__u32) (long) rpci->private;
999         LASSERT(idx < MECH_MAX);
1000
1001         upcall_list_lock(idx);
1002         while (!cfs_list_empty(&upcall_lists[idx])) {
1003                 struct gss_upcall_msg      *gmsg;
1004                 struct gss_upcall_msg_data *gumd;
1005
1006                 gmsg = cfs_list_entry(upcall_lists[idx].next,
1007                                       struct gss_upcall_msg, gum_list);
1008                 gumd = &gmsg->gum_data;
1009                 LASSERT(cfs_list_empty(&gmsg->gum_base.list));
1010
1011                 CERROR("failing remaining msg %p:seq %u, uid %u, svc %u, "
1012                        "nid "LPX64", obd %.*s\n", gmsg,
1013                        gumd->gum_seq, gumd->gum_uid, gumd->gum_svc,
1014                        gumd->gum_nid, (int) sizeof(gumd->gum_obd),
1015                        gumd->gum_obd);
1016
1017                 gmsg->gum_base.errno = -EPIPE;
1018                 atomic_inc(&gmsg->gum_refcount);
1019                 gss_unhash_msg_nolock(gmsg);
1020
1021                 gss_msg_fail_ctx(gmsg);
1022
1023                 upcall_list_unlock(idx);
1024                 gss_release_msg(gmsg);
1025                 upcall_list_lock(idx);
1026         }
1027         upcall_list_unlock(idx);
1028         EXIT;
1029 }
1030
1031 static struct rpc_pipe_ops gss_upcall_ops = {
1032         .upcall         = gss_pipe_upcall,
1033         .downcall       = gss_pipe_downcall,
1034         .destroy_msg    = gss_pipe_destroy_msg,
1035         .release_pipe   = gss_pipe_release,
1036 };
1037
1038 /****************************************
1039  * upcall helper functions              *
1040  ****************************************/
1041
1042 static
1043 int gss_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx)
1044 {
1045         struct obd_import          *imp;
1046         struct gss_sec             *gsec;
1047         struct gss_upcall_msg      *gmsg;
1048         int                         rc = 0;
1049         ENTRY;
1050
1051         might_sleep();
1052
1053         LASSERT(ctx->cc_sec);
1054         LASSERT(ctx->cc_sec->ps_import);
1055         LASSERT(ctx->cc_sec->ps_import->imp_obd);
1056
1057         imp = ctx->cc_sec->ps_import;
1058         if (!imp->imp_connection) {
1059                 CERROR("import has no connection set\n");
1060                 RETURN(-EINVAL);
1061         }
1062
1063         gsec = container_of(ctx->cc_sec, struct gss_sec, gs_base);
1064
1065         OBD_ALLOC_PTR(gmsg);
1066         if (!gmsg)
1067                 RETURN(-ENOMEM);
1068
1069         /* initialize pipefs base msg */
1070         CFS_INIT_LIST_HEAD(&gmsg->gum_base.list);
1071         gmsg->gum_base.data = &gmsg->gum_data;
1072         gmsg->gum_base.len = sizeof(gmsg->gum_data);
1073         gmsg->gum_base.copied = 0;
1074         gmsg->gum_base.errno = 0;
1075
1076         /* init upcall msg */
1077         atomic_set(&gmsg->gum_refcount, 1);
1078         gmsg->gum_mechidx = mech_name2idx(gsec->gs_mech->gm_name);
1079         gmsg->gum_gsec = gsec;
1080         gmsg->gum_gctx = container_of(sptlrpc_cli_ctx_get(ctx),
1081                                       struct gss_cli_ctx, gc_base);
1082         gmsg->gum_data.gum_seq = upcall_get_sequence();
1083         gmsg->gum_data.gum_uid = ctx->cc_vcred.vc_uid;
1084         gmsg->gum_data.gum_gid = 0; /* not used for now */
1085         gmsg->gum_data.gum_svc = import_to_gss_svc(imp);
1086         gmsg->gum_data.gum_nid = imp->imp_connection->c_peer.nid;
1087         strlcpy(gmsg->gum_data.gum_obd, imp->imp_obd->obd_name,
1088                 sizeof(gmsg->gum_data.gum_obd));
1089
1090         /* This only could happen when sysadmin set it dead/expired
1091          * using lctl by force. */
1092         if (ctx->cc_flags & PTLRPC_CTX_STATUS_MASK) {
1093                 CWARN("ctx %p(%u->%s) was set flags %lx unexpectedly\n",
1094                       ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec),
1095                       ctx->cc_flags);
1096
1097                 LASSERT(!(ctx->cc_flags & PTLRPC_CTX_UPTODATE));
1098                 ctx->cc_flags |= PTLRPC_CTX_DEAD | PTLRPC_CTX_ERROR;
1099
1100                 rc = -EIO;
1101                 goto err_free;
1102         }
1103
1104         upcall_msg_enlist(gmsg);
1105
1106         rc = rpc_queue_upcall(de_pipes[gmsg->gum_mechidx]->d_inode,
1107                               &gmsg->gum_base);
1108         if (rc) {
1109                 CERROR("rpc_queue_upcall failed: %d\n", rc);
1110
1111                 upcall_msg_delist(gmsg);
1112                 goto err_free;
1113         }
1114
1115         RETURN(0);
1116 err_free:
1117         OBD_FREE_PTR(gmsg);
1118         RETURN(rc);
1119 }
1120
1121 static
1122 int gss_cli_ctx_refresh_pf(struct ptlrpc_cli_ctx *ctx)
1123 {
1124         /* if we are refreshing for root, also update the reverse
1125          * handle index, do not confuse reverse contexts. */
1126         if (ctx->cc_vcred.vc_uid == 0) {
1127                 struct gss_sec *gsec;
1128
1129                 gsec = container_of(ctx->cc_sec, struct gss_sec, gs_base);
1130                 gsec->gs_rvs_hdl = gss_get_next_ctx_index();
1131         }
1132
1133         return gss_ctx_refresh_pf(ctx);
1134 }
1135
1136 /****************************************
1137  * lustre gss pipefs policy             *
1138  ****************************************/
1139
1140 static struct ptlrpc_ctx_ops gss_pipefs_ctxops = {
1141         .match                  = gss_cli_ctx_match,
1142         .refresh                = gss_cli_ctx_refresh_pf,
1143         .validate               = gss_cli_ctx_validate_pf,
1144         .die                    = gss_cli_ctx_die_pf,
1145         .sign                   = gss_cli_ctx_sign,
1146         .verify                 = gss_cli_ctx_verify,
1147         .seal                   = gss_cli_ctx_seal,
1148         .unseal                 = gss_cli_ctx_unseal,
1149         .wrap_bulk              = gss_cli_ctx_wrap_bulk,
1150         .unwrap_bulk            = gss_cli_ctx_unwrap_bulk,
1151 };
1152
1153 static struct ptlrpc_sec_cops gss_sec_pipefs_cops = {
1154         .create_sec             = gss_sec_create_pf,
1155         .destroy_sec            = gss_sec_destroy_pf,
1156         .kill_sec               = gss_sec_kill,
1157         .lookup_ctx             = gss_sec_lookup_ctx_pf,
1158         .release_ctx            = gss_sec_release_ctx_pf,
1159         .flush_ctx_cache        = gss_sec_flush_ctx_cache_pf,
1160         .install_rctx           = gss_sec_install_rctx,
1161         .alloc_reqbuf           = gss_alloc_reqbuf,
1162         .free_reqbuf            = gss_free_reqbuf,
1163         .alloc_repbuf           = gss_alloc_repbuf,
1164         .free_repbuf            = gss_free_repbuf,
1165         .enlarge_reqbuf         = gss_enlarge_reqbuf,
1166 };
1167
1168 static struct ptlrpc_sec_sops gss_sec_pipefs_sops = {
1169         .accept                 = gss_svc_accept_pf,
1170         .invalidate_ctx         = gss_svc_invalidate_ctx,
1171         .alloc_rs               = gss_svc_alloc_rs,
1172         .authorize              = gss_svc_authorize,
1173         .free_rs                = gss_svc_free_rs,
1174         .free_ctx               = gss_svc_free_ctx,
1175         .unwrap_bulk            = gss_svc_unwrap_bulk,
1176         .wrap_bulk              = gss_svc_wrap_bulk,
1177         .install_rctx           = gss_svc_install_rctx_pf,
1178 };
1179
1180 static struct ptlrpc_sec_policy gss_policy_pipefs = {
1181         .sp_owner               = THIS_MODULE,
1182         .sp_name                = "gss.pipefs",
1183         .sp_policy              = SPTLRPC_POLICY_GSS_PIPEFS,
1184         .sp_cops                = &gss_sec_pipefs_cops,
1185         .sp_sops                = &gss_sec_pipefs_sops,
1186 };
1187
1188 static
1189 int __init gss_init_pipefs_upcall(void)
1190 {
1191         struct dentry   *de;
1192
1193         /* pipe dir */
1194         de = rpc_mkdir(LUSTRE_PIPE_ROOT, NULL);
1195         if (IS_ERR(de) && PTR_ERR(de) != -EEXIST) {
1196                 CERROR("Failed to create gss pipe dir: %ld\n", PTR_ERR(de));
1197                 return PTR_ERR(de);
1198         }
1199
1200         /* FIXME hack pipefs: dput will sometimes cause oops during module
1201          * unload and lgssd close the pipe fds. */
1202
1203         /* krb5 mechanism */
1204         de = rpc_mkpipe(LUSTRE_PIPE_KRB5, (void *) MECH_KRB5, &gss_upcall_ops,
1205                         RPC_PIPE_WAIT_FOR_OPEN);
1206         if (!de || IS_ERR(de)) {
1207                 CERROR("failed to make rpc_pipe %s: %ld\n",
1208                        LUSTRE_PIPE_KRB5, PTR_ERR(de));
1209                 rpc_rmdir(LUSTRE_PIPE_ROOT);
1210                 return PTR_ERR(de);
1211         }
1212
1213         de_pipes[MECH_KRB5] = de;
1214         CFS_INIT_LIST_HEAD(&upcall_lists[MECH_KRB5]);
1215         spin_lock_init(&upcall_locks[MECH_KRB5]);
1216
1217         return 0;
1218 }
1219
1220 static
1221 void __exit gss_exit_pipefs_upcall(void)
1222 {
1223         __u32   i;
1224
1225         for (i = 0; i < MECH_MAX; i++) {
1226                 LASSERT(cfs_list_empty(&upcall_lists[i]));
1227
1228                 /* dput pipe dentry here might cause lgssd oops. */
1229                 de_pipes[i] = NULL;
1230         }
1231
1232         rpc_unlink(LUSTRE_PIPE_KRB5);
1233         rpc_rmdir(LUSTRE_PIPE_ROOT);
1234 }
1235
1236 int __init gss_init_pipefs(void)
1237 {
1238         int rc;
1239
1240         rc = gss_init_pipefs_upcall();
1241         if (rc)
1242                 return rc;
1243
1244         rc = sptlrpc_register_policy(&gss_policy_pipefs);
1245         if (rc) {
1246                 gss_exit_pipefs_upcall();
1247                 return rc;
1248         }
1249
1250         return 0;
1251 }
1252
1253 void __exit gss_exit_pipefs(void)
1254 {
1255         gss_exit_pipefs_upcall();
1256         sptlrpc_unregister_policy(&gss_policy_pipefs);
1257 }