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