1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Modifications for Lustre
5 * Copyright 2004, Cluster File Systems, Inc.
7 * Author: Eric Mei <ericm@clusterfs.com>
11 * linux/net/sunrpc/auth_gss.c
13 * RPCSEC_GSS client authentication.
15 * Copyright (c) 2000 The Regents of the University of Michigan.
16 * All rights reserved.
18 * Dug Song <dugsong@monkey.org>
19 * Andy Adamson <andros@umich.edu>
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. Neither the name of the University nor the names of its
31 * contributors may be used to endorse or promote products derived
32 * from this software without specific prior written permission.
34 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
35 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 # define EXPORT_SYMTAB
51 #define DEBUG_SUBSYSTEM S_SEC
53 #include <linux/init.h>
54 #include <linux/module.h>
55 #include <linux/slab.h>
56 #include <linux/dcache.h>
58 #include <linux/random.h>
61 #include <linux/sunrpc/rpc_pipe_fs.h>
63 #include <liblustre.h>
66 #include <libcfs/kp30.h>
67 #include <linux/obd.h>
68 #include <linux/obd_class.h>
69 #include <linux/obd_support.h>
70 #include <linux/lustre_idl.h>
71 #include <linux/lustre_net.h>
72 #include <linux/lustre_import.h>
73 #include <linux/lustre_sec.h>
76 #include "gss_internal.h"
79 #define GSS_CREDCACHE_EXPIRE (60) /* 1 minute */
80 #define GSS_CRED_EXPIRE (8 * 60 * 60) /* 8 hours */
81 #define GSS_CRED_SIGN_SIZE (1024)
82 #define GSS_CRED_VERIFY_SIZE (56)
84 #define LUSTRE_PIPEDIR "/lustre"
86 /**********************************************
87 * gss security init/fini helper *
88 **********************************************/
90 #define SECINIT_RPC_TIMEOUT (30)
91 #define SECFINI_RPC_TIMEOUT (30)
93 static int secinit_compose_request(struct obd_import *imp,
94 char *buf, int bufsize,
100 struct ptlrpcs_wire_hdr *hdr;
101 struct lustre_msg *lmsg;
102 struct mds_req_sec_desc *secdesc;
103 int size = sizeof(*secdesc);
107 lmsg_size = lustre_msg_size(1, &size);
109 if (sizeof(*hdr) + lmsg_size + size_round(token_size) > bufsize) {
110 CERROR("token size %ld too large\n", token_size);
114 /* security wire hdr */
115 hdr = buf_to_sec_hdr(buf);
116 hdr->flavor = cpu_to_le32(PTLRPC_SEC_GSS);
117 hdr->sectype = cpu_to_le32(PTLRPC_SEC_TYPE_NONE);
118 hdr->msg_len = cpu_to_le32(lmsg_size);
119 hdr->sec_len = cpu_to_le32(8 * 4 + token_size);
121 /* lustre message & secdesc */
122 lmsg = buf_to_lustre_msg(buf);
124 lustre_init_msg(lmsg, 1, &size, NULL);
125 secdesc = lustre_msg_buf(lmsg, 0, size);
126 secdesc->rsd_uid = secdesc->rsd_fsuid = uid;
127 secdesc->rsd_gid = secdesc->rsd_fsgid = gid;
128 secdesc->rsd_cap = secdesc->rsd_ngroups = 0;
130 lmsg->handle = imp->imp_remote_handle;
131 lmsg->type = PTL_RPC_MSG_REQUEST;
132 lmsg->opc = SEC_INIT;
134 lmsg->conn_cnt = imp->imp_conn_cnt;
136 p = (__u32 *) (buf + sizeof(*hdr) + lmsg_size);
139 *p++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* gss version */
140 *p++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I); /* subflavor */
141 *p++ = cpu_to_le32(PTLRPC_GSS_PROC_INIT); /* proc */
142 *p++ = cpu_to_le32(0); /* seq */
143 *p++ = cpu_to_le32(PTLRPC_GSS_SVC_NONE); /* service */
144 *p++ = cpu_to_le32(0); /* context handle */
146 /* plus lustre svc type */
147 *p++ = cpu_to_le32(lustre_srv);
149 /* now the token part */
150 *p++ = cpu_to_le32((__u32) token_size);
151 LASSERT(((char *)p - buf) + token_size <= bufsize);
153 rc = copy_from_user(p, token, token_size);
155 CERROR("can't copy token\n");
159 rc = size_round(((char *)p - buf) + token_size);
163 static int secinit_parse_reply(char *repbuf, int replen,
164 char __user *outbuf, long outlen)
166 __u32 *p = (__u32 *)repbuf;
167 struct ptlrpcs_wire_hdr *hdr = (struct ptlrpcs_wire_hdr *) repbuf;
168 __u32 lmsg_len, sec_len, status;
169 __u32 major, minor, seq, obj_len, round_len;
172 if (replen <= (4 + 6) * 4) {
173 CERROR("reply size %d too small\n", replen);
177 hdr->flavor = le32_to_cpu(hdr->flavor);
178 hdr->sectype = le32_to_cpu(hdr->sectype);
179 hdr->msg_len = le32_to_cpu(hdr->msg_len);
180 hdr->sec_len = le32_to_cpu(hdr->sec_len);
182 lmsg_len = le32_to_cpu(p[2]);
183 sec_len = le32_to_cpu(p[3]);
186 if (hdr->flavor != PTLRPC_SEC_GSS ||
187 hdr->sectype != PTLRPC_SEC_TYPE_NONE) {
188 CERROR("unexpected reply\n");
191 if (hdr->msg_len % 8 ||
192 sizeof(*hdr) + hdr->msg_len + hdr->sec_len > replen) {
193 CERROR("unexpected reply\n");
196 if (hdr->sec_len > outlen) {
197 CERROR("outbuf too small\n");
201 p = (__u32 *) buf_to_sec_data(repbuf);
204 status = le32_to_cpu(*p++);
205 major = le32_to_cpu(*p++);
206 minor = le32_to_cpu(*p++);
207 seq = le32_to_cpu(*p++);
210 if (copy_to_user(outbuf, &status, 4))
213 if (copy_to_user(outbuf, &major, 4))
216 if (copy_to_user(outbuf, &minor, 4))
219 if (copy_to_user(outbuf, &seq, 4))
223 obj_len = le32_to_cpu(*p++);
224 round_len = (obj_len + 3) & ~ 3;
225 if (copy_to_user(outbuf, &obj_len, 4))
228 if (copy_to_user(outbuf, (char *)p, round_len))
232 effective += 4 + round_len;
234 obj_len = le32_to_cpu(*p++);
235 round_len = (obj_len + 3) & ~ 3;
236 if (copy_to_user(outbuf, &obj_len, 4))
239 if (copy_to_user(outbuf, (char *)p, round_len))
243 effective += 4 + round_len;
248 /* XXX move to where lgssd could see */
249 struct lgssd_ioctl_param {
250 int version; /* in */
252 int lustre_svc; /* in */
255 long send_token_size;/* in */
256 char *send_token; /* in */
257 long reply_buf_size; /* in */
258 char *reply_buf; /* in */
259 long status; /* out */
260 long reply_length; /* out */
263 static int gss_send_secinit_rpc(__user char *buffer, unsigned long count)
265 struct obd_import *imp;
266 struct ptlrpc_request *request = NULL;
267 struct lgssd_ioctl_param param;
268 const int reqbuf_size = 1024;
269 const int repbuf_size = 1024;
270 char *reqbuf, *repbuf;
271 struct obd_device *obd;
274 int rc, reqlen, replen;
276 if (count != sizeof(param)) {
277 CERROR("ioctl size %lu, expect %d, please check lgssd version\n",
278 count, sizeof(param));
281 if (copy_from_user(¶m, buffer, sizeof(param))) {
282 CERROR("failed copy data from lgssd\n");
286 if (param.version != GSSD_INTERFACE_VERSION) {
287 CERROR("gssd interface version %d (expect %d)\n",
288 param.version, GSSD_INTERFACE_VERSION);
293 if (strncpy_from_user(obdname, param.uuid,
294 sizeof(obdname)) <= 0) {
295 CERROR("Invalid obdname pointer\n");
299 obd = class_name2obd(obdname);
301 CERROR("no such obd %s\n", obdname);
305 imp = class_import_get(obd->u.cli.cl_import);
307 OBD_ALLOC(reqbuf, reqbuf_size);
308 OBD_ALLOC(repbuf, reqbuf_size);
310 if (!reqbuf || !repbuf) {
311 CERROR("Can't alloc buffer: %p/%p\n", reqbuf, repbuf);
312 param.status = -ENOMEM;
317 reqlen = secinit_compose_request(imp, reqbuf, reqbuf_size,
319 param.uid, param.gid,
320 param.send_token_size,
323 param.status = reqlen;
327 request = ptl_do_rawrpc(imp, reqbuf, reqbuf_size, reqlen,
328 repbuf, repbuf_size, &replen,
329 SECINIT_RPC_TIMEOUT, &rc);
330 if (request == NULL || rc) {
335 if (replen > param.reply_buf_size) {
336 CERROR("output buffer size %ld too small, need %d\n",
337 param.reply_buf_size, replen);
338 param.status = -EINVAL;
342 lsize = secinit_parse_reply(repbuf, replen,
343 param.reply_buf, param.reply_buf_size);
345 param.status = (int) lsize;
350 param.reply_length = lsize;
353 if (copy_to_user(buffer, ¶m, sizeof(param)))
358 class_import_put(imp);
359 if (request == NULL) {
361 OBD_FREE(repbuf, repbuf_size);
363 OBD_FREE(reqbuf, reqbuf_size);
365 rawrpc_req_finished(request);
370 /**********************************************
371 * structure definitions *
372 **********************************************/
374 struct ptlrpc_sec gs_base;
375 struct gss_api_mech *gs_mech;
378 struct list_head gs_upcalls;
380 struct dentry *gs_depipe;
386 static rwlock_t gss_ctx_lock = RW_LOCK_UNLOCKED;
388 struct gss_upcall_msg_data {
396 struct gss_upcall_msg {
397 struct rpc_pipe_msg gum_base;
398 atomic_t gum_refcount;
399 struct list_head gum_list;
400 struct gss_sec *gum_gsec;
401 wait_queue_head_t gum_waitq;
402 char gum_obdname[64];
403 struct gss_upcall_msg_data gum_data;
406 /**********************************************
407 * rpc_pipe upcall helpers *
408 **********************************************/
410 void gss_release_msg(struct gss_upcall_msg *gmsg)
413 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
415 if (!atomic_dec_and_test(&gmsg->gum_refcount)) {
416 CDEBUG(D_SEC, "gmsg %p ref %d\n", gmsg,
417 atomic_read(&gmsg->gum_refcount));
421 LASSERT(list_empty(&gmsg->gum_list));
422 LASSERT(list_empty(&gmsg->gum_base.list));
423 OBD_FREE(gmsg, sizeof(*gmsg));
428 gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg)
431 if (list_empty(&gmsg->gum_list)) {
436 list_del_init(&gmsg->gum_list);
437 wake_up(&gmsg->gum_waitq);
438 atomic_dec(&gmsg->gum_refcount);
439 CDEBUG(D_SEC, "gmsg %p refcount now %d\n",
440 gmsg, atomic_read(&gmsg->gum_refcount));
441 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
446 gss_unhash_msg(struct gss_upcall_msg *gmsg)
448 struct gss_sec *gsec = gmsg->gum_gsec;
450 spin_lock(&gsec->gs_lock);
451 gss_unhash_msg_nolock(gmsg);
452 spin_unlock(&gsec->gs_lock);
456 struct gss_upcall_msg * gss_find_upcall(struct gss_sec *gsec,
458 struct gss_upcall_msg_data *gmd)
460 struct gss_upcall_msg *gmsg;
463 list_for_each_entry(gmsg, &gsec->gs_upcalls, gum_list) {
464 if (memcmp(&gmsg->gum_data, gmd, sizeof(*gmd)))
466 if (strcmp(gmsg->gum_obdname, obdname))
468 atomic_inc(&gmsg->gum_refcount);
469 CDEBUG(D_SEC, "found gmsg at %p: obdname %s, uid %d, ref %d\n",
470 gmsg, obdname, gmd->gum_uid,
471 atomic_read(&gmsg->gum_refcount));
477 static void gss_init_upcall_msg(struct gss_upcall_msg *gmsg,
478 struct gss_sec *gsec, char *obdname,
479 struct gss_upcall_msg_data *gmd)
481 struct rpc_pipe_msg *rpcmsg;
484 /* 2 refs: 1 for hash, 1 for current user */
485 init_waitqueue_head(&gmsg->gum_waitq);
486 list_add(&gmsg->gum_list, &gsec->gs_upcalls);
487 atomic_set(&gmsg->gum_refcount, 2);
488 gmsg->gum_gsec = gsec;
489 strncpy(gmsg->gum_obdname, obdname, sizeof(gmsg->gum_obdname));
490 memcpy(&gmsg->gum_data, gmd, sizeof(*gmd));
492 rpcmsg = &gmsg->gum_base;
493 rpcmsg->data = &gmsg->gum_data;
494 rpcmsg->len = sizeof(gmsg->gum_data);
497 #endif /* __KERNEL__ */
499 /********************************************
500 * gss cred manipulation helpers *
501 ********************************************/
504 int gss_cred_is_uptodate_ctx(struct ptlrpc_cred *cred)
506 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
509 read_lock(&gss_ctx_lock);
510 if (((cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) ==
511 PTLRPC_CRED_UPTODATE) &&
514 read_unlock(&gss_ctx_lock);
520 struct gss_cl_ctx * gss_get_ctx(struct gss_cl_ctx *ctx)
522 atomic_inc(&ctx->gc_refcount);
527 void gss_destroy_ctx(struct gss_cl_ctx *ctx)
531 CDEBUG(D_SEC, "destroy cl_ctx %p\n", ctx);
533 kgss_delete_sec_context(&ctx->gc_gss_ctx);
535 if (ctx->gc_wire_ctx.len > 0) {
536 OBD_FREE(ctx->gc_wire_ctx.data, ctx->gc_wire_ctx.len);
537 ctx->gc_wire_ctx.len = 0;
540 OBD_FREE(ctx, sizeof(*ctx));
544 void gss_put_ctx(struct gss_cl_ctx *ctx)
546 if (atomic_dec_and_test(&ctx->gc_refcount))
547 gss_destroy_ctx(ctx);
551 struct gss_cl_ctx *gss_cred_get_ctx(struct ptlrpc_cred *cred)
553 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
554 struct gss_cl_ctx *ctx = NULL;
556 read_lock(&gss_ctx_lock);
558 ctx = gss_get_ctx(gcred->gc_ctx);
559 read_unlock(&gss_ctx_lock);
564 void gss_cred_set_ctx(struct ptlrpc_cred *cred, struct gss_cl_ctx *ctx)
566 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
567 struct gss_cl_ctx *old;
571 if (kgss_inquire_context(ctx->gc_gss_ctx, &ctx_expiry)) {
572 CERROR("unable to get expire time\n");
573 ctx_expiry = 1; /* make it expired now */
575 cred->pc_expire = (unsigned long) ctx_expiry;
577 write_lock(&gss_ctx_lock);
580 cred->pc_flags |= PTLRPC_CRED_UPTODATE;
581 write_unlock(&gss_ctx_lock);
585 CDEBUG(D_SEC, "client refreshed gss cred %p(uid %u)\n",
591 simple_get_bytes(char **buf, __u32 *buflen, void *res, __u32 reslen)
593 if (*buflen < reslen) {
594 CERROR("buflen %u < %u\n", *buflen, reslen);
598 memcpy(res, *buf, reslen);
608 * - wire_ctx (rawobj)
609 * - mech_ctx? (rawobj)
612 int gss_parse_init_downcall(struct gss_api_mech *gm, rawobj_t *buf,
613 struct gss_cl_ctx **gc,
614 struct gss_upcall_msg_data *gmd, int *gss_err)
616 char *p = (char *)buf->data;
617 struct gss_cl_ctx *ctx;
618 __u32 len = buf->len;
619 unsigned int timeout;
627 OBD_ALLOC(ctx, sizeof(*ctx));
631 ctx->gc_proc = RPC_GSS_PROC_DATA;
633 spin_lock_init(&ctx->gc_seq_lock);
634 atomic_set(&ctx->gc_refcount,1);
636 if (simple_get_bytes(&p, &len, &gmd->gum_uid, sizeof(gmd->gum_uid)))
638 if (simple_get_bytes(&p, &len, &gmd->gum_svc, sizeof(gmd->gum_svc)))
640 if (simple_get_bytes(&p, &len, &gmd->gum_nal, sizeof(gmd->gum_nal)))
642 if (simple_get_bytes(&p, &len, &gmd->gum_netid, sizeof(gmd->gum_netid)))
644 if (simple_get_bytes(&p, &len, &gmd->gum_nid, sizeof(gmd->gum_nid)))
646 /* FIXME: discarded timeout for now */
647 if (simple_get_bytes(&p, &len, &timeout, sizeof(timeout)))
649 if (simple_get_bytes(&p, &len, &ctx->gc_win, sizeof(ctx->gc_win)))
652 /* lgssd signals an error by passing ctx->gc_win = 0: */
654 /* in which case the next 2 int are:
658 if (simple_get_bytes(&p, &len, &err, sizeof(err))) {
662 if (simple_get_bytes(&p, &len, gss_err, sizeof(*gss_err))) {
666 if (err == 0 && *gss_err == 0) {
667 CERROR("no error passed from downcall\n");
673 if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
675 if (rawobj_dup(&ctx->gc_wire_ctx, &tmp_buf)) {
679 if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
680 goto err_free_wire_ctx;
682 CERROR("unexpected trailing %u bytes\n", len);
683 goto err_free_wire_ctx;
685 if (kgss_import_sec_context(&tmp_buf, gm, &ctx->gc_gss_ctx))
686 goto err_free_wire_ctx;
692 if (ctx->gc_wire_ctx.data)
693 OBD_FREE(ctx->gc_wire_ctx.data, ctx->gc_wire_ctx.len);
695 OBD_FREE(ctx, sizeof(*ctx));
696 CDEBUG(D_SEC, "err_code %d, gss code %d\n", err, *gss_err);
700 /***************************************
702 ***************************************/
704 #define CRED_REFRESH_UPCALL_TIMEOUT (50)
705 static int gss_cred_refresh(struct ptlrpc_cred *cred)
707 struct obd_import *import;
708 struct gss_sec *gsec;
709 struct gss_upcall_msg *gss_msg, *gss_new;
710 struct gss_upcall_msg_data gmd;
711 struct dentry *dentry;
712 char *obdname, *obdtype;
714 uid_t uid = cred->pc_uid;
718 /* any flags means it has been handled, do nothing */
719 if (cred->pc_flags & PTLRPC_CRED_FLAGS_MASK)
722 LASSERT(cred->pc_sec);
723 LASSERT(cred->pc_sec->ps_import);
724 LASSERT(cred->pc_sec->ps_import->imp_obd);
726 import = cred->pc_sec->ps_import;
727 if (!import->imp_connection) {
728 CERROR("import has no connection set\n");
733 gmd.gum_nal = import->imp_connection->c_peer.peer_ni->pni_number;
735 gmd.gum_nid = import->imp_connection->c_peer.peer_id.nid;
737 obdtype = import->imp_obd->obd_type->typ_name;
738 if (!strcmp(obdtype, "mdc"))
739 gmd.gum_svc = LUSTRE_GSS_SVC_MDS;
740 else if (!strcmp(obdtype, "osc"))
741 gmd.gum_svc = LUSTRE_GSS_SVC_OSS;
743 CERROR("gss on %s?\n", obdtype);
747 gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
748 obdname = import->imp_obd->obd_name;
749 dentry = gsec->gs_depipe;
753 CDEBUG(D_SEC, "Initiate gss context %p(%u@%s)\n",
754 container_of(cred, struct gss_cred, gc_base),
755 uid, import->imp_target_uuid.uuid);
758 spin_lock(&gsec->gs_lock);
759 gss_msg = gss_find_upcall(gsec, obdname, &gmd);
762 OBD_FREE(gss_new, sizeof(*gss_new));
769 spin_unlock(&gsec->gs_lock);
770 OBD_ALLOC(gss_new, sizeof(*gss_new));
775 /* so far we'v created gss_new */
776 gss_init_upcall_msg(gss_new, gsec, obdname, &gmd);
778 /* we'v created upcall msg, nobody else should touch the
779 * flag of this cred, unless be set as dead/expire by
780 * administrator via lctl etc.
782 if (cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) {
783 CWARN("cred %p("LPU64"/%u) was set flags %x unexpectedly\n",
784 cred, cred->pc_pag, cred->pc_uid, cred->pc_flags);
785 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
786 gss_unhash_msg_nolock(gss_new);
787 spin_unlock(&gsec->gs_lock);
788 gss_release_msg(gss_new);
792 /* need to make upcall now */
793 spin_unlock(&gsec->gs_lock);
794 res = rpc_queue_upcall(dentry->d_inode, &gss_new->gum_base);
796 CERROR("rpc_queue_upcall failed: %d\n", res);
797 gss_unhash_msg(gss_new);
798 gss_release_msg(gss_new);
799 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
803 spin_lock(&gsec->gs_lock);
806 /* upcall might finish quickly */
807 if (list_empty(&gss_msg->gum_list)) {
808 spin_unlock(&gsec->gs_lock);
813 init_waitqueue_entry(&wait, current);
814 set_current_state(TASK_INTERRUPTIBLE);
815 add_wait_queue(&gss_msg->gum_waitq, &wait);
816 spin_unlock(&gsec->gs_lock);
819 res = schedule_timeout(CRED_REFRESH_UPCALL_TIMEOUT * HZ);
825 remove_wait_queue(&gss_msg->gum_waitq, &wait);
827 /* - the one who refresh the cred for us should also be responsible
828 * to set the status of cred, we can simply return.
829 * - if cred flags has been set, we also don't need to do that again,
830 * no matter signal pending or timeout etc.
832 if (!gss_new || cred->pc_flags & PTLRPC_CRED_FLAGS_MASK)
835 if (signal_pending(current)) {
836 CERROR("%s: cred %p: interrupted upcall\n",
837 current->comm, cred);
838 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
840 } else if (res == 0) {
841 CERROR("cred %p: upcall timedout\n", cred);
842 cred->pc_flags |= PTLRPC_CRED_DEAD;
848 gss_release_msg(gss_msg);
852 #else /* !__KERNEL__ */
853 extern int lgss_handle_krb5_upcall(uid_t uid, __u32 dest_ip,
855 char *buf, int bufsize,
856 int (*callback)(char*, unsigned long));
858 static int gss_cred_refresh(struct ptlrpc_cred *cred)
862 struct obd_import *imp;
863 struct gss_sec *gsec;
864 struct gss_api_mech *mech;
865 struct gss_cl_ctx *ctx = NULL;
866 struct vfs_cred vcred = { 0 };
873 LASSERT(cred->pc_sec);
874 LASSERT(cred->pc_sec->ps_import);
875 LASSERT(cred->pc_sec->ps_import->imp_obd);
877 if (ptlrpcs_cred_is_uptodate(cred))
880 imp = cred->pc_sec->ps_import;
881 peer_nid = imp->imp_connection->c_peer.peer_id.nid;
882 dest_ip = (__u32) (peer_nid & 0xFFFFFFFF);
883 subflavor = cred->pc_sec->ps_flavor.subflavor;
885 if (subflavor != PTLRPC_SEC_GSS_KRB5I) {
886 CERROR("unknown subflavor %u\n", subflavor);
887 GOTO(err_out, rc = -EINVAL);
890 rc = lgss_handle_krb5_upcall(cred->pc_uid, dest_ip,
891 imp->imp_obd->obd_name,
893 gss_send_secinit_rpc);
901 gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
902 mech = gsec->gs_mech;
904 rc = gss_parse_init_downcall(mech, &obj, &ctx, &vcred, &dest_ip,
907 CERROR("parse init downcall: rpc %d, gss 0x%x\n", rc, gss_err);
908 if (rc != -ERESTART || gss_err != 0)
909 cred->pc_flags |= PTLRPC_CRED_ERROR;
916 gss_cred_set_ctx(cred, ctx);
917 LASSERT(gss_cred_is_uptodate_ctx(cred));
921 cred->pc_flags |= PTLRPC_CRED_DEAD;
926 static int gss_cred_match(struct ptlrpc_cred *cred,
927 struct vfs_cred *vcred)
929 RETURN(cred->pc_pag == vcred->vc_pag);
932 static int gss_cred_sign(struct ptlrpc_cred *cred,
933 struct ptlrpc_request *req)
935 struct gss_cred *gcred;
936 struct gss_cl_ctx *ctx;
938 __u32 *vp, *vpsave, vlen, seclen;
939 __u32 seqnum, major, rc = 0;
942 LASSERT(req->rq_reqbuf);
943 LASSERT(req->rq_cred == cred);
945 gcred = container_of(cred, struct gss_cred, gc_base);
946 ctx = gss_cred_get_ctx(cred);
948 CERROR("cred %p("LPU64"/%u) invalidated?\n",
949 cred, cred->pc_pag, cred->pc_uid);
953 lmsg.len = req->rq_reqlen;
954 lmsg.data = (__u8 *) req->rq_reqmsg;
956 vp = (__u32 *) (lmsg.data + lmsg.len);
957 vlen = req->rq_reqbuf_len - sizeof(struct ptlrpcs_wire_hdr) -
961 if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
962 CERROR("vlen %d, need %d\n",
963 vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
968 spin_lock(&ctx->gc_seq_lock);
969 seqnum = ctx->gc_seq++;
970 spin_unlock(&ctx->gc_seq_lock);
972 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* version */
973 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I); /* subflavor */
974 *vp++ = cpu_to_le32(ctx->gc_proc); /* proc */
975 *vp++ = cpu_to_le32(seqnum); /* seq */
976 *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_INTEGRITY); /* service */
979 if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
983 CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
985 vpsave = vp++; /* reserve for size */
989 mic.data = (unsigned char *)vp;
991 CDEBUG(D_SEC, "reqbuf at %p, lmsg at %p, len %d, mic at %p, len %d\n",
992 req->rq_reqbuf, lmsg.data, lmsg.len, mic.data, mic.len);
993 major = kgss_get_mic(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, &lmsg, &mic);
995 CERROR("cred %p: req %p compute mic error, major %x\n",
1001 *vpsave = cpu_to_le32(mic.len);
1003 seclen = seclen - vlen + mic.len;
1004 buf_to_sec_hdr(req->rq_reqbuf)->sec_len = cpu_to_le32(seclen);
1005 req->rq_reqdata_len += size_round(seclen);
1006 CDEBUG(D_SEC, "msg size %d, checksum size %d, total sec size %d\n",
1007 lmsg.len, mic.len, seclen);
1013 static int gss_cred_verify(struct ptlrpc_cred *cred,
1014 struct ptlrpc_request *req)
1016 struct gss_cred *gcred;
1017 struct gss_cl_ctx *ctx;
1018 struct ptlrpcs_wire_hdr *sec_hdr;
1020 __u32 *vp, vlen, subflavor, proc, seq, svc;
1021 __u32 major, minor, rc;
1024 LASSERT(req->rq_repbuf);
1025 LASSERT(req->rq_cred == cred);
1027 sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
1028 vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr) + sec_hdr->msg_len);
1029 vlen = sec_hdr->sec_len;
1032 CERROR("reply sec size %u too small\n", vlen);
1036 if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
1037 CERROR("reply have different gss version\n");
1040 subflavor = le32_to_cpu(*vp++);
1041 proc = le32_to_cpu(*vp++);
1045 case PTLRPC_GSS_PROC_DATA:
1046 seq = le32_to_cpu(*vp++);
1047 svc = le32_to_cpu(*vp++);
1048 if (svc != PTLRPC_GSS_SVC_INTEGRITY) {
1049 CERROR("Unknown svc %d\n", svc);
1053 CERROR("Unexpected ctx handle\n");
1056 mic.len = le32_to_cpu(*vp++);
1058 if (vlen < mic.len) {
1059 CERROR("vlen %d, mic.len %d\n", vlen, mic.len);
1062 mic.data = (unsigned char *)vp;
1064 gcred = container_of(cred, struct gss_cred, gc_base);
1065 ctx = gss_cred_get_ctx(cred);
1068 lmsg.len = sec_hdr->msg_len;
1069 lmsg.data = (__u8 *) buf_to_lustre_msg(req->rq_repbuf);
1071 major = kgss_verify_mic(ctx->gc_gss_ctx, &lmsg, &mic, NULL);
1072 if (major != GSS_S_COMPLETE) {
1073 CERROR("cred %p: req %p verify mic error: major %x\n",
1076 if (major == GSS_S_CREDENTIALS_EXPIRED ||
1077 major == GSS_S_CONTEXT_EXPIRED) {
1078 ptlrpcs_cred_expire(cred);
1079 req->rq_ptlrpcs_restart = 1;
1084 GOTO(proc_data_out, rc);
1087 req->rq_repmsg = (struct lustre_msg *) lmsg.data;
1088 req->rq_replen = lmsg.len;
1090 /* here we could check the seq number is the same one
1091 * we sent to server. but portals has prevent us from
1092 * replay attack, so maybe we don't need check it again.
1098 case PTLRPC_GSS_PROC_ERR:
1099 major = le32_to_cpu(*vp++);
1100 minor = le32_to_cpu(*vp++);
1101 /* server return NO_CONTEXT might be caused by context expire
1102 * or server reboot/failover. we refresh the cred transparently
1104 * In some cases, our gss handle is possible to be incidentally
1105 * identical to another handle since the handle itself is not
1106 * fully random. In krb5 case, the GSS_S_BAD_SIG will be
1107 * returned, maybe other gss error for other mechanism. Here we
1108 * only consider krb5 mech (FIXME) and try to establish new
1111 if (major == GSS_S_NO_CONTEXT ||
1112 major == GSS_S_BAD_SIG) {
1113 CWARN("req %p: server report cred %p %s, expired?\n",
1114 req, cred, (major == GSS_S_NO_CONTEXT) ?
1115 "NO_CONTEXT" : "BAD_SIG");
1117 ptlrpcs_cred_expire(cred);
1118 req->rq_ptlrpcs_restart = 1;
1121 CERROR("req %p: unrecognized gss error (%x/%x)\n",
1127 CERROR("unknown gss proc %d\n", proc);
1134 static int gss_cred_seal(struct ptlrpc_cred *cred,
1135 struct ptlrpc_request *req)
1137 struct gss_cred *gcred;
1138 struct gss_cl_ctx *ctx;
1139 struct ptlrpcs_wire_hdr *sec_hdr;
1140 rawobj_buf_t msg_buf;
1141 rawobj_t cipher_buf;
1142 __u32 *vp, *vpsave, vlen, seclen;
1143 __u32 major, seqnum, rc = 0;
1146 LASSERT(req->rq_reqbuf);
1147 LASSERT(req->rq_cred == cred);
1149 gcred = container_of(cred, struct gss_cred, gc_base);
1150 ctx = gss_cred_get_ctx(cred);
1152 CERROR("cred %p("LPU64"/%u) invalidated?\n",
1153 cred, cred->pc_pag, cred->pc_uid);
1157 vp = (__u32 *) (req->rq_reqbuf + sizeof(*sec_hdr));
1158 vlen = req->rq_reqbuf_len - sizeof(*sec_hdr);
1161 if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
1162 CERROR("vlen %d, need %d\n",
1163 vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
1168 spin_lock(&ctx->gc_seq_lock);
1169 seqnum = ctx->gc_seq++;
1170 spin_unlock(&ctx->gc_seq_lock);
1172 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* version */
1173 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5P); /* subflavor */
1174 *vp++ = cpu_to_le32(ctx->gc_proc); /* proc */
1175 *vp++ = cpu_to_le32(seqnum); /* seq */
1176 *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_PRIVACY); /* service */
1179 if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
1183 CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
1185 vpsave = vp++; /* reserve for size */
1188 msg_buf.buf = (__u8 *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1189 msg_buf.buflen = req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
1190 GSS_PRIVBUF_SUFFIX_LEN;
1191 msg_buf.dataoff = GSS_PRIVBUF_PREFIX_LEN;
1192 msg_buf.datalen = req->rq_reqlen;
1194 cipher_buf.data = (__u8 *) vp;
1195 cipher_buf.len = vlen;
1197 major = kgss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1198 &msg_buf, &cipher_buf);
1200 CERROR("cred %p: error wrap: major 0x%x\n", cred, major);
1201 GOTO(out, rc = -EINVAL);
1204 *vpsave = cpu_to_le32(cipher_buf.len);
1206 seclen = seclen - vlen + cipher_buf.len;
1207 sec_hdr = buf_to_sec_hdr(req->rq_reqbuf);
1208 sec_hdr->sec_len = cpu_to_le32(seclen);
1209 req->rq_reqdata_len += size_round(seclen);
1211 CDEBUG(D_SEC, "msg size %d, total sec size %d\n",
1212 req->rq_reqlen, seclen);
1218 static int gss_cred_unseal(struct ptlrpc_cred *cred,
1219 struct ptlrpc_request *req)
1221 struct gss_cred *gcred;
1222 struct gss_cl_ctx *ctx;
1223 struct ptlrpcs_wire_hdr *sec_hdr;
1224 rawobj_t cipher_text, plain_text;
1225 __u32 *vp, vlen, subflavor, proc, seq, svc;
1229 LASSERT(req->rq_repbuf);
1230 LASSERT(req->rq_cred == cred);
1232 sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
1233 if (sec_hdr->msg_len != 0) {
1234 CERROR("unexpected msg_len %u\n", sec_hdr->msg_len);
1238 vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr));
1239 vlen = sec_hdr->sec_len;
1242 CERROR("reply sec size %u too small\n", vlen);
1246 if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
1247 CERROR("reply have different gss version\n");
1250 subflavor = le32_to_cpu(*vp++);
1251 proc = le32_to_cpu(*vp++);
1252 seq = le32_to_cpu(*vp++);
1253 svc = le32_to_cpu(*vp++);
1257 case PTLRPC_GSS_PROC_DATA:
1258 if (svc != PTLRPC_GSS_SVC_PRIVACY) {
1259 CERROR("Unknown svc %d\n", svc);
1263 CERROR("Unexpected ctx handle\n");
1268 cipher_text.len = le32_to_cpu(*vp++);
1269 cipher_text.data = (__u8 *) vp;
1272 if (vlen < cipher_text.len) {
1273 CERROR("cipher text to be %u while buf only %u\n",
1274 cipher_text.len, vlen);
1278 plain_text = cipher_text;
1280 gcred = container_of(cred, struct gss_cred, gc_base);
1281 ctx = gss_cred_get_ctx(cred);
1284 major = kgss_unwrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1285 &cipher_text, &plain_text);
1287 CERROR("cred %p: error unwrap: major 0x%x\n",
1290 if (major == GSS_S_CREDENTIALS_EXPIRED ||
1291 major == GSS_S_CONTEXT_EXPIRED) {
1292 ptlrpcs_cred_expire(cred);
1293 req->rq_ptlrpcs_restart = 1;
1301 req->rq_repmsg = (struct lustre_msg *) vp;
1302 req->rq_replen = plain_text.len;
1309 CERROR("unknown gss proc %d\n", proc);
1316 static void destroy_gss_context(struct ptlrpc_cred *cred)
1318 struct ptlrpcs_wire_hdr *hdr;
1319 struct lustre_msg *lmsg;
1320 struct gss_cred *gcred;
1321 struct ptlrpc_request req;
1322 struct obd_import *imp;
1323 __u32 *vp, lmsg_size;
1324 struct ptlrpc_request *raw_req = NULL;
1325 const int repbuf_len = 256;
1330 /* cred's refcount is 0, steal one */
1331 atomic_inc(&cred->pc_refcount);
1333 if (!(cred->pc_flags & PTLRPC_CRED_UPTODATE)) {
1334 CDEBUG(D_SEC, "Destroy dead cred %p(%u@%s)\n",
1335 cred, cred->pc_uid, imp->imp_target_uuid.uuid);
1336 atomic_dec(&cred->pc_refcount);
1341 gcred = container_of(cred, struct gss_cred, gc_base);
1342 gcred->gc_ctx->gc_proc = PTLRPC_GSS_PROC_DESTROY;
1343 imp = cred->pc_sec->ps_import;
1346 CDEBUG(D_SEC, "client destroy gss cred %p(%u@%s)\n",
1347 gcred, cred->pc_uid, imp->imp_target_uuid.uuid);
1349 lmsg_size = lustre_msg_size(0, NULL);
1350 req.rq_reqbuf_len = sizeof(*hdr) + lmsg_size +
1351 ptlrpcs_est_req_payload(cred->pc_sec, lmsg_size);
1353 OBD_ALLOC(req.rq_reqbuf, req.rq_reqbuf_len);
1354 if (!req.rq_reqbuf) {
1355 CERROR("Fail to alloc reqbuf, cancel anyway\n");
1356 atomic_dec(&cred->pc_refcount);
1362 hdr = buf_to_sec_hdr(req.rq_reqbuf);
1363 hdr->flavor = cpu_to_le32(PTLRPC_SEC_GSS);
1364 hdr->sectype = cpu_to_le32(PTLRPC_SEC_TYPE_AUTH);
1365 hdr->msg_len = cpu_to_le32(lmsg_size);
1366 hdr->sec_len = cpu_to_le32(0);
1368 /* lustre message */
1369 lmsg = buf_to_lustre_msg(req.rq_reqbuf);
1370 lustre_init_msg(lmsg, 0, NULL, NULL);
1371 lmsg->handle = imp->imp_remote_handle;
1372 lmsg->type = PTL_RPC_MSG_REQUEST;
1373 lmsg->opc = SEC_FINI;
1375 lmsg->conn_cnt = imp->imp_conn_cnt;
1376 /* add this for randomize */
1377 get_random_bytes(&lmsg->last_xid, sizeof(lmsg->last_xid));
1378 get_random_bytes(&lmsg->transno, sizeof(lmsg->transno));
1380 vp = (__u32 *) req.rq_reqbuf;
1383 req.rq_reqmsg = buf_to_lustre_msg(req.rq_reqbuf);
1384 req.rq_reqlen = lmsg_size;
1385 req.rq_reqdata_len = sizeof(*hdr) + lmsg_size;
1387 if (gss_cred_sign(cred, &req)) {
1388 CERROR("failed to sign, cancel anyway\n");
1389 atomic_dec(&cred->pc_refcount);
1392 atomic_dec(&cred->pc_refcount);
1394 OBD_ALLOC(repbuf, repbuf_len);
1398 raw_req = ptl_do_rawrpc(imp, req.rq_reqbuf, req.rq_reqbuf_len,
1399 req.rq_reqdata_len, repbuf, repbuf_len, &replen,
1400 SECFINI_RPC_TIMEOUT, &rc);
1402 OBD_FREE(repbuf, repbuf_len);
1405 if (raw_req == NULL)
1406 OBD_FREE(req.rq_reqbuf, req.rq_reqbuf_len);
1408 rawrpc_req_finished(raw_req);
1412 static void gss_cred_destroy(struct ptlrpc_cred *cred)
1414 struct gss_cred *gcred;
1418 LASSERT(!atomic_read(&cred->pc_refcount));
1420 gcred = container_of(cred, struct gss_cred, gc_base);
1421 if (gcred->gc_ctx) {
1422 destroy_gss_context(cred);
1423 gss_put_ctx(gcred->gc_ctx);
1426 CDEBUG(D_SEC, "GSS_SEC: destroy cred %p\n", gcred);
1428 OBD_FREE(gcred, sizeof(*gcred));
1432 static struct ptlrpc_credops gss_credops = {
1433 .refresh = gss_cred_refresh,
1434 .match = gss_cred_match,
1435 .sign = gss_cred_sign,
1436 .verify = gss_cred_verify,
1437 .seal = gss_cred_seal,
1438 .unseal = gss_cred_unseal,
1439 .destroy = gss_cred_destroy,
1443 /*******************************************
1445 *******************************************/
1447 gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
1448 char *dst, size_t buflen)
1450 char *data = (char *)msg->data + msg->copied;
1451 ssize_t mlen = msg->len;
1457 left = copy_to_user(dst, data, mlen);
1463 msg->copied += mlen;
1469 gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
1472 const int bufsize = 1024;
1474 struct inode *inode = filp->f_dentry->d_inode;
1475 struct rpc_inode *rpci = RPC_I(inode);
1476 struct obd_import *import;
1477 struct ptlrpc_sec *sec;
1478 struct gss_sec *gsec;
1480 struct gss_api_mech *mech;
1481 struct vfs_cred vcred = { 0 };
1482 struct ptlrpc_cred *cred;
1483 struct gss_upcall_msg *gss_msg;
1484 struct gss_upcall_msg_data gmd = { 0 };
1485 struct gss_cl_ctx *ctx = NULL;
1490 if (mlen > bufsize) {
1491 CERROR("mlen %ld > bufsize %d\n", (long)mlen, bufsize);
1495 OBD_ALLOC(buf, bufsize);
1497 CERROR("alloc mem failed\n");
1501 left = copy_from_user(buf, src, mlen);
1503 GOTO(err_free, err = -EFAULT);
1505 obj.data = (unsigned char *)buf;
1508 LASSERT(rpci->private);
1509 gsec = (struct gss_sec *)rpci->private;
1510 sec = &gsec->gs_base;
1511 LASSERT(sec->ps_import);
1512 import = class_import_get(sec->ps_import);
1513 LASSERT(import->imp_obd);
1514 obdname = import->imp_obd->obd_name;
1515 mech = gsec->gs_mech;
1517 err = gss_parse_init_downcall(mech, &obj, &ctx, &gmd, &gss_err);
1519 CERROR("parse init downcall err %d\n", err);
1521 vcred.vc_uid = gmd.gum_uid;
1522 vcred.vc_pag = vcred.vc_uid; /* FIXME */
1524 cred = ptlrpcs_cred_lookup(sec, &vcred);
1526 CWARN("didn't find cred for uid %u\n", vcred.vc_uid);
1527 GOTO(err, err = -EINVAL);
1530 if (err || gss_err) {
1531 cred->pc_flags |= PTLRPC_CRED_DEAD;
1532 if (err != -ERESTART || gss_err != 0)
1533 cred->pc_flags |= PTLRPC_CRED_ERROR;
1534 CERROR("cred %p: rpc err %d, gss err 0x%x, fatal %d\n",
1536 ((cred->pc_flags & PTLRPC_CRED_ERROR) != 0));
1538 CDEBUG(D_SEC, "get initial ctx:\n");
1539 gss_cred_set_ctx(cred, ctx);
1542 spin_lock(&gsec->gs_lock);
1543 gss_msg = gss_find_upcall(gsec, obdname, &gmd);
1545 gss_unhash_msg_nolock(gss_msg);
1546 spin_unlock(&gsec->gs_lock);
1547 gss_release_msg(gss_msg);
1549 spin_unlock(&gsec->gs_lock);
1551 ptlrpcs_cred_put(cred, 1);
1552 class_import_put(import);
1553 OBD_FREE(buf, bufsize);
1557 gss_destroy_ctx(ctx);
1558 class_import_put(import);
1560 OBD_FREE(buf, bufsize);
1561 CDEBUG(D_SEC, "gss_pipe_downcall returning %d\n", err);
1566 void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
1568 struct gss_upcall_msg *gmsg;
1569 static unsigned long ratelimit;
1572 if (msg->errno >= 0) {
1577 gmsg = container_of(msg, struct gss_upcall_msg, gum_base);
1578 CDEBUG(D_SEC, "destroy gmsg %p\n", gmsg);
1579 atomic_inc(&gmsg->gum_refcount);
1580 gss_unhash_msg(gmsg);
1581 if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
1582 unsigned long now = get_seconds();
1583 if (time_after(now, ratelimit)) {
1584 CWARN("GSS_SEC upcall timed out.\n"
1585 "Please check user daemon is running!\n");
1586 ratelimit = now + 15;
1589 gss_release_msg(gmsg);
1594 void gss_pipe_release(struct inode *inode)
1596 struct rpc_inode *rpci = RPC_I(inode);
1597 struct ptlrpc_sec *sec;
1598 struct gss_sec *gsec;
1601 gsec = (struct gss_sec *)rpci->private;
1602 sec = &gsec->gs_base;
1603 spin_lock(&gsec->gs_lock);
1604 while (!list_empty(&gsec->gs_upcalls)) {
1605 struct gss_upcall_msg *gmsg;
1607 gmsg = list_entry(gsec->gs_upcalls.next,
1608 struct gss_upcall_msg, gum_list);
1609 gmsg->gum_base.errno = -EPIPE;
1610 atomic_inc(&gmsg->gum_refcount);
1611 gss_unhash_msg_nolock(gmsg);
1612 gss_release_msg(gmsg);
1614 spin_unlock(&gsec->gs_lock);
1618 static struct rpc_pipe_ops gss_upcall_ops = {
1619 .upcall = gss_pipe_upcall,
1620 .downcall = gss_pipe_downcall,
1621 .destroy_msg = gss_pipe_destroy_msg,
1622 .release_pipe = gss_pipe_release,
1624 #endif /* __KERNEL__ */
1626 /*********************************************
1627 * GSS security APIs *
1628 *********************************************/
1631 struct ptlrpc_sec* gss_create_sec(ptlrpcs_flavor_t *flavor,
1632 const char *pipe_dir,
1635 struct gss_sec *gsec;
1636 struct ptlrpc_sec *sec;
1643 LASSERT(flavor->flavor == PTLRPC_SEC_GSS);
1645 OBD_ALLOC(gsec, sizeof(*gsec));
1647 CERROR("can't alloc gsec\n");
1651 gsec->gs_mech = kgss_subflavor_to_mech(flavor->subflavor);
1652 if (!gsec->gs_mech) {
1653 CERROR("subflavor %d not found\n", flavor->subflavor);
1657 /* initialize gss sec */
1659 INIT_LIST_HEAD(&gsec->gs_upcalls);
1660 spin_lock_init(&gsec->gs_lock);
1662 pipepath_len = strlen(LUSTRE_PIPEDIR) + strlen(pipe_dir) +
1663 strlen(gsec->gs_mech->gm_name) + 3;
1664 OBD_ALLOC(gsec->gs_pipepath, pipepath_len);
1665 if (!gsec->gs_pipepath)
1668 sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s", pipe_dir);
1669 if (IS_ERR(rpc_mkdir(gsec->gs_pipepath, NULL))) {
1670 CERROR("can't make pipedir %s\n", gsec->gs_pipepath);
1674 sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s/%s", pipe_dir,
1675 gsec->gs_mech->gm_name);
1676 gsec->gs_depipe = rpc_mkpipe(gsec->gs_pipepath, gsec,
1677 &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
1678 if (IS_ERR(gsec->gs_depipe)) {
1679 CERROR("failed to make rpc_pipe %s: %ld\n",
1680 gsec->gs_pipepath, PTR_ERR(gsec->gs_depipe));
1683 CDEBUG(D_SEC, "gss sec %p, pipe path %s\n", gsec, gsec->gs_pipepath);
1686 sec = &gsec->gs_base;
1688 switch (flavor->subflavor) {
1689 case PTLRPC_SEC_GSS_KRB5I:
1690 sec->ps_sectype = PTLRPC_SEC_TYPE_AUTH;
1692 case PTLRPC_SEC_GSS_KRB5P:
1693 sec->ps_sectype = PTLRPC_SEC_TYPE_PRIV;
1699 sec->ps_expire = GSS_CREDCACHE_EXPIRE;
1700 sec->ps_nextgc = get_seconds() + sec->ps_expire;
1703 CDEBUG(D_SEC, "Create GSS security instance at %p(external %p)\n",
1709 pos = strrchr(gsec->gs_pipepath, '/');
1712 rpc_rmdir(gsec->gs_pipepath);
1714 OBD_FREE(gsec->gs_pipepath, pipepath_len);
1717 kgss_mech_put(gsec->gs_mech);
1719 OBD_FREE(gsec, sizeof(*gsec));
1724 void gss_destroy_sec(struct ptlrpc_sec *sec)
1726 struct gss_sec *gsec;
1733 gsec = container_of(sec, struct gss_sec, gs_base);
1734 CDEBUG(D_SEC, "Destroy GSS security instance at %p\n", gsec);
1736 LASSERT(gsec->gs_mech);
1737 LASSERT(!atomic_read(&sec->ps_refcount));
1738 LASSERT(!atomic_read(&sec->ps_credcount));
1740 pipepath_len = strlen(gsec->gs_pipepath) + 1;
1741 rpc_unlink(gsec->gs_pipepath);
1742 pos = strrchr(gsec->gs_pipepath, '/');
1745 rpc_rmdir(gsec->gs_pipepath);
1746 OBD_FREE(gsec->gs_pipepath, pipepath_len);
1749 kgss_mech_put(gsec->gs_mech);
1750 OBD_FREE(gsec, sizeof(*gsec));
1755 struct ptlrpc_cred * gss_create_cred(struct ptlrpc_sec *sec,
1756 struct vfs_cred *vcred)
1758 struct gss_cred *gcred;
1759 struct ptlrpc_cred *cred;
1762 OBD_ALLOC(gcred, sizeof(*gcred));
1766 cred = &gcred->gc_base;
1767 INIT_LIST_HEAD(&cred->pc_hash);
1768 atomic_set(&cred->pc_refcount, 0);
1770 cred->pc_ops = &gss_credops;
1771 cred->pc_expire = get_seconds() + GSS_CRED_EXPIRE;
1773 cred->pc_pag = vcred->vc_pag;
1774 cred->pc_uid = vcred->vc_uid;
1775 CDEBUG(D_SEC, "create a gss cred at %p("LPU64"/%u)\n",
1776 cred, vcred->vc_pag, vcred->vc_uid);
1781 static int gss_estimate_payload(struct ptlrpc_sec *sec, int msgsize)
1783 switch (sec->ps_sectype) {
1784 case PTLRPC_SEC_TYPE_AUTH:
1785 return GSS_MAX_AUTH_PAYLOAD;
1786 case PTLRPC_SEC_TYPE_PRIV:
1787 return size_round16(GSS_MAX_AUTH_PAYLOAD + msgsize +
1788 GSS_PRIVBUF_PREFIX_LEN +
1789 GSS_PRIVBUF_SUFFIX_LEN);
1796 static int gss_alloc_reqbuf(struct ptlrpc_sec *sec,
1797 struct ptlrpc_request *req,
1800 int msg_payload, sec_payload;
1804 /* In PRIVACY mode, lustre message is always 0 (already encoded into
1805 * security payload).
1807 privacy = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV;
1808 msg_payload = privacy ? 0 : lmsg_size;
1809 sec_payload = gss_estimate_payload(sec, lmsg_size);
1811 rc = sec_alloc_reqbuf(sec, req, msg_payload, sec_payload);
1816 int buflen = lmsg_size + GSS_PRIVBUF_PREFIX_LEN +
1817 GSS_PRIVBUF_SUFFIX_LEN;
1820 OBD_ALLOC(buf, buflen);
1822 CERROR("Fail to alloc %d\n", buflen);
1823 sec_free_reqbuf(sec, req);
1826 req->rq_reqmsg = (struct lustre_msg *)
1827 (buf + GSS_PRIVBUF_PREFIX_LEN);
1833 static void gss_free_reqbuf(struct ptlrpc_sec *sec,
1834 struct ptlrpc_request *req)
1840 LASSERT(req->rq_reqmsg);
1841 LASSERT(req->rq_reqlen);
1843 privacy = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV;
1845 buf = (char *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1846 LASSERT(buf < req->rq_reqbuf ||
1847 buf >= req->rq_reqbuf + req->rq_reqbuf_len);
1848 OBD_FREE(buf, req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
1849 GSS_PRIVBUF_SUFFIX_LEN);
1850 req->rq_reqmsg = NULL;
1853 sec_free_reqbuf(sec, req);
1856 static struct ptlrpc_secops gss_secops = {
1857 .create_sec = gss_create_sec,
1858 .destroy_sec = gss_destroy_sec,
1859 .create_cred = gss_create_cred,
1860 .est_req_payload = gss_estimate_payload,
1861 .est_rep_payload = gss_estimate_payload,
1862 .alloc_reqbuf = gss_alloc_reqbuf,
1863 .free_reqbuf = gss_free_reqbuf,
1866 static struct ptlrpc_sec_type gss_type = {
1867 .pst_owner = THIS_MODULE,
1868 .pst_name = "GSS_SEC",
1869 .pst_inst = ATOMIC_INIT(0),
1870 .pst_flavor = {PTLRPC_SEC_GSS, 0},
1871 .pst_ops = &gss_secops,
1875 (*lustre_secinit_downcall_handler)(char *buffer, unsigned long count);
1877 int __init ptlrpcs_gss_init(void)
1881 rc = ptlrpcs_register(&gss_type);
1888 rc = PTR_ERR(rpc_mkdir(LUSTRE_PIPEDIR, NULL));
1889 if (IS_ERR((void *)rc) && rc != -EEXIST) {
1890 CERROR("fail to make rpcpipedir for lustre\n");
1892 ptlrpcs_unregister(&gss_type);
1898 rc = init_kerberos_module();
1900 ptlrpcs_unregister(&gss_type);
1903 lustre_secinit_downcall_handler = gss_send_secinit_rpc;
1909 static void __exit ptlrpcs_gss_exit(void)
1911 lustre_secinit_downcall_handler = NULL;
1913 cleanup_kerberos_module();
1914 rpc_rmdir(LUSTRE_PIPEDIR);
1916 ptlrpcs_unregister(&gss_type);
1920 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
1921 MODULE_DESCRIPTION("GSS Security module for Lustre");
1922 MODULE_LICENSE("GPL");
1924 module_init(ptlrpcs_gss_init);
1925 module_exit(ptlrpcs_gss_exit);