Whamcloud - gitweb
quite some unnecessary messages and a compiler warning.
[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 static void ptlrpcs_cred_destroy(struct ptlrpc_cred *cred)
139 {
140         struct ptlrpc_sec *sec = cred->pc_sec;
141
142         LASSERT(cred->pc_sec);
143         LASSERT(atomic_read(&cred->pc_refcount) == 0);
144         LASSERT(list_empty(&cred->pc_hash));
145
146         cred->pc_ops->destroy(cred);
147         atomic_dec(&sec->ps_credcount);
148 }
149
150 static void ptlrpcs_destroy_credlist(struct list_head *head)
151 {
152         struct ptlrpc_cred *cred;
153
154         while (!list_empty(head)) {
155                 cred = list_entry(head->next, struct ptlrpc_cred, pc_hash);
156                 list_del_init(&cred->pc_hash);
157                 ptlrpcs_cred_destroy(cred);
158         }
159 }
160
161 static
162 int ptlrpcs_cred_unlink_expired(struct ptlrpc_cred *cred,
163                                 struct list_head *freelist)
164 {
165         LASSERT(cred->pc_sec);
166
167         if (atomic_read(&cred->pc_refcount) != 0)
168                 return 0;
169         if (time_after(cred->pc_expire, get_seconds()))
170                 return 0;
171
172         list_del(&cred->pc_hash);
173         list_add(&cred->pc_hash, freelist);
174         CDEBUG(D_SEC, "put cred %p into freelist\n", cred);
175         return 1;
176 }
177
178 static
179 void ptlrpcs_credcache_gc(struct ptlrpc_sec *sec,
180                           struct list_head *freelist)
181 {
182         struct ptlrpc_cred *cred, *n;
183         int i;
184         ENTRY;
185
186         CDEBUG(D_SEC, "do gc on sec %s\n", sec->ps_type->pst_name);
187         for (i = 0; i < PTLRPC_CREDCACHE_NR; i++) {
188                 list_for_each_entry_safe(cred, n, &sec->ps_credcache[i],
189                                          pc_hash) {
190                         ptlrpcs_cred_unlink_expired(cred, freelist);
191                 }
192         }
193         sec->ps_nextgc = get_seconds() + sec->ps_expire;
194         EXIT;
195 }
196
197 static
198 int ptlrpcs_flush_credcache(struct ptlrpc_sec *sec, int force)
199 {
200         struct ptlrpc_cred *cred, *n;
201         LIST_HEAD(freelist);
202         int i, busy = 0;
203         ENTRY;
204
205         spin_lock(&sec->ps_lock);
206         for (i = 0; i < PTLRPC_CREDCACHE_NR; i++) {
207                 list_for_each_entry_safe(cred, n, &sec->ps_credcache[i],
208                                          pc_hash) {
209                         LASSERT(atomic_read(&cred->pc_refcount) >= 0);
210                         if (atomic_read(&cred->pc_refcount)) {
211                                 busy = 1;
212                                 if (!force)
213                                         continue;
214                                 list_del_init(&cred->pc_hash);
215                         } else
216                                 list_move(&cred->pc_hash, &freelist);
217
218                         /* don't remove CRED_UPTODATE flag here */
219                         cred->pc_flags |= PTLRPC_CRED_DEAD;
220                 }
221         }
222         spin_unlock(&sec->ps_lock);
223         ptlrpcs_destroy_credlist(&freelist);
224         RETURN(busy);
225 }
226
227 /**************************************************
228  * credential APIs                                *
229  **************************************************/
230
231 static inline
232 int ptlrpcs_cred_get_hash(__u64 pag)
233 {
234         LASSERT((pag & PTLRPC_CREDCACHE_MASK) < PTLRPC_CREDCACHE_NR);
235         return (pag & PTLRPC_CREDCACHE_MASK);
236 }
237
238 static
239 struct ptlrpc_cred * cred_cache_lookup(struct ptlrpc_sec *sec,
240                                        struct vfs_cred *vcred,
241                                        int create)
242 {
243         struct ptlrpc_cred *cred, *new = NULL, *n;
244         LIST_HEAD(freelist);
245         int hash, found = 0;
246         ENTRY;
247
248         hash = ptlrpcs_cred_get_hash(vcred->vc_pag);
249
250 retry:
251         spin_lock(&sec->ps_lock);
252         /* do gc if expired */
253         if (time_after(get_seconds(), sec->ps_nextgc))
254                 ptlrpcs_credcache_gc(sec, &freelist);
255
256         list_for_each_entry_safe(cred, n, &sec->ps_credcache[hash], pc_hash) {
257                 if (cred->pc_flags & PTLRPC_CRED_DEAD)
258                         continue;
259                 if (ptlrpcs_cred_unlink_expired(cred, &freelist))
260                         continue;
261                 if (cred->pc_ops->match(cred, vcred)) {
262                         found = 1;
263                         break;
264                 }
265         }
266
267         if (found) {
268                 if (new && new != cred) {
269                         /* lost the race, just free it */
270                         list_add(&new->pc_hash, &freelist);
271                 }
272                 list_move(&cred->pc_hash, &sec->ps_credcache[hash]);
273         } else {
274                 if (new) {
275                         list_add(&new->pc_hash, &sec->ps_credcache[hash]);
276                         cred = new;
277                 } else if (create) {
278                         spin_unlock(&sec->ps_lock);
279                         new = sec->ps_type->pst_ops->create_cred(sec, vcred);
280                         if (new) {
281                                 atomic_inc(&sec->ps_credcount);
282                                 goto retry;
283                         }
284                 } else
285                         cred = NULL;
286         }
287
288         /* hold a ref */
289         if (cred)
290                 atomic_inc(&cred->pc_refcount);
291
292         spin_unlock(&sec->ps_lock);
293
294         ptlrpcs_destroy_credlist(&freelist);
295         RETURN(cred);
296 }
297
298 struct ptlrpc_cred * ptlrpcs_cred_lookup(struct ptlrpc_sec *sec,
299                                          struct vfs_cred *vcred)
300 {
301         struct ptlrpc_cred *cred;
302         ENTRY;
303
304         cred = cred_cache_lookup(sec, vcred, 0);
305         RETURN(cred);
306 }
307
308 int ptlrpcs_req_get_cred(struct ptlrpc_request *req)
309 {
310         struct obd_import *imp = req->rq_import;
311         struct vfs_cred vcred;
312         ENTRY;
313
314         LASSERT(!req->rq_cred);
315         LASSERT(imp);
316         LASSERT(imp->imp_sec);
317
318         /* XXX
319          * for now we simply let PAG == real uid
320          */
321         vcred.vc_pag = (__u64) current->uid;
322         vcred.vc_uid = current->uid;
323
324         req->rq_cred = cred_cache_lookup(imp->imp_sec, &vcred, 1);
325
326         if (!req->rq_cred) {
327                 CERROR("req %p: fail to get cred from cache\n", req);
328                 RETURN(-ENOMEM);
329         }
330
331         RETURN(0);
332 }
333
334 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec);
335
336 void ptlrpcs_cred_put(struct ptlrpc_cred *cred, int sync)
337 {
338         struct ptlrpc_sec *sec = cred->pc_sec;
339
340         LASSERT(cred);
341         LASSERT(sec);
342         LASSERT(atomic_read(&cred->pc_refcount));
343
344         spin_lock(&sec->ps_lock);
345         if (atomic_dec_and_test(&cred->pc_refcount) &&
346             sync && cred->pc_flags & PTLRPC_CRED_DEAD) {
347                 list_del_init(&cred->pc_hash);
348                 ptlrpcs_cred_destroy(cred);
349                 if (!atomic_read(&sec->ps_credcount) &&
350                     !atomic_read(&sec->ps_refcount)) {
351                         CWARN("put last cred on a dead sec %p(%s), "
352                               "also destroy the sec\n", sec,
353                                sec->ps_type->pst_name);
354                         spin_unlock(&sec->ps_lock);
355
356                         ptlrpcs_sec_destroy(sec);
357                         return;
358                 }
359         }
360         spin_unlock(&sec->ps_lock);
361 }
362
363 void ptlrpcs_req_drop_cred(struct ptlrpc_request *req)
364 {
365         ENTRY;
366
367         LASSERT(req);
368         LASSERT(req->rq_cred);
369
370         if (req->rq_cred) {
371                 /* We'd like to not use 'sync' mode, but might cause
372                  * some cred leak. Need more thinking here. FIXME
373                  */
374                 ptlrpcs_cred_put(req->rq_cred, 1);
375                 req->rq_cred = NULL;
376         } else
377                 CDEBUG(D_SEC, "req %p have no cred\n", req);
378         EXIT;
379 }
380
381 /* 
382  * request must have a cred. if failed to get new cred,
383  * just restore the old one
384  */
385 int ptlrpcs_req_replace_dead_cred(struct ptlrpc_request *req)
386 {
387         struct ptlrpc_cred *cred = req->rq_cred;
388         int rc;
389         ENTRY;
390
391         LASSERT(cred);
392         LASSERT(cred->pc_flags & PTLRPC_CRED_DEAD);
393
394         ptlrpcs_cred_get(cred);
395         ptlrpcs_req_drop_cred(req);
396         LASSERT(!req->rq_cred);
397         rc = ptlrpcs_req_get_cred(req);
398         if (!rc) {
399                 LASSERT(req->rq_cred);
400                 LASSERT(req->rq_cred != cred);
401                 ptlrpcs_cred_put(cred, 1);
402         } else {
403                 LASSERT(!req->rq_cred);
404                 req->rq_cred = cred;
405         }
406         RETURN(rc);
407 }
408
409 /*
410  * since there's no lock on the cred, its status could be changed
411  * by other threads at any time, we allow this race.
412  */
413 int ptlrpcs_req_refresh_cred(struct ptlrpc_request *req)
414 {
415         struct ptlrpc_cred *cred = req->rq_cred;
416         ENTRY;
417
418         LASSERT(cred);
419
420         if (ptlrpcs_cred_is_uptodate(cred))
421                 RETURN(0);
422
423         if (cred->pc_flags & PTLRPC_CRED_ERROR) {
424                 req->rq_ptlrpcs_err = 1;
425                 RETURN(-EPERM);
426         }
427
428         if (cred->pc_flags & PTLRPC_CRED_DEAD) {
429                 if (ptlrpcs_req_replace_dead_cred(req) == 0) {
430                         LASSERT(cred != req->rq_cred);
431                         CWARN("req %p: replace cred %p => %p\n",
432                                req, cred, req->rq_cred);
433                         cred = req->rq_cred;
434                 } else {
435                         LASSERT(cred == req->rq_cred);
436                         CERROR("req %p: failed to replace dead cred %p\n",
437                                 req, cred);
438                         RETURN(-ENOMEM);
439                 }
440         }
441
442         ptlrpcs_cred_refresh(cred);
443         if (!ptlrpcs_cred_is_uptodate(cred)) {
444                 if (cred->pc_flags & PTLRPC_CRED_ERROR)
445                         req->rq_ptlrpcs_err = 1;
446
447                 CERROR("req %p: failed to refresh cred %p, fatal %d\n",
448                         req, cred, req->rq_ptlrpcs_err);
449                 RETURN(-EPERM);
450         } else
451                 RETURN(0);
452 }
453
454 int ptlrpcs_cli_wrap_request(struct ptlrpc_request *req)
455 {
456         struct ptlrpc_cred     *cred;
457         int rc;
458         ENTRY;
459
460         LASSERT(req->rq_cred);
461         LASSERT(req->rq_cred->pc_sec);
462         LASSERT(req->rq_cred->pc_ops);
463         LASSERT(req->rq_reqbuf);
464         LASSERT(req->rq_reqbuf_len);
465
466         rc = ptlrpcs_req_refresh_cred(req);
467         if (rc)
468                 RETURN(rc);
469
470         CDEBUG(D_SEC, "wrap req %p\n", req);
471         cred = req->rq_cred;
472
473         switch (cred->pc_sec->ps_sectype) {
474         case PTLRPC_SEC_TYPE_NONE:
475         case PTLRPC_SEC_TYPE_AUTH:
476                 if (req->rq_req_wrapped) {
477                         CDEBUG(D_SEC, "req %p(o%u,x"LPU64",t"LPU64") "
478                                "already signed, resend?\n", req,
479                                req->rq_reqmsg ? req->rq_reqmsg->opc : -1,
480                                req->rq_xid, req->rq_transno);
481                         req->rq_req_wrapped = 0;
482                         req->rq_reqdata_len = sizeof(struct ptlrpcs_wire_hdr) +
483                                               req->rq_reqlen;
484                         LASSERT(req->rq_reqdata_len % 8 == 0);
485                 }
486
487                 LASSERT(cred->pc_ops->sign);
488                 rc = cred->pc_ops->sign(cred, req);
489                 if (!rc)
490                         req->rq_req_wrapped = 1;
491                 break;
492         case PTLRPC_SEC_TYPE_PRIV:
493                 if (req->rq_req_wrapped) {
494                         CDEBUG(D_SEC, "req %p(o%u,x"LPU64",t"LPU64") "
495                                "already encrypted, resend?\n", req,
496                                req->rq_reqmsg ? req->rq_reqmsg->opc : -1,
497                                req->rq_xid, req->rq_transno);
498                         req->rq_req_wrapped = 0;
499                         req->rq_reqdata_len = sizeof(struct ptlrpcs_wire_hdr);
500                         LASSERT(req->rq_reqdata_len % 8 == 0);
501                 }
502
503                 LASSERT(cred->pc_ops->seal);
504                 rc = cred->pc_ops->seal(cred, req);
505                 if (!rc)
506                         req->rq_req_wrapped = 1;
507                 break;
508         default:
509                 LBUG();
510         }
511         LASSERT(req->rq_reqdata_len);
512         LASSERT(req->rq_reqdata_len % 8 == 0);
513         LASSERT(req->rq_reqdata_len >= sizeof(struct ptlrpcs_wire_hdr));
514         LASSERT(req->rq_reqdata_len <= req->rq_reqbuf_len);
515
516         RETURN(rc);
517 }
518
519 /* rq_nob_received is the actual received data length */
520 int ptlrpcs_cli_unwrap_reply(struct ptlrpc_request *req)
521 {
522         struct ptlrpc_cred *cred = req->rq_cred;
523         struct ptlrpc_sec *sec;
524         struct ptlrpcs_wire_hdr *sec_hdr;
525         int rc;
526         ENTRY;
527
528         LASSERT(cred);
529         LASSERT(cred->pc_sec);
530         LASSERT(cred->pc_ops);
531         LASSERT(req->rq_repbuf);
532         
533         if (req->rq_nob_received < sizeof(*sec_hdr)) {
534                 CERROR("req %p: reply size only %d\n",
535                         req, req->rq_nob_received);
536                 RETURN(-EPROTO);
537         }
538
539         sec_hdr = (struct ptlrpcs_wire_hdr *) req->rq_repbuf;
540         sec_hdr->flavor = le32_to_cpu(sec_hdr->flavor);
541         sec_hdr->sectype = le32_to_cpu(sec_hdr->sectype);
542         sec_hdr->msg_len = le32_to_cpu(sec_hdr->msg_len);
543         sec_hdr->sec_len = le32_to_cpu(sec_hdr->sec_len);
544
545         CDEBUG(D_SEC, "req %p, cred %p, flavor %u, sectype %u\n",
546                req, cred, sec_hdr->flavor, sec_hdr->sectype);
547
548         sec = cred->pc_sec;
549         if (sec_hdr->flavor != sec->ps_flavor.flavor) {
550                 CERROR("unmatched flavor %u while expect %u\n",
551                        sec_hdr->flavor, sec->ps_flavor.flavor);
552                 RETURN(-EPROTO);
553         }
554
555         if (sizeof(*sec_hdr) + sec_hdr->msg_len + sec_hdr->sec_len >
556             req->rq_nob_received) {
557                 CERROR("msg %u, sec %u, while only get %d\n",
558                         sec_hdr->msg_len, sec_hdr->sec_len,
559                         req->rq_nob_received);
560                 RETURN(-EPROTO);
561         }
562
563         switch (sec_hdr->sectype) {
564         case PTLRPC_SEC_TYPE_NONE:
565         case PTLRPC_SEC_TYPE_AUTH: {
566                 LASSERT(cred->pc_ops->verify);
567                 rc = cred->pc_ops->verify(cred, req);
568                 LASSERT(rc || req->rq_repmsg || req->rq_ptlrpcs_restart);
569                 break;
570         case PTLRPC_SEC_TYPE_PRIV:
571                 LASSERT(cred->pc_ops->unseal);
572                 rc = cred->pc_ops->unseal(cred, req);
573                 LASSERT(rc || req->rq_repmsg || req->rq_ptlrpcs_restart);
574                 break;
575         }
576         default:
577                 rc = -1;
578                 LBUG();
579         }
580         RETURN(rc);
581 }
582
583 /**************************************************
584  * security APIs                                  *
585  **************************************************/
586
587 struct ptlrpc_sec * ptlrpcs_sec_create(ptlrpcs_flavor_t *flavor,
588                                        struct obd_import *import,
589                                        const char *pipe_dir,
590                                        void *pipe_data)
591 {
592         struct ptlrpc_sec_type *type;
593         struct ptlrpc_sec *sec;
594         ENTRY;
595
596         type = ptlrpcs_flavor2type(flavor);
597         if (!type) {
598                 CDEBUG(D_SEC, "invalid major flavor %u\n", flavor->flavor);
599                 RETURN(NULL);
600         }
601
602         sec = type->pst_ops->create_sec(flavor, pipe_dir, pipe_data);
603         if (sec) {
604                 spin_lock_init(&sec->ps_lock);
605                 ptlrpcs_init_credcache(sec);
606                 sec->ps_type = type;
607                 sec->ps_flavor = *flavor;
608                 sec->ps_import = class_import_get(import);
609                 atomic_set(&sec->ps_refcount, 1);
610                 atomic_set(&sec->ps_credcount, 0);
611                 atomic_inc(&type->pst_inst);
612         } else
613                 ptlrpcs_type_put(type);
614
615         return sec;
616 }
617
618 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec)
619 {
620         struct ptlrpc_sec_type *type = sec->ps_type;
621         struct obd_import *imp = sec->ps_import;
622
623         LASSERT(type && type->pst_ops);
624         LASSERT(type->pst_ops->destroy_sec);
625
626         type->pst_ops->destroy_sec(sec);
627         atomic_dec(&type->pst_inst);
628         ptlrpcs_type_put(type);
629         class_import_put(imp);
630 }
631
632 void ptlrpcs_sec_put(struct ptlrpc_sec *sec)
633 {
634         if (atomic_dec_and_test(&sec->ps_refcount)) {
635                 ptlrpcs_flush_credcache(sec, 1);
636
637                 if (atomic_read(&sec->ps_credcount) == 0) {
638                         ptlrpcs_sec_destroy(sec);
639                 } else {
640                         CWARN("sec %p(%s) is no usage while %d cred still "
641                               "holded, destroy delayed\n",
642                                sec, sec->ps_type->pst_name,
643                                atomic_read(&sec->ps_credcount));
644                 }
645         }
646 }
647
648 void ptlrpcs_sec_invalidate_cache(struct ptlrpc_sec *sec)
649 {
650         ptlrpcs_flush_credcache(sec, 1);
651 }
652
653 int sec_alloc_reqbuf(struct ptlrpc_sec *sec,
654                      struct ptlrpc_request *req,
655                      int msgsize, int secsize)
656 {
657         struct ptlrpcs_wire_hdr *hdr;
658         ENTRY;
659
660         LASSERT(msgsize % 8 == 0);
661         LASSERT(secsize % 8 == 0);
662
663         req->rq_reqbuf_len = sizeof(*hdr) + msgsize + secsize;
664         OBD_ALLOC(req->rq_reqbuf, req->rq_reqbuf_len);
665         if (!req->rq_reqbuf) {
666                 CERROR("can't alloc %d\n", req->rq_reqbuf_len);
667                 RETURN(-ENOMEM);
668         }
669
670         hdr = buf_to_sec_hdr(req->rq_reqbuf);
671         hdr->flavor = cpu_to_le32(sec->ps_flavor.flavor);
672         hdr->sectype = cpu_to_le32(sec->ps_sectype);
673         hdr->msg_len = msgsize;
674         /* security length will be filled later */
675
676         /* later reqdata_len will be added on actual security payload */
677         req->rq_reqdata_len = sizeof(*hdr) + msgsize;
678         req->rq_reqmsg = buf_to_lustre_msg(req->rq_reqbuf);
679
680         CDEBUG(D_SEC, "req %p: rqbuf at %p, len %d, msg %d, sec %d\n",
681                req, req->rq_reqbuf, req->rq_reqbuf_len,
682                msgsize, secsize);
683
684         RETURN(0);
685 }
686
687 /* when complete successfully, req->rq_reqmsg should point to the
688  * right place.
689  */
690 int ptlrpcs_cli_alloc_reqbuf(struct ptlrpc_request *req, int msgsize)
691 {
692         struct ptlrpc_cred *cred = req->rq_cred;
693         struct ptlrpc_sec *sec;
694         struct ptlrpc_secops *ops;
695
696         LASSERT(msgsize % 8 == 0);
697         LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
698         LASSERT(cred);
699         LASSERT(atomic_read(&cred->pc_refcount));
700         LASSERT(cred->pc_sec);
701         LASSERT(cred->pc_sec->ps_type);
702         LASSERT(cred->pc_sec->ps_type->pst_ops);
703         LASSERT(req->rq_reqbuf == NULL);
704         LASSERT(req->rq_reqmsg == NULL);
705
706         sec = cred->pc_sec;
707         ops = sec->ps_type->pst_ops;
708         if (ops->alloc_reqbuf)
709                 return ops->alloc_reqbuf(sec, req, msgsize);
710         else
711                 return sec_alloc_reqbuf(sec, req, msgsize, 0);
712 }
713
714 void sec_free_reqbuf(struct ptlrpc_sec *sec,
715                      struct ptlrpc_request *req)
716 {
717         LASSERT(req->rq_reqbuf);
718         LASSERT(req->rq_reqbuf_len);
719
720         /* sanity check */
721         if (req->rq_reqmsg) {
722                 LASSERT((char *) req->rq_reqmsg >= req->rq_reqbuf &&
723                         (char *) req->rq_reqmsg < req->rq_reqbuf +
724                                                   req->rq_reqbuf_len);
725         }
726
727         OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len);
728         req->rq_reqbuf = NULL;
729         req->rq_reqmsg = NULL;
730 }
731
732 void ptlrpcs_cli_free_reqbuf(struct ptlrpc_request *req)
733 {
734         struct ptlrpc_cred *cred = req->rq_cred;
735         struct ptlrpc_sec *sec;
736         struct ptlrpc_secops *ops;
737
738         LASSERT(cred);
739         LASSERT(atomic_read(&cred->pc_refcount));
740         LASSERT(cred->pc_sec);
741         LASSERT(cred->pc_sec->ps_type);
742         LASSERT(cred->pc_sec->ps_type->pst_ops);
743         LASSERT(req->rq_reqbuf);
744
745         sec = cred->pc_sec;
746         ops = sec->ps_type->pst_ops;
747         if (ops->free_reqbuf)
748                 ops->free_reqbuf(sec, req);
749         else
750                 sec_free_reqbuf(sec, req);
751 }
752
753 int ptlrpcs_cli_alloc_repbuf(struct ptlrpc_request *req, int msgsize)
754 {
755         struct ptlrpc_cred *cred = req->rq_cred;
756         struct ptlrpc_sec *sec;
757         struct ptlrpc_secops *ops;
758         int msg_payload, sec_payload;
759         ENTRY;
760
761         LASSERT(msgsize % 8 == 0);
762         LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
763         LASSERT(cred);
764         LASSERT(atomic_read(&cred->pc_refcount));
765         LASSERT(cred->pc_sec);
766         LASSERT(cred->pc_sec->ps_type);
767         LASSERT(cred->pc_sec->ps_type->pst_ops);
768         LASSERT(req->rq_repbuf == NULL);
769
770         sec = cred->pc_sec;
771         ops = sec->ps_type->pst_ops;
772         if (ops->alloc_repbuf)
773                 RETURN(ops->alloc_repbuf(sec, req, msgsize));
774
775         /* default allocation scheme */
776         msg_payload = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV ? 0 : msgsize;
777         sec_payload = size_round(ptlrpcs_est_rep_payload(sec, msgsize));
778
779         req->rq_repbuf_len = sizeof(struct ptlrpcs_wire_hdr) +
780                              msg_payload + sec_payload;
781         OBD_ALLOC(req->rq_repbuf, req->rq_repbuf_len);
782         if (!req->rq_repbuf)
783                 RETURN(-ENOMEM);
784
785         CDEBUG(D_SEC, "req %p: repbuf at %p, len %d, msg %d, sec %d\n",
786                req, req->rq_repbuf, req->rq_repbuf_len,
787                msg_payload, sec_payload);
788
789         RETURN(0);
790 }
791
792 void ptlrpcs_cli_free_repbuf(struct ptlrpc_request *req)
793 {
794         struct ptlrpc_cred *cred = req->rq_cred;
795         struct ptlrpc_sec *sec;
796         struct ptlrpc_secops *ops;
797         ENTRY;
798
799         LASSERT(cred);
800         LASSERT(atomic_read(&cred->pc_refcount));
801         LASSERT(cred->pc_sec);
802         LASSERT(cred->pc_sec->ps_type);
803         LASSERT(cred->pc_sec->ps_type->pst_ops);
804         LASSERT(req->rq_repbuf);
805
806         sec = cred->pc_sec;
807         ops = sec->ps_type->pst_ops;
808         if (ops->free_repbuf)
809                 ops->free_repbuf(sec, req);
810         else {
811                 OBD_FREE(req->rq_repbuf, req->rq_repbuf_len);
812                 req->rq_repbuf = NULL;
813                 req->rq_repmsg = NULL;
814         }
815         EXIT;
816 }
817
818 int ptlrpcs_import_get_sec(struct obd_import *imp)
819 {
820         ptlrpcs_flavor_t flavor = {PTLRPC_SEC_NULL, 0};
821         char *pipedir = NULL;
822         ENTRY;
823
824         LASSERT(imp->imp_obd);
825         LASSERT(imp->imp_obd->obd_type);
826
827         /* old sec might be still there in reconnecting */
828         if (imp->imp_sec)
829                 RETURN(0);
830
831         /* find actual flavor for client obd. right now server side
832          * obd (reverse imp, etc) will simply use NULL.
833          */
834         if (!strcmp(imp->imp_obd->obd_type->typ_name, "mdc") ||
835             !strcmp(imp->imp_obd->obd_type->typ_name, "osc")) {
836                 struct client_obd *cli = &imp->imp_obd->u.cli;
837
838                 if (cli->cl_sec_flavor == PTLRPC_SEC_GSS) {
839                         CWARN("select security gss/%s for %s(%s)\n",
840                                cli->cl_sec_subflavor == PTLRPC_SEC_GSS_KRB5I ?
841                                "krb5i" : "krb5p",
842                                imp->imp_obd->obd_type->typ_name,
843                                imp->imp_obd->obd_name);
844                         flavor.flavor = cli->cl_sec_flavor;
845                         flavor.subflavor = cli->cl_sec_subflavor;
846                         pipedir = imp->imp_obd->obd_name;
847                 } else if (cli->cl_sec_flavor == PTLRPC_SEC_NULL) {
848                         CWARN("select security null for %s(%s)\n",
849                                imp->imp_obd->obd_type->typ_name,
850                                imp->imp_obd->obd_name);
851                 } else {
852                         CWARN("unknown security flavor for mdc(%s), "
853                               "use 'null'\n", imp->imp_obd->obd_name);
854                 }
855         }
856
857         imp->imp_sec = ptlrpcs_sec_create(&flavor, imp, pipedir, imp);
858         if (!imp->imp_sec)
859                 RETURN(-EINVAL);
860         else
861                 RETURN(0);
862 }
863
864 void ptlrpcs_import_drop_sec(struct obd_import *imp)
865 {
866         ENTRY;
867         if (imp->imp_sec) {
868                 ptlrpcs_sec_put(imp->imp_sec);
869                 imp->imp_sec = NULL;
870         }
871         EXIT;
872 }
873
874 int __init ptlrpc_sec_init(void)
875 {
876         int rc;
877
878         if ((rc = ptlrpcs_null_init()))
879                 return rc;
880
881         if ((rc = svcsec_null_init())) {
882                 ptlrpcs_null_exit();
883                 return rc;
884         }
885
886 #if 0
887 #if !defined __KERNEL__ && defined ENABLE_GSS
888         ptlrpcs_gss_init();
889 #endif
890 #endif
891         return 0;
892 }
893
894 static void __exit ptlrpc_sec_exit(void)
895 {
896         svcsec_null_exit();
897         ptlrpcs_null_exit();
898 }
899
900
901 EXPORT_SYMBOL(ptlrpcs_register);
902 EXPORT_SYMBOL(ptlrpcs_unregister);
903 EXPORT_SYMBOL(ptlrpcs_sec_create);
904 EXPORT_SYMBOL(ptlrpcs_sec_put);
905 EXPORT_SYMBOL(ptlrpcs_sec_invalidate_cache);
906 EXPORT_SYMBOL(ptlrpcs_import_get_sec);
907 EXPORT_SYMBOL(ptlrpcs_import_drop_sec);
908 EXPORT_SYMBOL(ptlrpcs_cred_lookup);
909 EXPORT_SYMBOL(ptlrpcs_cred_put);
910 EXPORT_SYMBOL(ptlrpcs_req_get_cred);
911 EXPORT_SYMBOL(ptlrpcs_req_drop_cred);
912 EXPORT_SYMBOL(ptlrpcs_req_replace_dead_cred);
913 EXPORT_SYMBOL(ptlrpcs_req_refresh_cred);
914 EXPORT_SYMBOL(ptlrpcs_cli_alloc_reqbuf);
915 EXPORT_SYMBOL(ptlrpcs_cli_free_reqbuf);
916 EXPORT_SYMBOL(ptlrpcs_cli_alloc_repbuf);
917 EXPORT_SYMBOL(ptlrpcs_cli_free_repbuf);
918 EXPORT_SYMBOL(ptlrpcs_cli_wrap_request);
919 EXPORT_SYMBOL(ptlrpcs_cli_unwrap_reply);
920 EXPORT_SYMBOL(sec_alloc_reqbuf);
921 EXPORT_SYMBOL(sec_free_reqbuf);
922
923 EXPORT_SYMBOL(svcsec_register);
924 EXPORT_SYMBOL(svcsec_unregister);
925 EXPORT_SYMBOL(svcsec_accept);
926 EXPORT_SYMBOL(svcsec_authorize);
927 EXPORT_SYMBOL(svcsec_alloc_repbuf);
928 EXPORT_SYMBOL(svcsec_cleanup_req);
929 EXPORT_SYMBOL(svcsec_get);
930 EXPORT_SYMBOL(svcsec_put);
931 EXPORT_SYMBOL(svcsec_alloc_reply_state);
932 EXPORT_SYMBOL(svcsec_free_reply_state);
933
934 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
935 MODULE_DESCRIPTION("Lustre Security Support");
936 MODULE_LICENSE("GPL");
937
938 module_init(ptlrpc_sec_init);
939 module_exit(ptlrpc_sec_exit);