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