1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2004 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
23 # define EXPORT_SYMTAB
25 #define DEBUG_SUBSYSTEM S_SEC
27 #include <linux/init.h>
28 #include <linux/module.h>
29 #include <linux/slab.h>
31 #include <liblustre.h>
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>
43 static spinlock_t sectypes_lock = SPIN_LOCK_UNLOCKED;
44 static struct ptlrpc_sec_type *sectypes[PTLRPC_SEC_MAX_FLAVORS] = {
48 int ptlrpcs_register(struct ptlrpc_sec_type *type)
50 __u32 flavor = type->pst_flavor.flavor;
52 LASSERT(type->pst_name);
53 LASSERT(type->pst_ops);
55 if (flavor >= PTLRPC_SEC_MAX_FLAVORS)
58 spin_lock(§ypes_lock);
59 if (sectypes[flavor]) {
60 spin_unlock(§ypes_lock);
63 sectypes[flavor] = type;
64 atomic_set(&type->pst_inst, 0);
65 spin_unlock(§ypes_lock);
67 CWARN("Security module %s registered\n", type->pst_name);
71 int ptlrpcs_unregister(struct ptlrpc_sec_type *type)
73 __u32 flavor = type->pst_flavor.flavor;
75 if (flavor >= PTLRPC_SEC_MAX_FLAVORS)
78 spin_lock(§ypes_lock);
79 if (!sectypes[flavor]) {
80 spin_unlock(§ypes_lock);
84 if (sectypes[flavor] != type) {
85 CERROR("invalid unregister\n");
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(§ypes_lock);
96 CDEBUG(D_SEC, "Security module %s unregistered\n", type->pst_name);
97 sectypes[flavor] = NULL;
98 spin_unlock(§ypes_lock);
104 struct ptlrpc_sec_type * ptlrpcs_flavor2type(ptlrpcs_flavor_t *flavor)
106 struct ptlrpc_sec_type *type;
107 __u32 major = flavor->flavor;
109 if (major >= PTLRPC_SEC_MAX_FLAVORS)
112 spin_lock(§ypes_lock);
113 type = sectypes[major];
114 if (type && !try_module_get(type->pst_owner))
116 spin_unlock(§ypes_lock);
121 void ptlrpcs_type_put(struct ptlrpc_sec_type *type)
123 module_put(type->pst_owner);
126 /***********************************************
127 * credential cache helpers *
128 ***********************************************/
130 void ptlrpcs_init_credcache(struct ptlrpc_sec *sec)
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);
138 static void ptlrpcs_cred_destroy(struct ptlrpc_cred *cred)
140 struct ptlrpc_sec *sec = cred->pc_sec;
142 LASSERT(cred->pc_sec);
143 LASSERT(atomic_read(&cred->pc_refcount) == 0);
144 LASSERT(list_empty(&cred->pc_hash));
146 cred->pc_ops->destroy(cred);
147 atomic_dec(&sec->ps_credcount);
150 static void ptlrpcs_destroy_credlist(struct list_head *head)
152 struct ptlrpc_cred *cred;
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);
162 int ptlrpcs_cred_unlink_expired(struct ptlrpc_cred *cred,
163 struct list_head *freelist)
165 LASSERT(cred->pc_sec);
167 /* only unlink non-busy entries */
168 if (atomic_read(&cred->pc_refcount) != 0)
170 /* expire is 0 means never expire. a newly created gss cred
171 * which during upcall also has 0 expiration
173 if (cred->pc_expire == 0)
175 /* check real expiration */
176 if (time_after(cred->pc_expire, get_seconds()))
179 LASSERT((cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) ==
180 PTLRPC_CRED_UPTODATE);
181 CWARN("cred %p: get expired, unlink\n", cred);
183 list_del(&cred->pc_hash);
184 list_add(&cred->pc_hash, freelist);
189 void ptlrpcs_credcache_gc(struct ptlrpc_sec *sec,
190 struct list_head *freelist)
192 struct ptlrpc_cred *cred, *n;
196 CDEBUG(D_SEC, "do gc on sec %s\n", sec->ps_type->pst_name);
197 for (i = 0; i < PTLRPC_CREDCACHE_NR; i++) {
198 list_for_each_entry_safe(cred, n, &sec->ps_credcache[i],
200 if (cred->pc_flags & (PTLRPC_CRED_DEAD |
201 PTLRPC_CRED_ERROR)) {
202 LASSERT(atomic_read(&cred->pc_refcount));
205 ptlrpcs_cred_unlink_expired(cred, freelist);
208 sec->ps_nextgc = get_seconds() + sec->ps_expire;
213 * grace: mark cred DEAD, allow graceful destroy like notify
215 * force: flush all entries, otherwise only free ones be flushed.
218 int ptlrpcs_flush_credcache(struct ptlrpc_sec *sec, int grace, int force)
220 struct ptlrpc_cred *cred, *n;
225 spin_lock(&sec->ps_lock);
226 for (i = 0; i < PTLRPC_CREDCACHE_NR; i++) {
227 list_for_each_entry_safe(cred, n, &sec->ps_credcache[i],
229 LASSERT(atomic_read(&cred->pc_refcount) >= 0);
230 if (atomic_read(&cred->pc_refcount)) {
234 list_del_init(&cred->pc_hash);
236 list_move(&cred->pc_hash, &freelist);
238 cred->pc_flags |= PTLRPC_CRED_DEAD;
240 cred->pc_flags &= ~PTLRPC_CRED_UPTODATE;
243 spin_unlock(&sec->ps_lock);
244 ptlrpcs_destroy_credlist(&freelist);
248 /**************************************************
250 **************************************************/
253 int ptlrpcs_cred_get_hash(__u64 pag)
255 LASSERT((pag & PTLRPC_CREDCACHE_MASK) < PTLRPC_CREDCACHE_NR);
256 return (pag & PTLRPC_CREDCACHE_MASK);
260 struct ptlrpc_cred * cred_cache_lookup(struct ptlrpc_sec *sec,
261 struct vfs_cred *vcred,
264 struct ptlrpc_cred *cred, *new = NULL, *n;
269 hash = ptlrpcs_cred_get_hash(vcred->vc_pag);
272 spin_lock(&sec->ps_lock);
273 /* do gc if expired */
274 if (time_after(get_seconds(), sec->ps_nextgc))
275 ptlrpcs_credcache_gc(sec, &freelist);
277 list_for_each_entry_safe(cred, n, &sec->ps_credcache[hash], pc_hash) {
278 /* for DEAD and ERROR entries, its final put will
279 * release them, so we simply skip here.
281 if (cred->pc_flags & (PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR)) {
282 LASSERT(atomic_read(&cred->pc_refcount));
285 if (ptlrpcs_cred_unlink_expired(cred, &freelist))
287 if (cred->pc_ops->match(cred, vcred)) {
294 if (new && new != cred) {
295 /* lost the race, just free it */
296 list_add(&new->pc_hash, &freelist);
298 list_move(&cred->pc_hash, &sec->ps_credcache[hash]);
301 list_add(&new->pc_hash, &sec->ps_credcache[hash]);
304 spin_unlock(&sec->ps_lock);
305 new = sec->ps_type->pst_ops->create_cred(sec, vcred);
307 atomic_inc(&sec->ps_credcount);
316 atomic_inc(&cred->pc_refcount);
318 spin_unlock(&sec->ps_lock);
320 ptlrpcs_destroy_credlist(&freelist);
324 struct ptlrpc_cred * ptlrpcs_cred_lookup(struct ptlrpc_sec *sec,
325 struct vfs_cred *vcred)
327 struct ptlrpc_cred *cred;
330 cred = cred_cache_lookup(sec, vcred, 0);
334 static struct ptlrpc_cred *get_cred(struct ptlrpc_sec *sec)
336 struct vfs_cred vcred;
340 * for now we simply let PAG == real uid
342 vcred.vc_pag = (__u64) current->uid;
343 vcred.vc_uid = current->uid;
345 return cred_cache_lookup(sec, &vcred, 1);
348 int ptlrpcs_req_get_cred(struct ptlrpc_request *req)
350 struct obd_import *imp = req->rq_import;
353 LASSERT(!req->rq_cred);
356 req->rq_cred = get_cred(imp->imp_sec);
359 CERROR("req %p: fail to get cred from cache\n", req);
367 * check whether current user have valid credential for an import or not.
368 * might repeatedly try in case of non-fatal errors.
369 * return 0 on success, 1 on failure
371 int ptlrpcs_check_cred(struct obd_import *imp)
373 struct ptlrpc_cred *cred;
377 cred = get_cred(imp->imp_sec);
381 if (ptlrpcs_cred_is_uptodate(cred)) {
382 if (!ptlrpcs_cred_check_expire(cred)) {
383 ptlrpcs_cred_put(cred, 1);
386 ptlrpcs_cred_put(cred, 1);
391 ptlrpcs_cred_refresh(cred);
392 if (ptlrpcs_cred_is_uptodate(cred)) {
393 ptlrpcs_cred_put(cred, 1);
397 if (cred->pc_flags & PTLRPC_CRED_ERROR ||
398 !imp->imp_replayable) {
399 ptlrpcs_cred_put(cred, 1);
403 ptlrpcs_cred_put(cred, 1);
405 if (signal_pending(current)) {
406 CWARN("%s: interrupted\n", current->comm);
412 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec);
414 void ptlrpcs_cred_put(struct ptlrpc_cred *cred, int sync)
416 struct ptlrpc_sec *sec = cred->pc_sec;
420 LASSERT(atomic_read(&cred->pc_refcount));
422 spin_lock(&sec->ps_lock);
423 if (atomic_dec_and_test(&cred->pc_refcount) && sync &&
424 cred->pc_flags & (PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR)) {
425 list_del_init(&cred->pc_hash);
426 ptlrpcs_cred_destroy(cred);
427 if (!atomic_read(&sec->ps_credcount) &&
428 !atomic_read(&sec->ps_refcount)) {
429 CWARN("put last cred on a dead sec %p(%s), "
430 "also destroy the sec\n", sec,
431 sec->ps_type->pst_name);
432 spin_unlock(&sec->ps_lock);
434 ptlrpcs_sec_destroy(sec);
438 spin_unlock(&sec->ps_lock);
441 void ptlrpcs_req_drop_cred(struct ptlrpc_request *req)
446 LASSERT(req->rq_cred);
449 /* We'd like to not use 'sync' mode, but might cause
450 * some cred leak. Need more thinking here. FIXME
452 ptlrpcs_cred_put(req->rq_cred, 1);
455 CDEBUG(D_SEC, "req %p have no cred\n", req);
460 * request must have a cred. if failed to get new cred,
461 * just restore the old one
463 int ptlrpcs_req_replace_dead_cred(struct ptlrpc_request *req)
465 struct ptlrpc_cred *cred = req->rq_cred;
470 LASSERT(cred->pc_flags & PTLRPC_CRED_DEAD);
472 ptlrpcs_cred_get(cred);
473 ptlrpcs_req_drop_cred(req);
474 LASSERT(!req->rq_cred);
475 rc = ptlrpcs_req_get_cred(req);
477 LASSERT(req->rq_cred);
478 LASSERT(req->rq_cred != cred);
479 ptlrpcs_cred_put(cred, 1);
481 LASSERT(!req->rq_cred);
488 * since there's no lock on the cred, its status could be changed
489 * by other threads at any time, we allow this race.
491 int ptlrpcs_req_refresh_cred(struct ptlrpc_request *req)
493 struct ptlrpc_cred *cred = req->rq_cred;
498 if (ptlrpcs_cred_is_uptodate(cred)) {
499 if (!ptlrpcs_cred_check_expire(cred))
503 if (cred->pc_flags & PTLRPC_CRED_ERROR) {
504 req->rq_ptlrpcs_err = 1;
508 if (cred->pc_flags & PTLRPC_CRED_DEAD) {
509 if (ptlrpcs_req_replace_dead_cred(req) == 0) {
510 LASSERT(cred != req->rq_cred);
511 CDEBUG(D_SEC, "req %p: replace cred %p => %p\n",
512 req, cred, req->rq_cred);
515 LASSERT(cred == req->rq_cred);
516 CERROR("req %p: failed to replace dead cred %p\n",
518 req->rq_ptlrpcs_err = 1;
523 ptlrpcs_cred_refresh(cred);
524 if (!ptlrpcs_cred_is_uptodate(cred)) {
525 if (cred->pc_flags & PTLRPC_CRED_ERROR)
526 req->rq_ptlrpcs_err = 1;
528 CERROR("req %p: failed to refresh cred %p, fatal %d\n",
529 req, cred, req->rq_ptlrpcs_err);
535 int ptlrpcs_cli_wrap_request(struct ptlrpc_request *req)
537 struct ptlrpc_cred *cred;
541 LASSERT(req->rq_cred);
542 LASSERT(req->rq_cred->pc_sec);
543 LASSERT(req->rq_cred->pc_ops);
544 LASSERT(req->rq_reqbuf);
545 LASSERT(req->rq_reqbuf_len);
547 rc = ptlrpcs_req_refresh_cred(req);
551 CDEBUG(D_SEC, "wrap req %p\n", req);
554 switch (cred->pc_sec->ps_sectype) {
555 case PTLRPC_SEC_TYPE_NONE:
556 case PTLRPC_SEC_TYPE_AUTH:
557 if (req->rq_req_wrapped) {
558 CDEBUG(D_SEC, "req %p(o%u,x"LPU64",t"LPU64") "
559 "already signed, resend?\n", req,
560 req->rq_reqmsg ? req->rq_reqmsg->opc : -1,
561 req->rq_xid, req->rq_transno);
562 req->rq_req_wrapped = 0;
563 req->rq_reqdata_len = sizeof(struct ptlrpcs_wire_hdr) +
565 LASSERT(req->rq_reqdata_len % 8 == 0);
568 LASSERT(cred->pc_ops->sign);
569 rc = cred->pc_ops->sign(cred, req);
571 req->rq_req_wrapped = 1;
573 case PTLRPC_SEC_TYPE_PRIV:
574 if (req->rq_req_wrapped) {
575 CDEBUG(D_SEC, "req %p(o%u,x"LPU64",t"LPU64") "
576 "already encrypted, resend?\n", req,
577 req->rq_reqmsg ? req->rq_reqmsg->opc : -1,
578 req->rq_xid, req->rq_transno);
579 req->rq_req_wrapped = 0;
580 req->rq_reqdata_len = sizeof(struct ptlrpcs_wire_hdr);
581 LASSERT(req->rq_reqdata_len % 8 == 0);
584 LASSERT(cred->pc_ops->seal);
585 rc = cred->pc_ops->seal(cred, req);
587 req->rq_req_wrapped = 1;
592 LASSERT(req->rq_reqdata_len);
593 LASSERT(req->rq_reqdata_len % 8 == 0);
594 LASSERT(req->rq_reqdata_len >= sizeof(struct ptlrpcs_wire_hdr));
595 LASSERT(req->rq_reqdata_len <= req->rq_reqbuf_len);
600 /* rq_nob_received is the actual received data length */
601 int ptlrpcs_cli_unwrap_reply(struct ptlrpc_request *req)
603 struct ptlrpc_cred *cred = req->rq_cred;
604 struct ptlrpc_sec *sec;
605 struct ptlrpcs_wire_hdr *sec_hdr;
610 LASSERT(cred->pc_sec);
611 LASSERT(cred->pc_ops);
612 LASSERT(req->rq_repbuf);
614 if (req->rq_nob_received < sizeof(*sec_hdr)) {
615 CERROR("req %p: reply size only %d\n",
616 req, req->rq_nob_received);
620 sec_hdr = (struct ptlrpcs_wire_hdr *) req->rq_repbuf;
621 sec_hdr->flavor = le32_to_cpu(sec_hdr->flavor);
622 sec_hdr->sectype = le32_to_cpu(sec_hdr->sectype);
623 sec_hdr->msg_len = le32_to_cpu(sec_hdr->msg_len);
624 sec_hdr->sec_len = le32_to_cpu(sec_hdr->sec_len);
626 CDEBUG(D_SEC, "req %p, cred %p, flavor %u, sectype %u\n",
627 req, cred, sec_hdr->flavor, sec_hdr->sectype);
630 if (sec_hdr->flavor != sec->ps_flavor.flavor) {
631 CERROR("unmatched flavor %u while expect %u\n",
632 sec_hdr->flavor, sec->ps_flavor.flavor);
636 if (sizeof(*sec_hdr) + sec_hdr->msg_len + sec_hdr->sec_len >
637 req->rq_nob_received) {
638 CERROR("msg %u, sec %u, while only get %d\n",
639 sec_hdr->msg_len, sec_hdr->sec_len,
640 req->rq_nob_received);
644 switch (sec_hdr->sectype) {
645 case PTLRPC_SEC_TYPE_NONE:
646 case PTLRPC_SEC_TYPE_AUTH: {
647 LASSERT(cred->pc_ops->verify);
648 rc = cred->pc_ops->verify(cred, req);
649 LASSERT(rc || req->rq_repmsg || req->rq_ptlrpcs_restart);
651 case PTLRPC_SEC_TYPE_PRIV:
652 LASSERT(cred->pc_ops->unseal);
653 rc = cred->pc_ops->unseal(cred, req);
654 LASSERT(rc || req->rq_repmsg || req->rq_ptlrpcs_restart);
664 /**************************************************
666 **************************************************/
668 struct ptlrpc_sec * ptlrpcs_sec_create(ptlrpcs_flavor_t *flavor,
669 struct obd_import *import,
670 const char *pipe_dir,
673 struct ptlrpc_sec_type *type;
674 struct ptlrpc_sec *sec;
677 type = ptlrpcs_flavor2type(flavor);
679 CDEBUG(D_SEC, "invalid major flavor %u\n", flavor->flavor);
683 sec = type->pst_ops->create_sec(flavor, pipe_dir, pipe_data);
685 spin_lock_init(&sec->ps_lock);
686 ptlrpcs_init_credcache(sec);
688 sec->ps_flavor = *flavor;
689 sec->ps_import = class_import_get(import);
690 atomic_set(&sec->ps_refcount, 1);
691 atomic_set(&sec->ps_credcount, 0);
692 atomic_inc(&type->pst_inst);
694 ptlrpcs_type_put(type);
699 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec)
701 struct ptlrpc_sec_type *type = sec->ps_type;
702 struct obd_import *imp = sec->ps_import;
704 LASSERT(type && type->pst_ops);
705 LASSERT(type->pst_ops->destroy_sec);
707 type->pst_ops->destroy_sec(sec);
708 atomic_dec(&type->pst_inst);
709 ptlrpcs_type_put(type);
710 class_import_put(imp);
713 void ptlrpcs_sec_put(struct ptlrpc_sec *sec)
715 if (atomic_dec_and_test(&sec->ps_refcount)) {
716 ptlrpcs_flush_credcache(sec, 1, 1);
718 if (atomic_read(&sec->ps_credcount) == 0) {
719 ptlrpcs_sec_destroy(sec);
721 CWARN("sec %p(%s) is no usage while %d cred still "
722 "holded, destroy delayed\n",
723 sec, sec->ps_type->pst_name,
724 atomic_read(&sec->ps_credcount));
729 void ptlrpcs_sec_invalidate_cache(struct ptlrpc_sec *sec)
731 ptlrpcs_flush_credcache(sec, 0, 1);
734 int sec_alloc_reqbuf(struct ptlrpc_sec *sec,
735 struct ptlrpc_request *req,
736 int msgsize, int secsize)
738 struct ptlrpcs_wire_hdr *hdr;
741 LASSERT(msgsize % 8 == 0);
742 LASSERT(secsize % 8 == 0);
744 req->rq_reqbuf_len = sizeof(*hdr) + msgsize + secsize;
745 OBD_ALLOC(req->rq_reqbuf, req->rq_reqbuf_len);
746 if (!req->rq_reqbuf) {
747 CERROR("can't alloc %d\n", req->rq_reqbuf_len);
751 hdr = buf_to_sec_hdr(req->rq_reqbuf);
752 hdr->flavor = cpu_to_le32(sec->ps_flavor.flavor);
753 hdr->sectype = cpu_to_le32(sec->ps_sectype);
754 hdr->msg_len = msgsize;
755 /* security length will be filled later */
757 /* later reqdata_len will be added on actual security payload */
758 req->rq_reqdata_len = sizeof(*hdr) + msgsize;
759 req->rq_reqmsg = buf_to_lustre_msg(req->rq_reqbuf);
761 CDEBUG(D_SEC, "req %p: rqbuf at %p, len %d, msg %d, sec %d\n",
762 req, req->rq_reqbuf, req->rq_reqbuf_len,
768 /* when complete successfully, req->rq_reqmsg should point to the
771 int ptlrpcs_cli_alloc_reqbuf(struct ptlrpc_request *req, int msgsize)
773 struct ptlrpc_cred *cred = req->rq_cred;
774 struct ptlrpc_sec *sec;
775 struct ptlrpc_secops *ops;
777 LASSERT(msgsize % 8 == 0);
778 LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
780 LASSERT(atomic_read(&cred->pc_refcount));
781 LASSERT(cred->pc_sec);
782 LASSERT(cred->pc_sec->ps_type);
783 LASSERT(cred->pc_sec->ps_type->pst_ops);
784 LASSERT(req->rq_reqbuf == NULL);
785 LASSERT(req->rq_reqmsg == NULL);
788 ops = sec->ps_type->pst_ops;
789 if (ops->alloc_reqbuf)
790 return ops->alloc_reqbuf(sec, req, msgsize);
792 return sec_alloc_reqbuf(sec, req, msgsize, 0);
795 void sec_free_reqbuf(struct ptlrpc_sec *sec,
796 struct ptlrpc_request *req)
798 LASSERT(req->rq_reqbuf);
799 LASSERT(req->rq_reqbuf_len);
802 if (req->rq_reqmsg) {
803 LASSERT((char *) req->rq_reqmsg >= req->rq_reqbuf &&
804 (char *) req->rq_reqmsg < req->rq_reqbuf +
808 OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len);
809 req->rq_reqbuf = NULL;
810 req->rq_reqmsg = NULL;
813 void ptlrpcs_cli_free_reqbuf(struct ptlrpc_request *req)
815 struct ptlrpc_cred *cred = req->rq_cred;
816 struct ptlrpc_sec *sec;
817 struct ptlrpc_secops *ops;
820 LASSERT(atomic_read(&cred->pc_refcount));
821 LASSERT(cred->pc_sec);
822 LASSERT(cred->pc_sec->ps_type);
823 LASSERT(cred->pc_sec->ps_type->pst_ops);
824 LASSERT(req->rq_reqbuf);
827 ops = sec->ps_type->pst_ops;
828 if (ops->free_reqbuf)
829 ops->free_reqbuf(sec, req);
831 sec_free_reqbuf(sec, req);
834 int ptlrpcs_cli_alloc_repbuf(struct ptlrpc_request *req, int msgsize)
836 struct ptlrpc_cred *cred = req->rq_cred;
837 struct ptlrpc_sec *sec;
838 struct ptlrpc_secops *ops;
839 int msg_payload, sec_payload;
842 LASSERT(msgsize % 8 == 0);
843 LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
845 LASSERT(atomic_read(&cred->pc_refcount));
846 LASSERT(cred->pc_sec);
847 LASSERT(cred->pc_sec->ps_type);
848 LASSERT(cred->pc_sec->ps_type->pst_ops);
849 LASSERT(req->rq_repbuf == NULL);
852 ops = sec->ps_type->pst_ops;
853 if (ops->alloc_repbuf)
854 RETURN(ops->alloc_repbuf(sec, req, msgsize));
856 /* default allocation scheme */
857 msg_payload = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV ? 0 : msgsize;
858 sec_payload = size_round(ptlrpcs_est_rep_payload(sec, msgsize));
860 req->rq_repbuf_len = sizeof(struct ptlrpcs_wire_hdr) +
861 msg_payload + sec_payload;
862 OBD_ALLOC(req->rq_repbuf, req->rq_repbuf_len);
866 CDEBUG(D_SEC, "req %p: repbuf at %p, len %d, msg %d, sec %d\n",
867 req, req->rq_repbuf, req->rq_repbuf_len,
868 msg_payload, sec_payload);
873 void ptlrpcs_cli_free_repbuf(struct ptlrpc_request *req)
875 struct ptlrpc_cred *cred = req->rq_cred;
876 struct ptlrpc_sec *sec;
877 struct ptlrpc_secops *ops;
881 LASSERT(atomic_read(&cred->pc_refcount));
882 LASSERT(cred->pc_sec);
883 LASSERT(cred->pc_sec->ps_type);
884 LASSERT(cred->pc_sec->ps_type->pst_ops);
885 LASSERT(req->rq_repbuf);
888 ops = sec->ps_type->pst_ops;
889 if (ops->free_repbuf)
890 ops->free_repbuf(sec, req);
892 OBD_FREE(req->rq_repbuf, req->rq_repbuf_len);
893 req->rq_repbuf = NULL;
894 req->rq_repmsg = NULL;
899 int ptlrpcs_import_get_sec(struct obd_import *imp)
901 ptlrpcs_flavor_t flavor = {PTLRPC_SEC_NULL, 0};
902 char *pipedir = NULL;
905 LASSERT(imp->imp_obd);
906 LASSERT(imp->imp_obd->obd_type);
908 /* old sec might be still there in reconnecting */
912 /* find actual flavor for client obd. right now server side
913 * obd (reverse imp, etc) will simply use NULL.
915 if (!strcmp(imp->imp_obd->obd_type->typ_name, "mdc") ||
916 !strcmp(imp->imp_obd->obd_type->typ_name, "osc")) {
917 struct client_obd *cli = &imp->imp_obd->u.cli;
919 if (cli->cl_sec_flavor == PTLRPC_SEC_GSS) {
920 CWARN("select security gss/%s for %s(%s)\n",
921 cli->cl_sec_subflavor == PTLRPC_SEC_GSS_KRB5I ?
923 imp->imp_obd->obd_type->typ_name,
924 imp->imp_obd->obd_name);
925 flavor.flavor = cli->cl_sec_flavor;
926 flavor.subflavor = cli->cl_sec_subflavor;
927 pipedir = imp->imp_obd->obd_name;
928 } else if (cli->cl_sec_flavor == PTLRPC_SEC_NULL) {
929 CWARN("select security null for %s(%s)\n",
930 imp->imp_obd->obd_type->typ_name,
931 imp->imp_obd->obd_name);
933 CWARN("unknown security flavor for mdc(%s), "
934 "use 'null'\n", imp->imp_obd->obd_name);
938 imp->imp_sec = ptlrpcs_sec_create(&flavor, imp, pipedir, imp);
945 void ptlrpcs_import_drop_sec(struct obd_import *imp)
949 ptlrpcs_sec_put(imp->imp_sec);
955 int __init ptlrpc_sec_init(void)
959 if ((rc = ptlrpcs_null_init()))
962 if ((rc = svcsec_null_init())) {
968 #if !defined __KERNEL__ && defined ENABLE_GSS
975 static void __exit ptlrpc_sec_exit(void)
982 EXPORT_SYMBOL(ptlrpcs_register);
983 EXPORT_SYMBOL(ptlrpcs_unregister);
984 EXPORT_SYMBOL(ptlrpcs_sec_create);
985 EXPORT_SYMBOL(ptlrpcs_sec_put);
986 EXPORT_SYMBOL(ptlrpcs_sec_invalidate_cache);
987 EXPORT_SYMBOL(ptlrpcs_import_get_sec);
988 EXPORT_SYMBOL(ptlrpcs_import_drop_sec);
989 EXPORT_SYMBOL(ptlrpcs_cred_lookup);
990 EXPORT_SYMBOL(ptlrpcs_cred_put);
991 EXPORT_SYMBOL(ptlrpcs_req_get_cred);
992 EXPORT_SYMBOL(ptlrpcs_req_drop_cred);
993 EXPORT_SYMBOL(ptlrpcs_req_replace_dead_cred);
994 EXPORT_SYMBOL(ptlrpcs_req_refresh_cred);
995 EXPORT_SYMBOL(ptlrpcs_check_cred);
996 EXPORT_SYMBOL(ptlrpcs_cli_alloc_reqbuf);
997 EXPORT_SYMBOL(ptlrpcs_cli_free_reqbuf);
998 EXPORT_SYMBOL(ptlrpcs_cli_alloc_repbuf);
999 EXPORT_SYMBOL(ptlrpcs_cli_free_repbuf);
1000 EXPORT_SYMBOL(ptlrpcs_cli_wrap_request);
1001 EXPORT_SYMBOL(ptlrpcs_cli_unwrap_reply);
1002 EXPORT_SYMBOL(sec_alloc_reqbuf);
1003 EXPORT_SYMBOL(sec_free_reqbuf);
1005 EXPORT_SYMBOL(svcsec_register);
1006 EXPORT_SYMBOL(svcsec_unregister);
1007 EXPORT_SYMBOL(svcsec_accept);
1008 EXPORT_SYMBOL(svcsec_authorize);
1009 EXPORT_SYMBOL(svcsec_alloc_repbuf);
1010 EXPORT_SYMBOL(svcsec_cleanup_req);
1011 EXPORT_SYMBOL(svcsec_get);
1012 EXPORT_SYMBOL(svcsec_put);
1013 EXPORT_SYMBOL(svcsec_alloc_reply_state);
1014 EXPORT_SYMBOL(svcsec_free_reply_state);
1016 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
1017 MODULE_DESCRIPTION("Lustre Security Support");
1018 MODULE_LICENSE("GPL");
1020 module_init(ptlrpc_sec_init);
1021 module_exit(ptlrpc_sec_exit);