Whamcloud - gitweb
current branches now use lnet from HEAD
[fs/lustre-release.git] / lustre / sec / sec.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 # define EXPORT_SYMTAB
24 #endif
25 #define DEBUG_SUBSYSTEM S_SEC
26 #ifdef __KERNEL__
27 #include <linux/init.h>
28 #include <linux/module.h>
29 #include <linux/slab.h>
30 #else
31 #include <liblustre.h>
32 #endif
33
34 #include <libcfs/kp30.h>
35 #include <linux/obd.h>
36 #include <linux/obd_class.h>
37 #include <linux/obd_support.h>
38 #include <linux/lustre_net.h>
39 #include <linux/lustre_import.h>
40 #include <linux/lustre_dlm.h>
41 #include <linux/lustre_sec.h>
42
43 static spinlock_t sectypes_lock = SPIN_LOCK_UNLOCKED;
44 static struct ptlrpc_sec_type *sectypes[PTLRPCS_FLVR_MAJOR_MAX] = {
45         NULL,
46 };
47
48 int ptlrpcs_register(struct ptlrpc_sec_type *type)
49 {
50         __u32 flavor = type->pst_flavor;
51
52         LASSERT(type->pst_name);
53         LASSERT(type->pst_ops);
54
55         if (flavor >= PTLRPCS_FLVR_MAJOR_MAX)
56                 return -EINVAL;
57
58         spin_lock(&sectypes_lock);
59         if (sectypes[flavor]) {
60                 spin_unlock(&sectypes_lock);
61                 return -EALREADY;
62         }
63         sectypes[flavor] = type;
64         atomic_set(&type->pst_inst, 0);
65         spin_unlock(&sectypes_lock);
66
67         CWARN("%s: registered\n", type->pst_name);
68         return 0;
69 }
70
71 int ptlrpcs_unregister(struct ptlrpc_sec_type *type)
72 {
73         __u32 major = type->pst_flavor;
74
75         LASSERT(major < PTLRPCS_FLVR_MAJOR_MAX);
76
77         spin_lock(&sectypes_lock);
78         if (!sectypes[major]) {
79                 spin_unlock(&sectypes_lock);
80                 CERROR("%s: already unregistered?\n", type->pst_name);
81                 return -EINVAL;
82         }
83
84         LASSERT(sectypes[major] == type);
85
86         if (atomic_read(&type->pst_inst)) {
87                 CERROR("%s: still have %d instances\n",
88                        type->pst_name, atomic_read(&type->pst_inst));
89                 spin_unlock(&sectypes_lock);
90                 return -EINVAL;
91         }
92
93         sectypes[major] = NULL;
94         spin_unlock(&sectypes_lock);
95
96         CDEBUG(D_SEC, "%s: unregistered\n", type->pst_name);
97         return 0;
98 }
99
100 static
101 struct ptlrpc_sec_type * ptlrpcs_flavor2type(__u32 flavor)
102 {
103         struct ptlrpc_sec_type *type;
104         __u32 major = SEC_FLAVOR_MAJOR(flavor);
105
106         if (major >= PTLRPCS_FLVR_MAJOR_MAX)
107                 return NULL;
108
109         spin_lock(&sectypes_lock);
110         type = sectypes[major];
111         if (type && !try_module_get(type->pst_owner))
112                 type = NULL;
113         spin_unlock(&sectypes_lock);
114         return type;
115 }
116
117 static inline
118 void ptlrpcs_type_put(struct ptlrpc_sec_type *type)
119 {
120         module_put(type->pst_owner);
121 }
122
123 __u32 ptlrpcs_name2flavor(const char *name)
124 {
125         if (!strcmp(name, "null"))
126                 return PTLRPCS_FLVR_NULL;
127         if (!strcmp(name, "krb5"))
128                 return PTLRPCS_FLVR_KRB5;
129         if (!strcmp(name, "krb5i"))
130                 return PTLRPCS_FLVR_KRB5I;
131         if (!strcmp(name, "krb5p"))
132                 return PTLRPCS_FLVR_KRB5P;
133
134         return PTLRPCS_FLVR_INVALID;
135 }
136
137 char *ptlrpcs_flavor2name(__u32 flavor)
138 {
139         switch (flavor) {
140         case PTLRPCS_FLVR_NULL:
141                 return "null";
142         case PTLRPCS_FLVR_KRB5:
143                 return "krb5";
144         case PTLRPCS_FLVR_KRB5I:
145                 return "krb5i";
146         case PTLRPCS_FLVR_KRB5P:
147                 return "krb5p";
148         default:
149                 CERROR("invalid flavor 0x%x\n", flavor);
150         }
151         return "unknown";
152 }
153
154 /***********************************************
155  * credential cache helpers                    *
156  ***********************************************/
157
158 void ptlrpcs_init_credcache(struct ptlrpc_sec *sec)
159 {
160         int i;
161         for (i = 0; i < PTLRPC_CREDCACHE_NR; i++)
162                 INIT_LIST_HEAD(&sec->ps_credcache[i]);
163
164         /* ps_nextgc == 0 means never do gc */
165         if (sec->ps_nextgc)
166                 sec->ps_nextgc = get_seconds() + (sec->ps_expire >> 1);
167 }
168
169 /*
170  * return 1 means we should also destroy the sec structure.
171  * normally return 0
172  */
173 static int ptlrpcs_cred_destroy(struct ptlrpc_cred *cred)
174 {
175         struct ptlrpc_sec *sec = cred->pc_sec;
176         int rc = 0;
177
178         LASSERT(cred->pc_sec);
179         LASSERT(atomic_read(&cred->pc_refcount) == 0);
180         LASSERT(list_empty(&cred->pc_hash));
181
182         cred->pc_ops->destroy(cred);
183
184         /* spinlock to protect against ptlrpcs_sec_put() */
185         LASSERT(atomic_read(&sec->ps_credcount));
186         spin_lock(&sec->ps_lock);
187         if (atomic_dec_and_test(&sec->ps_credcount) &&
188             !atomic_read(&sec->ps_refcount))
189                 rc = 1;
190         spin_unlock(&sec->ps_lock);
191         return rc;
192 }
193
194 static void ptlrpcs_destroy_credlist(struct list_head *head)
195 {
196         struct ptlrpc_cred *cred;
197
198         while (!list_empty(head)) {
199                 cred = list_entry(head->next, struct ptlrpc_cred, pc_hash);
200                 list_del_init(&cred->pc_hash);
201                 ptlrpcs_cred_destroy(cred);
202         }
203 }
204
205 static
206 int cred_check_dead(struct ptlrpc_cred *cred,
207                     struct list_head *freelist, int removal)
208 {
209         /* here we do the exact thing as asked. but an alternative
210          * way is remove dead entries immediately without be asked
211          * remove, since dead entry will not lead to further rpcs.
212          */
213         if (unlikely(ptlrpcs_cred_is_dead(cred))) {
214                 /* don't try to destroy a busy entry */
215                 if (atomic_read(&cred->pc_refcount))
216                         return 1;
217                 goto out;
218         }
219
220         /* a busy non-dead entry is considered as "good" one.
221          * Note in a very busy client where cred always busy, we
222          * will not be able to find the expire here, but some other
223          * part will, e.g. checking during refresh, or got error
224          * notification from server, etc. We don't touch busy cred
225          * here is because a busy cred's flag might be changed at
226          * anytime by the owner, we don't want to compete with them.
227          */
228         if (atomic_read(&cred->pc_refcount) != 0)
229                 return 0;
230
231         /* expire is 0 means never expire. a newly created gss cred
232          * which during upcall also has 0 expiration
233          */
234         if (cred->pc_expire == 0)
235                 return 0;
236
237         /* check real expiration */
238         if (time_after(cred->pc_expire, get_seconds()))
239                 return 0;
240
241         /* although we'v checked the bit right above, there's still
242          * possibility that somebody else set the bit elsewhere.
243          */
244         ptlrpcs_cred_expire(cred);
245
246 out:
247         if (removal) {
248                 LASSERT(atomic_read(&cred->pc_refcount) >= 0);
249                 LASSERT(cred->pc_sec);
250                 LASSERT(spin_is_locked(&cred->pc_sec->ps_lock));
251                 LASSERT(freelist);
252
253                 list_move(&cred->pc_hash, freelist);
254         }
255         return 1;
256 }
257
258 static
259 void ptlrpcs_credcache_gc(struct ptlrpc_sec *sec,
260                           struct list_head *freelist)
261 {
262         struct ptlrpc_cred *cred, *n;
263         int i;
264         ENTRY;
265
266         CDEBUG(D_SEC, "do gc on sec %s\n", sec->ps_type->pst_name);
267         for (i = 0; i < PTLRPC_CREDCACHE_NR; i++) {
268                 list_for_each_entry_safe(cred, n, &sec->ps_credcache[i],
269                                          pc_hash)
270                         cred_check_dead(cred, freelist, 1);
271         }
272         sec->ps_nextgc = get_seconds() + sec->ps_expire;
273         EXIT;
274 }
275
276 /*
277  * @uid: which user. "-1" means flush all.
278  * @grace: mark cred DEAD, allow graceful destroy like notify
279  *         server side, etc.
280  * @force: flush all entries, otherwise only free ones be flushed.
281  */
282 static
283 int flush_credcache(struct ptlrpc_sec *sec, unsigned long pag, uid_t uid,
284                     int grace, int force)
285 {
286         struct ptlrpc_cred *cred, *n;
287         LIST_HEAD(freelist);
288         int i, busy = 0;
289         ENTRY;
290
291         might_sleep_if(grace);
292
293         spin_lock(&sec->ps_lock);
294         for (i = 0; i < PTLRPC_CREDCACHE_NR; i++) {
295                 list_for_each_entry_safe(cred, n, &sec->ps_credcache[i],
296                                          pc_hash) {
297                         LASSERT(atomic_read(&cred->pc_refcount) >= 0);
298
299                         if (sec->ps_flags & PTLRPC_SEC_FL_PAG) {
300                                 if (pag != -1 && pag != cred->pc_pag)
301                                         continue;
302                         } else {
303                                 if (uid != -1 && uid != cred->pc_uid)
304                                         continue;
305                         }
306
307                         if (atomic_read(&cred->pc_refcount)) {
308                                 busy = 1;
309                                 if (!force)
310                                         continue;
311                                 list_del_init(&cred->pc_hash);
312                                 CDEBUG(D_SEC, "sec %p: flush busy(%d) cred %p "
313                                        "by force\n", sec,
314                                        atomic_read(&cred->pc_refcount), cred);
315                         } else
316                                 list_move(&cred->pc_hash, &freelist);
317
318                         set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
319                         if (!grace)
320                                 clear_bit(PTLRPC_CRED_UPTODATE_BIT,
321                                           &cred->pc_flags);
322                 }
323         }
324         spin_unlock(&sec->ps_lock);
325
326         ptlrpcs_destroy_credlist(&freelist);
327         RETURN(busy);
328 }
329
330 /**************************************************
331  * credential APIs                                *
332  **************************************************/
333
334 static inline
335 int ptlrpcs_cred_get_hash(__u64 pag)
336 {
337         LASSERT((pag & PTLRPC_CREDCACHE_MASK) < PTLRPC_CREDCACHE_NR);
338         return (pag & PTLRPC_CREDCACHE_MASK);
339 }
340
341 /*
342  * return an uptodate or newly created cred entry.
343  */
344 static
345 struct ptlrpc_cred * cred_cache_lookup(struct ptlrpc_sec *sec,
346                                        struct vfs_cred *vcred,
347                                        int create, int remove_dead)
348 {
349         struct ptlrpc_cred *cred, *new = NULL, *n;
350         LIST_HEAD(freelist);
351         int hash, found = 0;
352         ENTRY;
353
354         might_sleep();
355
356         hash = ptlrpcs_cred_get_hash(vcred->vc_pag);
357
358 retry:
359         spin_lock(&sec->ps_lock);
360
361         /* do gc if expired */
362         if (remove_dead &&
363             sec->ps_nextgc && time_after(get_seconds(), sec->ps_nextgc))
364                 ptlrpcs_credcache_gc(sec, &freelist);
365
366         list_for_each_entry_safe(cred, n, &sec->ps_credcache[hash], pc_hash) {
367                 if (cred_check_dead(cred, &freelist, remove_dead))
368                         continue;
369                 if (cred->pc_ops->match(cred, vcred)) {
370                         found = 1;
371                         break;
372                 }
373         }
374
375         if (found) {
376                 if (new && new != cred) {
377                         /* lost the race, just free it */
378                         list_add(&new->pc_hash, &freelist);
379                 }
380                 list_move(&cred->pc_hash, &sec->ps_credcache[hash]);
381         } else {
382                 if (new) {
383                         list_add(&new->pc_hash, &sec->ps_credcache[hash]);
384                         cred = new;
385                 } else if (create) {
386                         spin_unlock(&sec->ps_lock);
387                         new = sec->ps_type->pst_ops->create_cred(sec, vcred);
388                         if (new) {
389                                 atomic_inc(&sec->ps_credcount);
390                                 goto retry;
391                         }
392                 } else
393                         cred = NULL;
394         }
395
396         /* hold a ref */
397         if (cred)
398                 atomic_inc(&cred->pc_refcount);
399
400         spin_unlock(&sec->ps_lock);
401
402         ptlrpcs_destroy_credlist(&freelist);
403         RETURN(cred);
404 }
405
406 struct ptlrpc_cred * ptlrpcs_cred_lookup(struct ptlrpc_sec *sec,
407                                          struct vfs_cred *vcred)
408 {
409         struct ptlrpc_cred *cred;
410         ENTRY;
411
412         cred = cred_cache_lookup(sec, vcred, 0, 1);
413         RETURN(cred);
414 }
415
416 static struct ptlrpc_cred *get_cred(struct ptlrpc_sec *sec)
417 {
418         struct vfs_cred vcred;
419
420         LASSERT(sec);
421
422         if (sec->ps_flags &
423             (PTLRPC_SEC_FL_MDS | PTLRPC_SEC_FL_OSS | PTLRPC_SEC_FL_REVERSE)) {
424                 vcred.vc_pag = 0;
425                 vcred.vc_uid = 0;
426         } else {
427                 if (sec->ps_flags & PTLRPC_SEC_FL_PAG)
428                         vcred.vc_pag = (__u64) current->pag;
429                 else
430                         vcred.vc_pag = (__u64) current->uid;
431                 vcred.vc_uid = current->uid;
432         }
433
434         return cred_cache_lookup(sec, &vcred, 1, 1);
435 }
436
437 int ptlrpcs_req_get_cred(struct ptlrpc_request *req)
438 {
439         struct obd_import *imp = req->rq_import;
440         ENTRY;
441
442         LASSERT(!req->rq_cred);
443         LASSERT(imp);
444
445         req->rq_cred = get_cred(imp->imp_sec);
446
447         if (!req->rq_cred) {
448                 CERROR("req %p: fail to get cred from cache\n", req);
449                 RETURN(-ENOMEM);
450         }
451
452         RETURN(0);
453 }
454
455 /*
456  * check whether current user have valid credential for an import or not.
457  * might repeatedly try in case of non-fatal errors.
458  * return 0 on success, 1 on failure
459  */
460 int ptlrpcs_check_cred(struct obd_import *imp)
461 {
462         struct ptlrpc_cred *cred;
463         ENTRY;
464
465         might_sleep();
466 again:
467         cred = get_cred(imp->imp_sec);
468         if (!cred)
469                 RETURN(0);
470
471         if (ptlrpcs_cred_is_uptodate(cred)) {
472                 /* get_cred() has done expire checking, so we don't
473                  * expect it could expire so quickly, and actually
474                  * we don't care.
475                  */
476                 ptlrpcs_cred_put(cred, 1);
477                 RETURN(0);
478         }
479
480         ptlrpcs_cred_refresh(cred);
481         if (ptlrpcs_cred_is_uptodate(cred)) {
482                 ptlrpcs_cred_put(cred, 1);
483                 RETURN(0);
484         }
485
486         if (cred->pc_flags & PTLRPC_CRED_ERROR ||
487             !imp->imp_replayable) {
488                 ptlrpcs_cred_put(cred, 1);
489                 RETURN(1);
490         }
491
492         ptlrpcs_cred_put(cred, 1);
493
494         if (signal_pending(current)) {
495                 CWARN("%s: interrupted\n", current->comm);
496                 RETURN(1);
497         }
498         goto again;
499 }
500
501 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec);
502
503 void ptlrpcs_cred_put(struct ptlrpc_cred *cred, int sync)
504 {
505         struct ptlrpc_sec *sec = cred->pc_sec;
506
507         LASSERT(sec);
508         LASSERT(atomic_read(&cred->pc_refcount));
509
510         spin_lock(&sec->ps_lock);
511
512         /* this has to be protected by ps_lock, because cred cache
513          * management code might increase ref against a 0-refed cred.
514          */
515         if (!atomic_dec_and_test(&cred->pc_refcount)) {
516                 spin_unlock(&sec->ps_lock);
517                 return;
518         }
519
520         /* if sec already unused, we have to destroy the cred (prevent it
521          * hanging there for ever)
522          */
523         if (atomic_read(&sec->ps_refcount) == 0) {
524                 if (!test_and_set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags))
525                         CWARN("cred %p: force expire on a unused sec\n", cred);
526                 list_del_init(&cred->pc_hash);
527         } else if (unlikely(sync && ptlrpcs_cred_is_dead(cred)))
528                 list_del_init(&cred->pc_hash);
529
530         if (!list_empty(&cred->pc_hash)) {
531                 spin_unlock(&sec->ps_lock);
532                 return;
533         }
534
535         /* if required async, and we reached here, we have to clear
536          * the UPTODATE bit, thus no rpc is needed in destroy procedure.
537          */
538         if (!sync)
539                 clear_bit(PTLRPC_CRED_UPTODATE_BIT, &cred->pc_flags);
540
541         spin_unlock(&sec->ps_lock);
542
543         /* destroy this cred */
544         if (!ptlrpcs_cred_destroy(cred))
545                 return;
546
547         LASSERT(!atomic_read(&sec->ps_credcount));
548         LASSERT(!atomic_read(&sec->ps_refcount));
549
550         CWARN("sec %p(%s), put last cred, also destroy the sec\n",
551               sec, sec->ps_type->pst_name);
552 }
553
554 void ptlrpcs_req_drop_cred(struct ptlrpc_request *req)
555 {
556         ENTRY;
557
558         LASSERT(req);
559         LASSERT(req->rq_cred);
560
561         if (req->rq_cred) {
562                 /* this could be called with spinlock hold, use async mode */
563                 ptlrpcs_cred_put(req->rq_cred, 0);
564                 req->rq_cred = NULL;
565         } else
566                 CDEBUG(D_SEC, "req %p have no cred\n", req);
567         EXIT;
568 }
569
570 /* 
571  * request must have a cred. if failed to get new cred,
572  * just restore the old one
573  */
574 int ptlrpcs_req_replace_dead_cred(struct ptlrpc_request *req)
575 {
576         struct ptlrpc_cred *cred = req->rq_cred;
577         int rc;
578         ENTRY;
579
580         LASSERT(cred);
581         LASSERT(test_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags));
582
583         ptlrpcs_cred_get(cred);
584         ptlrpcs_req_drop_cred(req);
585         LASSERT(!req->rq_cred);
586         rc = ptlrpcs_req_get_cred(req);
587         if (!rc) {
588                 LASSERT(req->rq_cred);
589                 LASSERT(req->rq_cred != cred);
590                 ptlrpcs_cred_put(cred, 1);
591         } else {
592                 LASSERT(!req->rq_cred);
593                 req->rq_cred = cred;
594         }
595         RETURN(rc);
596 }
597
598 /*
599  * since there's no lock on the cred, its status could be changed
600  * by other threads at any time, we allow this race. If an uptodate
601  * cred turn to dead quickly under us, we don't know and continue
602  * using it, that's fine. if necessary the later error handling code
603  * will catch it.
604  */
605 int ptlrpcs_req_refresh_cred(struct ptlrpc_request *req)
606 {
607         struct ptlrpc_cred *cred = req->rq_cred;
608         ENTRY;
609
610         LASSERT(cred);
611
612         if (!ptlrpcs_cred_check_uptodate(cred))
613                 RETURN(0);
614
615         if (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags)) {
616                 req->rq_ptlrpcs_err = 1;
617                 RETURN(-EPERM);
618         }
619
620         if (test_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags)) {
621                 if (ptlrpcs_req_replace_dead_cred(req) == 0) {
622                         LASSERT(cred != req->rq_cred);
623                         CDEBUG(D_SEC, "req %p: replace cred %p => %p\n",
624                                req, cred, req->rq_cred);
625                         cred = req->rq_cred;
626                 } else {
627                         LASSERT(cred == req->rq_cred);
628                         CERROR("req %p: failed to replace dead cred %p\n",
629                                 req, cred);
630                         req->rq_ptlrpcs_err = 1;
631                         RETURN(-ENOMEM);
632                 }
633         }
634
635         ptlrpcs_cred_refresh(cred);
636
637         if (!ptlrpcs_cred_is_uptodate(cred)) {
638                 if (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags))
639                         req->rq_ptlrpcs_err = 1;
640
641                 CERROR("req %p: failed to refresh cred %p, fatal %d\n",
642                         req, cred, req->rq_ptlrpcs_err);
643                 RETURN(-EPERM);
644         } else
645                 RETURN(0);
646 }
647
648 int ptlrpcs_cli_wrap_request(struct ptlrpc_request *req)
649 {
650         struct ptlrpc_cred     *cred;
651         int rc;
652         ENTRY;
653
654         LASSERT(req->rq_cred);
655         LASSERT(req->rq_cred->pc_sec);
656         LASSERT(req->rq_cred->pc_ops);
657         LASSERT(req->rq_reqbuf);
658         LASSERT(req->rq_reqbuf_len);
659
660         rc = ptlrpcs_req_refresh_cred(req);
661         if (rc)
662                 RETURN(rc);
663
664         CDEBUG(D_SEC, "wrap req %p\n", req);
665         cred = req->rq_cred;
666
667         switch (SEC_FLAVOR_SVC(req->rq_req_secflvr)) {
668         case PTLRPCS_SVC_NONE:
669         case PTLRPCS_SVC_AUTH:
670                 if (req->rq_req_wrapped) {
671                         CDEBUG(D_SEC, "req %p(o%u,x"LPU64",t"LPU64") "
672                                "already signed, resend?\n", req,
673                                req->rq_reqmsg ? req->rq_reqmsg->opc : -1,
674                                req->rq_xid, req->rq_transno);
675                         req->rq_req_wrapped = 0;
676                         req->rq_reqdata_len = sizeof(struct ptlrpcs_wire_hdr) +
677                                               req->rq_reqlen;
678                         LASSERT(req->rq_reqdata_len % 8 == 0);
679                 }
680
681                 LASSERT(cred->pc_ops->sign);
682                 rc = cred->pc_ops->sign(cred, req);
683                 if (!rc)
684                         req->rq_req_wrapped = 1;
685                 break;
686         case PTLRPCS_SVC_PRIV:
687                 if (req->rq_req_wrapped) {
688                         CDEBUG(D_SEC, "req %p(o%u,x"LPU64",t"LPU64") "
689                                "already encrypted, resend?\n", req,
690                                req->rq_reqmsg ? req->rq_reqmsg->opc : -1,
691                                req->rq_xid, req->rq_transno);
692                         req->rq_req_wrapped = 0;
693                         req->rq_reqdata_len = sizeof(struct ptlrpcs_wire_hdr);
694                         LASSERT(req->rq_reqdata_len % 8 == 0);
695                 }
696
697                 LASSERT(cred->pc_ops->seal);
698                 rc = cred->pc_ops->seal(cred, req);
699                 if (!rc)
700                         req->rq_req_wrapped = 1;
701                 break;
702         default:
703                 LBUG();
704         }
705         LASSERT(req->rq_reqdata_len);
706         LASSERT(req->rq_reqdata_len % 8 == 0);
707         LASSERT(req->rq_reqdata_len >= sizeof(struct ptlrpcs_wire_hdr));
708         LASSERT(req->rq_reqdata_len <= req->rq_reqbuf_len);
709
710         RETURN(rc);
711 }
712
713 /* rq_nob_received is the actual received data length */
714 int ptlrpcs_cli_unwrap_reply(struct ptlrpc_request *req)
715 {
716         struct ptlrpc_cred *cred = req->rq_cred;
717         struct ptlrpc_sec *sec;
718         struct ptlrpcs_wire_hdr *sec_hdr;
719         int rc;
720         ENTRY;
721
722         LASSERT(cred);
723         LASSERT(cred->pc_sec);
724         LASSERT(cred->pc_ops);
725         LASSERT(req->rq_repbuf);
726         
727         if (req->rq_nob_received < sizeof(*sec_hdr)) {
728                 CERROR("req %p: reply size only %d\n",
729                         req, req->rq_nob_received);
730                 RETURN(-EPROTO);
731         }
732
733         sec_hdr = (struct ptlrpcs_wire_hdr *) req->rq_repbuf;
734         sec_hdr->flavor = le32_to_cpu(sec_hdr->flavor);
735         sec_hdr->msg_len = le32_to_cpu(sec_hdr->msg_len);
736         sec_hdr->sec_len = le32_to_cpu(sec_hdr->sec_len);
737
738         CDEBUG(D_SEC, "req %p, cred %p, flavor 0x%x\n",
739                req, cred, sec_hdr->flavor);
740
741         sec = cred->pc_sec;
742
743         /* only compare major flavor, reply might use different subflavor.
744          */
745         if (SEC_FLAVOR_MAJOR(sec_hdr->flavor) !=
746             SEC_FLAVOR_MAJOR(req->rq_req_secflvr)) {
747                 CERROR("got major flavor %u while expect %u\n",
748                        SEC_FLAVOR_MAJOR(sec_hdr->flavor),
749                        SEC_FLAVOR_MAJOR(req->rq_req_secflvr));
750                 RETURN(-EPROTO);
751         }
752
753         if (sizeof(*sec_hdr) + sec_hdr->msg_len + sec_hdr->sec_len >
754             req->rq_nob_received) {
755                 CERROR("msg %u, sec %u, while only get %d\n",
756                         sec_hdr->msg_len, sec_hdr->sec_len,
757                         req->rq_nob_received);
758                 RETURN(-EPROTO);
759         }
760
761         switch (SEC_FLAVOR_SVC(sec_hdr->flavor)) {
762         case PTLRPCS_SVC_NONE:
763         case PTLRPCS_SVC_AUTH: {
764                 LASSERT(cred->pc_ops->verify);
765                 rc = cred->pc_ops->verify(cred, req);
766                 LASSERT(rc || req->rq_repmsg || req->rq_ptlrpcs_restart);
767                 break;
768         case PTLRPCS_SVC_PRIV:
769                 LASSERT(cred->pc_ops->unseal);
770                 rc = cred->pc_ops->unseal(cred, req);
771                 LASSERT(rc || req->rq_repmsg || req->rq_ptlrpcs_restart);
772                 break;
773         }
774         default:
775                 rc = -1;
776                 LBUG();
777         }
778         RETURN(rc);
779 }
780
781 /**************************************************
782  * security APIs                                  *
783  **************************************************/
784
785 struct ptlrpc_sec * ptlrpcs_sec_create(__u32 flavor,
786                                        unsigned long flags,
787                                        struct obd_import *import,
788                                        const char *pipe_dir,
789                                        void *pipe_data)
790 {
791         struct ptlrpc_sec_type *type;
792         struct ptlrpc_sec *sec;
793         ENTRY;
794
795         type = ptlrpcs_flavor2type(flavor);
796         if (!type) {
797                 CERROR("invalid flavor 0x%x\n", flavor);
798                 RETURN(NULL);
799         }
800
801         sec = type->pst_ops->create_sec(flavor, pipe_dir, pipe_data);
802         if (sec) {
803                 spin_lock_init(&sec->ps_lock);
804                 ptlrpcs_init_credcache(sec);
805                 sec->ps_type = type;
806                 sec->ps_flavor = flavor;
807                 sec->ps_flags = flags;
808                 sec->ps_import = class_import_get(import);
809                 atomic_set(&sec->ps_refcount, 1);
810                 atomic_set(&sec->ps_credcount, 0);
811                 atomic_inc(&type->pst_inst);
812         } else
813                 ptlrpcs_type_put(type);
814
815         return sec;
816 }
817
818 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec)
819 {
820         struct ptlrpc_sec_type *type = sec->ps_type;
821         struct obd_import *imp = sec->ps_import;
822
823         LASSERT(type && type->pst_ops);
824         LASSERT(type->pst_ops->destroy_sec);
825
826         type->pst_ops->destroy_sec(sec);
827         atomic_dec(&type->pst_inst);
828         ptlrpcs_type_put(type);
829         class_import_put(imp);
830 }
831
832 void ptlrpcs_sec_put(struct ptlrpc_sec *sec)
833 {
834         int ncred;
835
836         if (atomic_dec_and_test(&sec->ps_refcount)) {
837                 flush_credcache(sec, -1, -1, 1, 1);
838
839                 /* this spinlock is protect against ptlrpcs_cred_destroy() */
840                 spin_lock(&sec->ps_lock);
841                 ncred = atomic_read(&sec->ps_credcount);
842                 spin_unlock(&sec->ps_lock);
843
844                 if (ncred == 0) {
845                         ptlrpcs_sec_destroy(sec);
846                 } else {
847                         CWARN("%s %p is no usage while %d cred still "
848                               "holded, destroy delayed\n",
849                                sec->ps_type->pst_name, sec,
850                                atomic_read(&sec->ps_credcount));
851                 }
852         }
853 }
854
855 void ptlrpcs_sec_invalidate_cache(struct ptlrpc_sec *sec)
856 {
857         flush_credcache(sec, -1, -1, 0, 1);
858 }
859
860 int sec_alloc_reqbuf(struct ptlrpc_sec *sec,
861                      struct ptlrpc_request *req,
862                      int msgsize, int secsize)
863 {
864         struct ptlrpcs_wire_hdr *hdr;
865         ENTRY;
866
867         LASSERT(msgsize % 8 == 0);
868         LASSERT(secsize % 8 == 0);
869
870         req->rq_reqbuf_len = sizeof(*hdr) + msgsize + secsize;
871         OBD_ALLOC(req->rq_reqbuf, req->rq_reqbuf_len);
872         if (!req->rq_reqbuf) {
873                 CERROR("can't alloc %d\n", req->rq_reqbuf_len);
874                 RETURN(-ENOMEM);
875         }
876
877         hdr = buf_to_sec_hdr(req->rq_reqbuf);
878         hdr->flavor = cpu_to_le32(req->rq_req_secflvr);
879         hdr->msg_len = msgsize;
880         /* security length will be filled later */
881
882         /* later reqdata_len will be added on actual security payload */
883         req->rq_reqdata_len = sizeof(*hdr) + msgsize;
884         req->rq_reqmsg = buf_to_lustre_msg(req->rq_reqbuf);
885
886         CDEBUG(D_SEC, "req %p: rqbuf at %p, len %d, msg %d, sec %d\n",
887                req, req->rq_reqbuf, req->rq_reqbuf_len,
888                msgsize, secsize);
889
890         RETURN(0);
891 }
892
893 /* when complete successfully, req->rq_reqmsg should point to the
894  * right place.
895  */
896 int ptlrpcs_cli_alloc_reqbuf(struct ptlrpc_request *req, int msgsize)
897 {
898         struct ptlrpc_cred *cred = req->rq_cred;
899         struct ptlrpc_sec *sec;
900         struct ptlrpc_secops *ops;
901
902         LASSERT(msgsize % 8 == 0);
903         LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
904         LASSERT(cred);
905         LASSERT(atomic_read(&cred->pc_refcount));
906         LASSERT(cred->pc_sec);
907         LASSERT(cred->pc_sec->ps_type);
908         LASSERT(cred->pc_sec->ps_type->pst_ops);
909         LASSERT(req->rq_reqbuf == NULL);
910         LASSERT(req->rq_reqmsg == NULL);
911
912         sec = cred->pc_sec;
913         ops = sec->ps_type->pst_ops;
914         if (ops->alloc_reqbuf)
915                 return ops->alloc_reqbuf(sec, req, msgsize);
916         else
917                 return sec_alloc_reqbuf(sec, req, msgsize, 0);
918 }
919
920 void sec_free_reqbuf(struct ptlrpc_sec *sec,
921                      struct ptlrpc_request *req)
922 {
923         LASSERT(req->rq_reqbuf);
924         LASSERT(req->rq_reqbuf_len);
925
926         /* sanity check */
927         if (req->rq_reqmsg) {
928                 LASSERT((char *) req->rq_reqmsg >= req->rq_reqbuf &&
929                         (char *) req->rq_reqmsg < req->rq_reqbuf +
930                                                   req->rq_reqbuf_len);
931         }
932
933         OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len);
934         req->rq_reqbuf = NULL;
935         req->rq_reqmsg = NULL;
936 }
937
938 void ptlrpcs_cli_free_reqbuf(struct ptlrpc_request *req)
939 {
940         struct ptlrpc_cred *cred = req->rq_cred;
941         struct ptlrpc_sec *sec;
942         struct ptlrpc_secops *ops;
943
944         LASSERT(cred);
945         LASSERT(atomic_read(&cred->pc_refcount));
946         LASSERT(cred->pc_sec);
947         LASSERT(cred->pc_sec->ps_type);
948         LASSERT(cred->pc_sec->ps_type->pst_ops);
949         LASSERT(req->rq_reqbuf);
950
951         sec = cred->pc_sec;
952         ops = sec->ps_type->pst_ops;
953         if (ops->free_reqbuf)
954                 ops->free_reqbuf(sec, req);
955         else
956                 sec_free_reqbuf(sec, req);
957 }
958
959 int ptlrpcs_cli_alloc_repbuf(struct ptlrpc_request *req, int msgsize)
960 {
961         struct ptlrpc_cred *cred = req->rq_cred;
962         struct ptlrpc_sec *sec;
963         struct ptlrpc_secops *ops;
964         int msg_payload, sec_payload;
965         ENTRY;
966
967         LASSERT(msgsize % 8 == 0);
968         LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
969         LASSERT(cred);
970         LASSERT(atomic_read(&cred->pc_refcount));
971         LASSERT(cred->pc_sec);
972         LASSERT(cred->pc_sec->ps_type);
973         LASSERT(cred->pc_sec->ps_type->pst_ops);
974         LASSERT(req->rq_repbuf == NULL);
975
976         sec = cred->pc_sec;
977         ops = sec->ps_type->pst_ops;
978         if (ops->alloc_repbuf)
979                 RETURN(ops->alloc_repbuf(sec, req, msgsize));
980
981         /* default allocation scheme */
982         msg_payload = SEC_FLAVOR_SVC(req->rq_req_secflvr) == PTLRPCS_SVC_PRIV ?
983                       0 : msgsize;
984         sec_payload = size_round(ptlrpcs_est_rep_payload(req, msgsize));
985
986         req->rq_repbuf_len = sizeof(struct ptlrpcs_wire_hdr) +
987                              msg_payload + sec_payload;
988         OBD_ALLOC(req->rq_repbuf, req->rq_repbuf_len);
989         if (!req->rq_repbuf)
990                 RETURN(-ENOMEM);
991
992         CDEBUG(D_SEC, "req %p: repbuf at %p, len %d, msg %d, sec %d\n",
993                req, req->rq_repbuf, req->rq_repbuf_len,
994                msg_payload, sec_payload);
995
996         RETURN(0);
997 }
998
999 void ptlrpcs_cli_free_repbuf(struct ptlrpc_request *req)
1000 {
1001         struct ptlrpc_cred *cred = req->rq_cred;
1002         struct ptlrpc_sec *sec;
1003         struct ptlrpc_secops *ops;
1004         ENTRY;
1005
1006         LASSERT(cred);
1007         LASSERT(atomic_read(&cred->pc_refcount));
1008         LASSERT(cred->pc_sec);
1009         LASSERT(cred->pc_sec->ps_type);
1010         LASSERT(cred->pc_sec->ps_type->pst_ops);
1011         LASSERT(req->rq_repbuf);
1012
1013         sec = cred->pc_sec;
1014         ops = sec->ps_type->pst_ops;
1015         if (ops->free_repbuf)
1016                 ops->free_repbuf(sec, req);
1017         else {
1018                 OBD_FREE(req->rq_repbuf, req->rq_repbuf_len);
1019                 req->rq_repbuf = NULL;
1020                 req->rq_repmsg = NULL;
1021         }
1022         EXIT;
1023 }
1024
1025 int ptlrpcs_import_get_sec(struct obd_import *imp)
1026 {
1027         __u32 flavor = PTLRPCS_FLVR_NULL;
1028         unsigned long flags = 0;
1029         char *pipedir = NULL;
1030         ENTRY;
1031
1032         LASSERT(imp->imp_obd);
1033         LASSERT(imp->imp_obd->obd_type);
1034
1035         /* old sec might be still there in reconnecting */
1036         if (imp->imp_sec)
1037                 RETURN(0);
1038
1039         /* find actual flavor for client obd. right now server side
1040          * obd (reverse imp, etc) will simply use NULL. */
1041         if (!strcmp(imp->imp_obd->obd_type->typ_name, OBD_MDC_DEVICENAME) ||
1042             !strcmp(imp->imp_obd->obd_type->typ_name, OBD_OSC_DEVICENAME)) {
1043                 struct client_obd *cli = &imp->imp_obd->u.cli;
1044
1045                 switch (SEC_FLAVOR_MAJOR(cli->cl_sec_flavor)) {
1046                 case PTLRPCS_FLVR_MAJOR_NULL:
1047                         CWARN("select security null for %s(%s)\n",
1048                               imp->imp_obd->obd_type->typ_name,
1049                               imp->imp_obd->obd_name);
1050                         break;
1051                 case PTLRPCS_FLVR_MAJOR_GSS:
1052                         CWARN("select security %s for %s(%s)\n",
1053                               ptlrpcs_flavor2name(cli->cl_sec_flavor),
1054                               imp->imp_obd->obd_type->typ_name,
1055                               imp->imp_obd->obd_name);
1056                         flavor = cli->cl_sec_flavor;
1057                         pipedir = imp->imp_obd->obd_name;
1058                         break;
1059                 default:
1060                         CWARN("unknown security flavor for %s(%s), "
1061                               "use null\n",
1062                               imp->imp_obd->obd_type->typ_name,
1063                               imp->imp_obd->obd_name);
1064                 }
1065
1066                 flags = cli->cl_sec_flags;
1067         }
1068
1069         imp->imp_sec = ptlrpcs_sec_create(flavor, flags, imp, pipedir, imp);
1070         if (!imp->imp_sec)
1071                 RETURN(-EINVAL);
1072         else
1073                 RETURN(0);
1074 }
1075
1076 void ptlrpcs_import_drop_sec(struct obd_import *imp)
1077 {
1078         ENTRY;
1079         if (imp->imp_sec) {
1080                 ptlrpcs_sec_put(imp->imp_sec);
1081                 imp->imp_sec = NULL;
1082         }
1083         EXIT;
1084 }
1085
1086 void ptlrpcs_import_flush_current_creds(struct obd_import *imp)
1087 {
1088         LASSERT(imp);
1089
1090         class_import_get(imp);
1091         if (imp->imp_sec)
1092                 flush_credcache(imp->imp_sec, current->pag, current->uid, 1, 1);
1093         class_import_put(imp);
1094 }
1095
1096 int __init ptlrpc_sec_init(void)
1097 {
1098         int rc;
1099
1100         if ((rc = ptlrpcs_null_init()))
1101                 return rc;
1102
1103         if ((rc = svcsec_null_init())) {
1104                 ptlrpcs_null_exit();
1105                 return rc;
1106         }
1107
1108 #if 0
1109 #if !defined __KERNEL__ && defined ENABLE_GSS
1110         ptlrpcs_gss_init();
1111 #endif
1112 #endif
1113         return 0;
1114 }
1115
1116 #if defined __KERNEL__ && defined ENABLE_GSS
1117 static void __exit ptlrpc_sec_exit(void)
1118 {
1119         svcsec_null_exit();
1120         ptlrpcs_null_exit();
1121 }
1122 #endif
1123
1124 EXPORT_SYMBOL(ptlrpcs_register);
1125 EXPORT_SYMBOL(ptlrpcs_unregister);
1126 EXPORT_SYMBOL(ptlrpcs_sec_create);
1127 EXPORT_SYMBOL(ptlrpcs_sec_put);
1128 EXPORT_SYMBOL(ptlrpcs_sec_invalidate_cache);
1129 EXPORT_SYMBOL(ptlrpcs_import_get_sec);
1130 EXPORT_SYMBOL(ptlrpcs_import_drop_sec);
1131 EXPORT_SYMBOL(ptlrpcs_import_flush_current_creds);
1132 EXPORT_SYMBOL(ptlrpcs_cred_lookup);
1133 EXPORT_SYMBOL(ptlrpcs_cred_put);
1134 EXPORT_SYMBOL(ptlrpcs_req_get_cred);
1135 EXPORT_SYMBOL(ptlrpcs_req_drop_cred);
1136 EXPORT_SYMBOL(ptlrpcs_req_replace_dead_cred);
1137 EXPORT_SYMBOL(ptlrpcs_req_refresh_cred);
1138 EXPORT_SYMBOL(ptlrpcs_check_cred);
1139 EXPORT_SYMBOL(ptlrpcs_cli_alloc_reqbuf);
1140 EXPORT_SYMBOL(ptlrpcs_cli_free_reqbuf);
1141 EXPORT_SYMBOL(ptlrpcs_cli_alloc_repbuf);
1142 EXPORT_SYMBOL(ptlrpcs_cli_free_repbuf);
1143 EXPORT_SYMBOL(ptlrpcs_cli_wrap_request);
1144 EXPORT_SYMBOL(ptlrpcs_cli_unwrap_reply);
1145 EXPORT_SYMBOL(sec_alloc_reqbuf);
1146 EXPORT_SYMBOL(sec_free_reqbuf);
1147
1148 EXPORT_SYMBOL(svcsec_register);
1149 EXPORT_SYMBOL(svcsec_unregister);
1150 EXPORT_SYMBOL(svcsec_accept);
1151 EXPORT_SYMBOL(svcsec_authorize);
1152 EXPORT_SYMBOL(svcsec_alloc_repbuf);
1153 EXPORT_SYMBOL(svcsec_cleanup_req);
1154 EXPORT_SYMBOL(svcsec_get);
1155 EXPORT_SYMBOL(svcsec_put);
1156 EXPORT_SYMBOL(svcsec_alloc_reply_state);
1157 EXPORT_SYMBOL(svcsec_free_reply_state);
1158
1159 EXPORT_SYMBOL(ptlrpcs_name2flavor);
1160 EXPORT_SYMBOL(ptlrpcs_flavor2name);
1161
1162 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
1163 MODULE_DESCRIPTION("Lustre Security Support");
1164 MODULE_LICENSE("GPL");
1165
1166 module_init(ptlrpc_sec_init);
1167 module_exit(ptlrpc_sec_exit);