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);
139 * return 1 means we should also destroy the sec structure.
142 static int ptlrpcs_cred_destroy(struct ptlrpc_cred *cred)
144 struct ptlrpc_sec *sec = cred->pc_sec;
147 LASSERT(cred->pc_sec);
148 LASSERT(atomic_read(&cred->pc_refcount) == 0);
149 LASSERT(list_empty(&cred->pc_hash));
151 cred->pc_ops->destroy(cred);
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))
159 spin_unlock(&sec->ps_lock);
163 static void ptlrpcs_destroy_credlist(struct list_head *head)
165 struct ptlrpc_cred *cred;
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);
175 int cred_check_dead(struct ptlrpc_cred *cred,
176 struct list_head *freelist, int removal)
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.
182 if (unlikely(ptlrpcs_cred_is_dead(cred))) {
183 /* don't try to destroy a busy entry */
184 if (atomic_read(&cred->pc_refcount))
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.
197 if (atomic_read(&cred->pc_refcount) != 0)
200 /* expire is 0 means never expire. a newly created gss cred
201 * which during upcall also has 0 expiration
203 if (cred->pc_expire == 0)
206 /* check real expiration */
207 if (time_after(cred->pc_expire, get_seconds()))
210 /* although we'v checked the bit right above, there's still
211 * possibility that somebody else set the bit elsewhere.
213 ptlrpcs_cred_expire(cred);
217 LASSERT(atomic_read(&cred->pc_refcount) >= 0);
218 LASSERT(cred->pc_sec);
219 LASSERT(spin_is_locked(&cred->pc_sec->ps_lock));
222 list_move(&cred->pc_hash, freelist);
228 void ptlrpcs_credcache_gc(struct ptlrpc_sec *sec,
229 struct list_head *freelist)
231 struct ptlrpc_cred *cred, *n;
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],
239 cred_check_dead(cred, freelist, 1);
241 sec->ps_nextgc = get_seconds() + sec->ps_expire;
246 * @uid: which user. "-1" means flush all.
247 * @grace: mark cred DEAD, allow graceful destroy like notify
249 * @force: flush all entries, otherwise only free ones be flushed.
252 int flush_credcache(struct ptlrpc_sec *sec, uid_t uid,
253 int grace, int force)
255 struct ptlrpc_cred *cred, *n;
260 might_sleep_if(grace);
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],
266 LASSERT(atomic_read(&cred->pc_refcount) >= 0);
268 if (uid != -1 && uid != cred->pc_uid)
270 if (atomic_read(&cred->pc_refcount)) {
274 list_del_init(&cred->pc_hash);
276 list_move(&cred->pc_hash, &freelist);
278 set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
280 clear_bit(PTLRPC_CRED_UPTODATE_BIT,
284 spin_unlock(&sec->ps_lock);
286 ptlrpcs_destroy_credlist(&freelist);
290 /**************************************************
292 **************************************************/
295 int ptlrpcs_cred_get_hash(__u64 pag)
297 LASSERT((pag & PTLRPC_CREDCACHE_MASK) < PTLRPC_CREDCACHE_NR);
298 return (pag & PTLRPC_CREDCACHE_MASK);
302 * return an uptodate or newly created cred entry.
305 struct ptlrpc_cred * cred_cache_lookup(struct ptlrpc_sec *sec,
306 struct vfs_cred *vcred,
307 int create, int remove_dead)
309 struct ptlrpc_cred *cred, *new = NULL, *n;
316 hash = ptlrpcs_cred_get_hash(vcred->vc_pag);
319 spin_lock(&sec->ps_lock);
321 /* do gc if expired */
322 if (remove_dead && time_after(get_seconds(), sec->ps_nextgc))
323 ptlrpcs_credcache_gc(sec, &freelist);
325 list_for_each_entry_safe(cred, n, &sec->ps_credcache[hash], pc_hash) {
326 if (cred_check_dead(cred, &freelist, remove_dead))
328 if (cred->pc_ops->match(cred, vcred)) {
335 if (new && new != cred) {
336 /* lost the race, just free it */
337 list_add(&new->pc_hash, &freelist);
339 list_move(&cred->pc_hash, &sec->ps_credcache[hash]);
342 list_add(&new->pc_hash, &sec->ps_credcache[hash]);
345 spin_unlock(&sec->ps_lock);
346 new = sec->ps_type->pst_ops->create_cred(sec, vcred);
348 atomic_inc(&sec->ps_credcount);
357 atomic_inc(&cred->pc_refcount);
359 spin_unlock(&sec->ps_lock);
361 ptlrpcs_destroy_credlist(&freelist);
365 struct ptlrpc_cred * ptlrpcs_cred_lookup(struct ptlrpc_sec *sec,
366 struct vfs_cred *vcred)
368 struct ptlrpc_cred *cred;
371 cred = cred_cache_lookup(sec, vcred, 0, 1);
375 static struct ptlrpc_cred *get_cred(struct ptlrpc_sec *sec)
377 struct vfs_cred vcred;
381 * for now we simply let PAG == real uid
383 vcred.vc_pag = (__u64) current->uid;
384 vcred.vc_uid = current->uid;
386 return cred_cache_lookup(sec, &vcred, 1, 1);
389 int ptlrpcs_req_get_cred(struct ptlrpc_request *req)
391 struct obd_import *imp = req->rq_import;
394 LASSERT(!req->rq_cred);
397 req->rq_cred = get_cred(imp->imp_sec);
400 CERROR("req %p: fail to get cred from cache\n", req);
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
412 int ptlrpcs_check_cred(struct obd_import *imp)
414 struct ptlrpc_cred *cred;
419 cred = get_cred(imp->imp_sec);
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
428 ptlrpcs_cred_put(cred, 1);
432 ptlrpcs_cred_refresh(cred);
433 if (ptlrpcs_cred_is_uptodate(cred)) {
434 ptlrpcs_cred_put(cred, 1);
438 if (cred->pc_flags & PTLRPC_CRED_ERROR ||
439 !imp->imp_replayable) {
440 ptlrpcs_cred_put(cred, 1);
444 ptlrpcs_cred_put(cred, 1);
446 if (signal_pending(current)) {
447 CWARN("%s: interrupted\n", current->comm);
453 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec);
455 void ptlrpcs_cred_put(struct ptlrpc_cred *cred, int sync)
457 struct ptlrpc_sec *sec = cred->pc_sec;
460 LASSERT(atomic_read(&cred->pc_refcount));
462 spin_lock(&sec->ps_lock);
464 /* this has to be protected by ps_lock, because cred cache
465 * management code might increase ref against a 0-refed cred.
467 if (!atomic_dec_and_test(&cred->pc_refcount)) {
468 spin_unlock(&sec->ps_lock);
472 /* if sec already unused, we have to destroy the cred (prevent it
473 * hanging there for ever)
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);
482 if (!list_empty(&cred->pc_hash)) {
483 spin_unlock(&sec->ps_lock);
487 /* if required async, and we reached here, we have to clear
488 * the UPTODATE bit, thus no rpc is needed in destroy procedure.
491 clear_bit(PTLRPC_CRED_UPTODATE_BIT, &cred->pc_flags);
493 spin_unlock(&sec->ps_lock);
495 /* destroy this cred */
496 if (!ptlrpcs_cred_destroy(cred))
499 LASSERT(!atomic_read(&sec->ps_credcount));
500 LASSERT(!atomic_read(&sec->ps_refcount));
502 CWARN("sec %p(%s), put last cred, also destroy the sec\n",
503 sec, sec->ps_type->pst_name);
506 void ptlrpcs_req_drop_cred(struct ptlrpc_request *req)
511 LASSERT(req->rq_cred);
514 /* this could be called with spinlock hold, use async mode */
515 ptlrpcs_cred_put(req->rq_cred, 0);
518 CDEBUG(D_SEC, "req %p have no cred\n", req);
523 * request must have a cred. if failed to get new cred,
524 * just restore the old one
526 int ptlrpcs_req_replace_dead_cred(struct ptlrpc_request *req)
528 struct ptlrpc_cred *cred = req->rq_cred;
533 LASSERT(test_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags));
535 ptlrpcs_cred_get(cred);
536 ptlrpcs_req_drop_cred(req);
537 LASSERT(!req->rq_cred);
538 rc = ptlrpcs_req_get_cred(req);
540 LASSERT(req->rq_cred);
541 LASSERT(req->rq_cred != cred);
542 ptlrpcs_cred_put(cred, 1);
544 LASSERT(!req->rq_cred);
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
557 int ptlrpcs_req_refresh_cred(struct ptlrpc_request *req)
559 struct ptlrpc_cred *cred = req->rq_cred;
564 if (!ptlrpcs_cred_check_uptodate(cred))
567 if (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags)) {
568 req->rq_ptlrpcs_err = 1;
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);
579 LASSERT(cred == req->rq_cred);
580 CERROR("req %p: failed to replace dead cred %p\n",
582 req->rq_ptlrpcs_err = 1;
587 ptlrpcs_cred_refresh(cred);
589 if (!ptlrpcs_cred_is_uptodate(cred)) {
590 if (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags))
591 req->rq_ptlrpcs_err = 1;
593 CERROR("req %p: failed to refresh cred %p, fatal %d\n",
594 req, cred, req->rq_ptlrpcs_err);
600 int ptlrpcs_cli_wrap_request(struct ptlrpc_request *req)
602 struct ptlrpc_cred *cred;
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);
612 rc = ptlrpcs_req_refresh_cred(req);
616 CDEBUG(D_SEC, "wrap req %p\n", req);
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) +
630 LASSERT(req->rq_reqdata_len % 8 == 0);
633 LASSERT(cred->pc_ops->sign);
634 rc = cred->pc_ops->sign(cred, req);
636 req->rq_req_wrapped = 1;
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);
649 LASSERT(cred->pc_ops->seal);
650 rc = cred->pc_ops->seal(cred, req);
652 req->rq_req_wrapped = 1;
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);
665 /* rq_nob_received is the actual received data length */
666 int ptlrpcs_cli_unwrap_reply(struct ptlrpc_request *req)
668 struct ptlrpc_cred *cred = req->rq_cred;
669 struct ptlrpc_sec *sec;
670 struct ptlrpcs_wire_hdr *sec_hdr;
675 LASSERT(cred->pc_sec);
676 LASSERT(cred->pc_ops);
677 LASSERT(req->rq_repbuf);
679 if (req->rq_nob_received < sizeof(*sec_hdr)) {
680 CERROR("req %p: reply size only %d\n",
681 req, req->rq_nob_received);
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);
691 CDEBUG(D_SEC, "req %p, cred %p, flavor %u, sectype %u\n",
692 req, cred, sec_hdr->flavor, sec_hdr->sectype);
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);
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);
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);
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);
729 /**************************************************
731 **************************************************/
733 struct ptlrpc_sec * ptlrpcs_sec_create(ptlrpcs_flavor_t *flavor,
734 struct obd_import *import,
735 const char *pipe_dir,
738 struct ptlrpc_sec_type *type;
739 struct ptlrpc_sec *sec;
742 type = ptlrpcs_flavor2type(flavor);
744 CDEBUG(D_SEC, "invalid major flavor %u\n", flavor->flavor);
748 sec = type->pst_ops->create_sec(flavor, pipe_dir, pipe_data);
750 spin_lock_init(&sec->ps_lock);
751 ptlrpcs_init_credcache(sec);
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);
759 ptlrpcs_type_put(type);
764 static void ptlrpcs_sec_destroy(struct ptlrpc_sec *sec)
766 struct ptlrpc_sec_type *type = sec->ps_type;
767 struct obd_import *imp = sec->ps_import;
769 LASSERT(type && type->pst_ops);
770 LASSERT(type->pst_ops->destroy_sec);
772 type->pst_ops->destroy_sec(sec);
773 atomic_dec(&type->pst_inst);
774 ptlrpcs_type_put(type);
775 class_import_put(imp);
778 void ptlrpcs_sec_put(struct ptlrpc_sec *sec)
782 if (atomic_dec_and_test(&sec->ps_refcount)) {
783 flush_credcache(sec, -1, 1, 1);
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);
791 ptlrpcs_sec_destroy(sec);
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));
801 void ptlrpcs_sec_invalidate_cache(struct ptlrpc_sec *sec)
803 flush_credcache(sec, -1, 0, 1);
806 int sec_alloc_reqbuf(struct ptlrpc_sec *sec,
807 struct ptlrpc_request *req,
808 int msgsize, int secsize)
810 struct ptlrpcs_wire_hdr *hdr;
813 LASSERT(msgsize % 8 == 0);
814 LASSERT(secsize % 8 == 0);
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);
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 */
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);
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,
840 /* when complete successfully, req->rq_reqmsg should point to the
843 int ptlrpcs_cli_alloc_reqbuf(struct ptlrpc_request *req, int msgsize)
845 struct ptlrpc_cred *cred = req->rq_cred;
846 struct ptlrpc_sec *sec;
847 struct ptlrpc_secops *ops;
849 LASSERT(msgsize % 8 == 0);
850 LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
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);
860 ops = sec->ps_type->pst_ops;
861 if (ops->alloc_reqbuf)
862 return ops->alloc_reqbuf(sec, req, msgsize);
864 return sec_alloc_reqbuf(sec, req, msgsize, 0);
867 void sec_free_reqbuf(struct ptlrpc_sec *sec,
868 struct ptlrpc_request *req)
870 LASSERT(req->rq_reqbuf);
871 LASSERT(req->rq_reqbuf_len);
874 if (req->rq_reqmsg) {
875 LASSERT((char *) req->rq_reqmsg >= req->rq_reqbuf &&
876 (char *) req->rq_reqmsg < req->rq_reqbuf +
880 OBD_FREE(req->rq_reqbuf, req->rq_reqbuf_len);
881 req->rq_reqbuf = NULL;
882 req->rq_reqmsg = NULL;
885 void ptlrpcs_cli_free_reqbuf(struct ptlrpc_request *req)
887 struct ptlrpc_cred *cred = req->rq_cred;
888 struct ptlrpc_sec *sec;
889 struct ptlrpc_secops *ops;
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);
899 ops = sec->ps_type->pst_ops;
900 if (ops->free_reqbuf)
901 ops->free_reqbuf(sec, req);
903 sec_free_reqbuf(sec, req);
906 int ptlrpcs_cli_alloc_repbuf(struct ptlrpc_request *req, int msgsize)
908 struct ptlrpc_cred *cred = req->rq_cred;
909 struct ptlrpc_sec *sec;
910 struct ptlrpc_secops *ops;
911 int msg_payload, sec_payload;
914 LASSERT(msgsize % 8 == 0);
915 LASSERT(sizeof(struct ptlrpcs_wire_hdr) % 8 == 0);
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);
924 ops = sec->ps_type->pst_ops;
925 if (ops->alloc_repbuf)
926 RETURN(ops->alloc_repbuf(sec, req, msgsize));
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));
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);
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);
945 void ptlrpcs_cli_free_repbuf(struct ptlrpc_request *req)
947 struct ptlrpc_cred *cred = req->rq_cred;
948 struct ptlrpc_sec *sec;
949 struct ptlrpc_secops *ops;
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);
960 ops = sec->ps_type->pst_ops;
961 if (ops->free_repbuf)
962 ops->free_repbuf(sec, req);
964 OBD_FREE(req->rq_repbuf, req->rq_repbuf_len);
965 req->rq_repbuf = NULL;
966 req->rq_repmsg = NULL;
971 int ptlrpcs_import_get_sec(struct obd_import *imp)
973 ptlrpcs_flavor_t flavor = {PTLRPC_SEC_NULL, 0};
974 char *pipedir = NULL;
977 LASSERT(imp->imp_obd);
978 LASSERT(imp->imp_obd->obd_type);
980 /* old sec might be still there in reconnecting */
984 /* find actual flavor for client obd. right now server side
985 * obd (reverse imp, etc) will simply use NULL.
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;
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 ?
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);
1005 CWARN("unknown security flavor for mdc(%s), "
1006 "use 'null'\n", imp->imp_obd->obd_name);
1010 imp->imp_sec = ptlrpcs_sec_create(&flavor, imp, pipedir, imp);
1017 void ptlrpcs_import_drop_sec(struct obd_import *imp)
1021 ptlrpcs_sec_put(imp->imp_sec);
1022 imp->imp_sec = NULL;
1027 void ptlrpcs_import_flush_creds(struct obd_import *imp, uid_t uid)
1031 class_import_get(imp);
1033 flush_credcache(imp->imp_sec, uid, 1, 1);
1034 class_import_put(imp);
1037 int __init ptlrpc_sec_init(void)
1041 if ((rc = ptlrpcs_null_init()))
1044 if ((rc = svcsec_null_init())) {
1045 ptlrpcs_null_exit();
1050 #if !defined __KERNEL__ && defined ENABLE_GSS
1057 static void __exit ptlrpc_sec_exit(void)
1060 ptlrpcs_null_exit();
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);
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);
1099 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
1100 MODULE_DESCRIPTION("Lustre Security Support");
1101 MODULE_LICENSE("GPL");
1103 module_init(ptlrpc_sec_init);
1104 module_exit(ptlrpc_sec_exit);