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 LUSTRE_PIPEDIR "/lustre"
81 #define GSS_CREDCACHE_EXPIRE (30 * 60) /* 30 minute */
83 #define GSS_TIMEOUT_DELTA (5)
84 #define CRED_REFRESH_UPCALL_TIMEOUT \
86 int timeout = obd_timeout - GSS_TIMEOUT_DELTA; \
88 if (timeout < GSS_TIMEOUT_DELTA * 2) \
89 timeout = GSS_TIMEOUT_DELTA * 2; \
92 #define SECINIT_RPC_TIMEOUT \
94 int timeout = CRED_REFRESH_UPCALL_TIMEOUT - \
96 if (timeout < GSS_TIMEOUT_DELTA) \
97 timeout = GSS_TIMEOUT_DELTA; \
100 #define SECFINI_RPC_TIMEOUT (GSS_TIMEOUT_DELTA)
103 /**********************************************
104 * gss security init/fini helper *
105 **********************************************/
107 static int secinit_compose_request(struct obd_import *imp,
108 char *buf, int bufsize,
110 uid_t uid, gid_t gid,
114 struct ptlrpcs_wire_hdr *hdr;
115 struct lustre_msg *lmsg;
116 struct mds_req_sec_desc *secdesc;
117 int size = sizeof(*secdesc);
121 lmsg_size = lustre_msg_size(1, &size);
123 if (sizeof(*hdr) + lmsg_size + size_round(token_size) > bufsize) {
124 CERROR("token size %ld too large\n", token_size);
128 /* security wire hdr */
129 hdr = buf_to_sec_hdr(buf);
130 hdr->flavor = cpu_to_le32(PTLRPCS_FLVR_GSS_NONE);
131 hdr->msg_len = cpu_to_le32(lmsg_size);
132 hdr->sec_len = cpu_to_le32(8 * 4 + token_size);
134 /* lustre message & secdesc */
135 lmsg = buf_to_lustre_msg(buf);
137 lustre_init_msg(lmsg, 1, &size, NULL);
138 secdesc = lustre_msg_buf(lmsg, 0, size);
139 secdesc->rsd_uid = secdesc->rsd_fsuid = uid;
140 secdesc->rsd_gid = secdesc->rsd_fsgid = gid;
141 secdesc->rsd_cap = secdesc->rsd_ngroups = 0;
143 lmsg->handle = imp->imp_remote_handle;
144 lmsg->type = PTL_RPC_MSG_REQUEST;
145 lmsg->opc = SEC_INIT;
147 lmsg->conn_cnt = imp->imp_conn_cnt;
149 p = (__u32 *) (buf + sizeof(*hdr) + lmsg_size);
152 *p++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* gss version */
153 *p++ = cpu_to_le32(PTLRPCS_FLVR_KRB5I); /* subflavor */
154 *p++ = cpu_to_le32(PTLRPCS_GSS_PROC_INIT); /* proc */
155 *p++ = cpu_to_le32(0); /* seq */
156 *p++ = cpu_to_le32(PTLRPCS_GSS_SVC_NONE); /* service */
157 *p++ = cpu_to_le32(0); /* context handle */
159 /* plus lustre svc type */
160 *p++ = cpu_to_le32(lustre_srv);
162 /* now the token part */
163 *p++ = cpu_to_le32((__u32) token_size);
164 LASSERT(((char *)p - buf) + token_size <= bufsize);
166 rc = copy_from_user(p, token, token_size);
168 CERROR("can't copy token\n");
172 rc = size_round(((char *)p - buf) + token_size);
176 static int secinit_parse_reply(char *repbuf, int replen,
177 char __user *outbuf, long outlen)
179 __u32 *p = (__u32 *)repbuf;
180 struct ptlrpcs_wire_hdr *hdr = (struct ptlrpcs_wire_hdr *) repbuf;
181 __u32 lmsg_len, sec_len, status;
182 __u32 major, minor, seq, obj_len, round_len;
185 if (replen <= (4 + 6) * 4) {
186 CERROR("reply size %d too small\n", replen);
190 hdr->flavor = le32_to_cpu(hdr->flavor);
191 hdr->msg_len = le32_to_cpu(hdr->msg_len);
192 hdr->sec_len = le32_to_cpu(hdr->sec_len);
194 lmsg_len = le32_to_cpu(p[2]);
195 sec_len = le32_to_cpu(p[3]);
198 if (hdr->flavor != PTLRPCS_FLVR_GSS_NONE) {
199 CERROR("unexpected reply\n");
202 if (hdr->msg_len % 8 ||
203 sizeof(*hdr) + hdr->msg_len + hdr->sec_len > replen) {
204 CERROR("unexpected reply\n");
207 if (hdr->sec_len > outlen) {
208 CERROR("outbuf too small\n");
212 p = (__u32 *) buf_to_sec_data(repbuf);
215 status = le32_to_cpu(*p++);
216 major = le32_to_cpu(*p++);
217 minor = le32_to_cpu(*p++);
218 seq = le32_to_cpu(*p++);
221 if (copy_to_user(outbuf, &status, 4))
224 if (copy_to_user(outbuf, &major, 4))
227 if (copy_to_user(outbuf, &minor, 4))
230 if (copy_to_user(outbuf, &seq, 4))
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;
245 obj_len = le32_to_cpu(*p++);
246 round_len = (obj_len + 3) & ~ 3;
247 if (copy_to_user(outbuf, &obj_len, 4))
250 if (copy_to_user(outbuf, (char *)p, round_len))
254 effective += 4 + round_len;
259 /* XXX move to where lgssd could see */
260 struct lgssd_ioctl_param {
261 int version; /* in */
263 int lustre_svc; /* in */
266 long send_token_size;/* in */
267 char *send_token; /* in */
268 long reply_buf_size; /* in */
269 char *reply_buf; /* in */
270 long status; /* out */
271 long reply_length; /* out */
274 static int gss_send_secinit_rpc(__user char *buffer, unsigned long count)
276 struct obd_import *imp;
277 struct ptlrpc_request *request = NULL;
278 struct lgssd_ioctl_param param;
279 const int reqbuf_size = 1024;
280 const int repbuf_size = 1024;
281 char *reqbuf, *repbuf;
282 struct obd_device *obd;
285 int rc, reqlen, replen;
287 if (count != sizeof(param)) {
288 CERROR("ioctl size %lu, expect %d, please check lgssd version\n",
289 count, sizeof(param));
292 if (copy_from_user(¶m, buffer, sizeof(param))) {
293 CERROR("failed copy data from lgssd\n");
297 if (param.version != GSSD_INTERFACE_VERSION) {
298 CERROR("gssd interface version %d (expect %d)\n",
299 param.version, GSSD_INTERFACE_VERSION);
304 if (strncpy_from_user(obdname, param.uuid,
305 sizeof(obdname)) <= 0) {
306 CERROR("Invalid obdname pointer\n");
310 obd = class_name2obd(obdname);
312 CERROR("no such obd %s\n", obdname);
316 imp = class_import_get(obd->u.cli.cl_import);
318 OBD_ALLOC(reqbuf, reqbuf_size);
319 OBD_ALLOC(repbuf, reqbuf_size);
321 if (!reqbuf || !repbuf) {
322 CERROR("Can't alloc buffer: %p/%p\n", reqbuf, repbuf);
323 param.status = -ENOMEM;
328 reqlen = secinit_compose_request(imp, reqbuf, reqbuf_size,
330 param.uid, param.gid,
331 param.send_token_size,
334 param.status = reqlen;
338 request = ptl_do_rawrpc(imp, reqbuf, reqbuf_size, reqlen,
339 repbuf, repbuf_size, &replen,
340 SECINIT_RPC_TIMEOUT, &rc);
341 if (request == NULL || rc) {
346 if (replen > param.reply_buf_size) {
347 CERROR("output buffer size %ld too small, need %d\n",
348 param.reply_buf_size, replen);
349 param.status = -EINVAL;
353 lsize = secinit_parse_reply(repbuf, replen,
354 param.reply_buf, param.reply_buf_size);
356 param.status = (int) lsize;
361 param.reply_length = lsize;
364 if (copy_to_user(buffer, ¶m, sizeof(param)))
369 class_import_put(imp);
370 if (request == NULL) {
372 OBD_FREE(repbuf, repbuf_size);
374 OBD_FREE(reqbuf, reqbuf_size);
376 rawrpc_req_finished(request);
381 /**********************************************
382 * structure definitions *
383 **********************************************/
385 struct ptlrpc_sec gs_base;
386 struct gss_api_mech *gs_mech;
388 struct list_head gs_upcalls;
390 struct dentry *gs_depipe;
393 struct gss_upcall_msg_data {
402 struct gss_upcall_msg {
403 struct rpc_pipe_msg gum_base;
404 atomic_t gum_refcount;
405 struct list_head gum_list;
406 struct gss_sec *gum_gsec;
407 wait_queue_head_t gum_waitq;
408 char gum_obdname[64];
409 struct gss_upcall_msg_data gum_data;
413 static rwlock_t gss_ctx_lock = RW_LOCK_UNLOCKED;
414 /**********************************************
415 * rpc_pipe upcall helpers *
416 **********************************************/
418 void gss_release_msg(struct gss_upcall_msg *gmsg)
421 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
423 if (!atomic_dec_and_test(&gmsg->gum_refcount)) {
424 CDEBUG(D_SEC, "gmsg %p ref %d\n", gmsg,
425 atomic_read(&gmsg->gum_refcount));
429 LASSERT(list_empty(&gmsg->gum_list));
431 LASSERT(list_empty(&gmsg->gum_base.list));
434 if (!list_empty(&gmsg->gum_base.list)) {
435 int error = gmsg->gum_base.errno;
437 CWARN("msg %p: list: %p/%p/%p, copied %d, err %d, wq %d\n",
438 gmsg, &gmsg->gum_base.list, gmsg->gum_base.list.prev,
439 gmsg->gum_base.list.next, gmsg->gum_base.copied, error,
440 list_empty(&gmsg->gum_waitq.task_list));
444 OBD_FREE(gmsg, sizeof(*gmsg));
449 gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg)
451 LASSERT_SPIN_LOCKED(&gmsg->gum_gsec->gs_lock);
453 if (list_empty(&gmsg->gum_list))
456 list_del_init(&gmsg->gum_list);
457 wake_up(&gmsg->gum_waitq);
458 LASSERT(atomic_read(&gmsg->gum_refcount) > 1);
459 atomic_dec(&gmsg->gum_refcount);
463 gss_unhash_msg(struct gss_upcall_msg *gmsg)
465 struct gss_sec *gsec = gmsg->gum_gsec;
467 spin_lock(&gsec->gs_lock);
468 gss_unhash_msg_nolock(gmsg);
469 spin_unlock(&gsec->gs_lock);
473 struct gss_upcall_msg * gss_find_upcall(struct gss_sec *gsec,
475 struct gss_upcall_msg_data *gmd)
477 struct gss_upcall_msg *gmsg;
480 LASSERT_SPIN_LOCKED(&gsec->gs_lock);
482 list_for_each_entry(gmsg, &gsec->gs_upcalls, gum_list) {
483 if (memcmp(&gmsg->gum_data, gmd, sizeof(*gmd)))
485 if (strcmp(gmsg->gum_obdname, obdname))
487 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
488 atomic_inc(&gmsg->gum_refcount);
489 CDEBUG(D_SEC, "found gmsg at %p: obdname %s, uid %d, ref %d\n",
490 gmsg, obdname, gmd->gum_uid,
491 atomic_read(&gmsg->gum_refcount));
497 static void gss_init_upcall_msg(struct gss_upcall_msg *gmsg,
498 struct gss_sec *gsec, char *obdname,
499 struct gss_upcall_msg_data *gmd)
501 struct rpc_pipe_msg *rpcmsg;
504 /* 2 refs: 1 for hash, 1 for current user */
505 init_waitqueue_head(&gmsg->gum_waitq);
506 list_add(&gmsg->gum_list, &gsec->gs_upcalls);
507 atomic_set(&gmsg->gum_refcount, 2);
508 gmsg->gum_gsec = gsec;
509 strncpy(gmsg->gum_obdname, obdname, sizeof(gmsg->gum_obdname));
510 memcpy(&gmsg->gum_data, gmd, sizeof(*gmd));
512 rpcmsg = &gmsg->gum_base;
513 INIT_LIST_HEAD(&rpcmsg->list);
514 rpcmsg->data = &gmsg->gum_data;
515 rpcmsg->len = sizeof(gmsg->gum_data);
520 #endif /* __KERNEL__ */
522 /* this seems to be used only from userspace code */
524 /********************************************
525 * gss cred manipulation helpers *
526 ********************************************/
528 int gss_cred_is_uptodate_ctx(struct ptlrpc_cred *cred)
530 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
533 read_lock(&gss_ctx_lock);
534 if (((cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) ==
535 PTLRPC_CRED_UPTODATE) &&
538 read_unlock(&gss_ctx_lock);
544 struct gss_cl_ctx *gss_get_ctx(struct gss_cl_ctx *ctx)
546 atomic_inc(&ctx->gc_refcount);
551 void gss_destroy_ctx(struct gss_cl_ctx *ctx)
555 CDEBUG(D_SEC, "destroy cl_ctx %p\n", ctx);
557 kgss_delete_sec_context(&ctx->gc_gss_ctx);
559 if (ctx->gc_wire_ctx.len > 0) {
560 OBD_FREE(ctx->gc_wire_ctx.data, ctx->gc_wire_ctx.len);
561 ctx->gc_wire_ctx.len = 0;
564 OBD_FREE(ctx, sizeof(*ctx));
568 void gss_put_ctx(struct gss_cl_ctx *ctx)
570 if (atomic_dec_and_test(&ctx->gc_refcount))
571 gss_destroy_ctx(ctx);
575 struct gss_cl_ctx *gss_cred_get_ctx(struct ptlrpc_cred *cred)
577 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
578 struct gss_cl_ctx *ctx = NULL;
580 read_lock(&gss_ctx_lock);
582 ctx = gss_get_ctx(gcred->gc_ctx);
583 read_unlock(&gss_ctx_lock);
588 void gss_cred_set_ctx(struct ptlrpc_cred *cred, struct gss_cl_ctx *ctx)
590 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
591 struct gss_cl_ctx *old;
595 if (kgss_inquire_context(ctx->gc_gss_ctx, &ctx_expiry)) {
596 CERROR("unable to get expire time\n");
597 ctx_expiry = 1; /* make it expired now */
599 cred->pc_expire = (unsigned long) ctx_expiry;
601 write_lock(&gss_ctx_lock);
604 set_bit(PTLRPC_CRED_UPTODATE_BIT, &cred->pc_flags);
605 write_unlock(&gss_ctx_lock);
609 CDEBUG(D_SEC, "client refreshed gss cred %p(uid %u)\n",
615 simple_get_bytes(char **buf, __u32 *buflen, void *res, __u32 reslen)
617 if (*buflen < reslen) {
618 CERROR("buflen %u < %u\n", *buflen, reslen);
622 memcpy(res, *buf, reslen);
632 * - wire_ctx (rawobj)
633 * - mech_ctx? (rawobj)
636 int gss_parse_init_downcall(struct gss_api_mech *gm, rawobj_t *buf,
637 struct gss_cl_ctx **gc,
638 struct gss_upcall_msg_data *gmd, int *gss_err)
640 char *p = (char *)buf->data;
641 struct gss_cl_ctx *ctx;
642 __u32 len = buf->len;
643 unsigned int timeout;
651 OBD_ALLOC(ctx, sizeof(*ctx));
655 ctx->gc_proc = RPC_GSS_PROC_DATA;
657 spin_lock_init(&ctx->gc_seq_lock);
658 atomic_set(&ctx->gc_refcount,1);
660 if (simple_get_bytes(&p, &len, &gmd->gum_pag, sizeof(gmd->gum_pag)))
662 if (simple_get_bytes(&p, &len, &gmd->gum_uid, sizeof(gmd->gum_uid)))
664 if (simple_get_bytes(&p, &len, &gmd->gum_svc, sizeof(gmd->gum_svc)))
666 if (simple_get_bytes(&p, &len, &gmd->gum_nal, sizeof(gmd->gum_nal)))
668 if (simple_get_bytes(&p, &len, &gmd->gum_netid, sizeof(gmd->gum_netid)))
670 if (simple_get_bytes(&p, &len, &gmd->gum_nid, sizeof(gmd->gum_nid)))
672 /* FIXME: discarded timeout for now */
673 if (simple_get_bytes(&p, &len, &timeout, sizeof(timeout)))
675 if (simple_get_bytes(&p, &len, &ctx->gc_win, sizeof(ctx->gc_win)))
678 /* lgssd signals an error by passing ctx->gc_win = 0: */
680 /* in which case the next 2 int are:
684 if (simple_get_bytes(&p, &len, &err, sizeof(err))) {
688 if (simple_get_bytes(&p, &len, gss_err, sizeof(*gss_err))) {
692 if (err == 0 && *gss_err == 0) {
693 CERROR("no error passed from downcall\n");
699 if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
701 if (rawobj_dup(&ctx->gc_wire_ctx, &tmp_buf)) {
705 if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
706 goto err_free_wire_ctx;
708 CERROR("unexpected trailing %u bytes\n", len);
709 goto err_free_wire_ctx;
711 if (kgss_import_sec_context(&tmp_buf, gm, &ctx->gc_gss_ctx))
712 goto err_free_wire_ctx;
718 if (ctx->gc_wire_ctx.data)
719 OBD_FREE(ctx->gc_wire_ctx.data, ctx->gc_wire_ctx.len);
721 OBD_FREE(ctx, sizeof(*ctx));
722 CDEBUG(D_SEC, "err_code %d, gss code %d\n", err, *gss_err);
726 /***************************************
728 ***************************************/
730 static int gss_cred_refresh(struct ptlrpc_cred *cred)
732 struct obd_import *import;
733 struct gss_sec *gsec;
734 struct gss_upcall_msg *gss_msg, *gss_new;
735 struct gss_upcall_msg_data gmd;
736 struct dentry *dentry;
737 char *obdname, *obdtype;
744 /* any flags means it has been handled, do nothing */
745 if (cred->pc_flags & PTLRPC_CRED_FLAGS_MASK)
748 LASSERT(cred->pc_sec);
749 LASSERT(cred->pc_sec->ps_import);
750 LASSERT(cred->pc_sec->ps_import->imp_obd);
752 import = cred->pc_sec->ps_import;
753 if (!import->imp_connection) {
754 CERROR("import has no connection set\n");
758 gmd.gum_pag = cred->pc_pag;
759 gmd.gum_uid = cred->pc_uid;
760 gmd.gum_nal = import->imp_connection->c_peer.peer_ni->pni_number;
762 gmd.gum_nid = import->imp_connection->c_peer.peer_id.nid;
764 obdtype = import->imp_obd->obd_type->typ_name;
765 if (!strcmp(obdtype, OBD_MDC_DEVICENAME))
766 gmd.gum_svc = LUSTRE_GSS_SVC_MDS;
767 else if (!strcmp(obdtype, OBD_OSC_DEVICENAME))
768 gmd.gum_svc = LUSTRE_GSS_SVC_OSS;
770 CERROR("gss on %s?\n", obdtype);
774 gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
775 obdname = import->imp_obd->obd_name;
776 dentry = gsec->gs_depipe;
780 CDEBUG(D_SEC, "Initiate gss context %p(%u@%s)\n",
781 container_of(cred, struct gss_cred, gc_base),
782 cred->pc_uid, import->imp_target_uuid.uuid);
785 spin_lock(&gsec->gs_lock);
786 gss_msg = gss_find_upcall(gsec, obdname, &gmd);
789 OBD_FREE(gss_new, sizeof(*gss_new));
796 spin_unlock(&gsec->gs_lock);
797 OBD_ALLOC(gss_new, sizeof(*gss_new));
802 /* so far we'v created gss_new */
803 gss_init_upcall_msg(gss_new, gsec, obdname, &gmd);
805 /* we'v created upcall msg, nobody else should touch the
806 * flag of this cred, unless be set as dead/expire by
807 * administrator via lctl etc.
809 if (cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) {
810 CWARN("cred %p("LPU64"/%u) was set flags %lx unexpectedly\n",
811 cred, cred->pc_pag, cred->pc_uid, cred->pc_flags);
812 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
813 gss_unhash_msg_nolock(gss_new);
814 spin_unlock(&gsec->gs_lock);
815 gss_release_msg(gss_new);
819 /* need to make upcall now */
820 spin_unlock(&gsec->gs_lock);
821 res = rpc_queue_upcall(dentry->d_inode, &gss_new->gum_base);
823 CERROR("rpc_queue_upcall failed: %d\n", res);
824 gss_unhash_msg(gss_new);
825 gss_release_msg(gss_new);
826 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
830 spin_lock(&gsec->gs_lock);
833 /* upcall might finish quickly */
834 if (list_empty(&gss_msg->gum_list)) {
835 spin_unlock(&gsec->gs_lock);
840 init_waitqueue_entry(&wait, current);
841 set_current_state(TASK_INTERRUPTIBLE);
842 add_wait_queue(&gss_msg->gum_waitq, &wait);
843 spin_unlock(&gsec->gs_lock);
846 res = schedule_timeout(CRED_REFRESH_UPCALL_TIMEOUT * HZ);
852 remove_wait_queue(&gss_msg->gum_waitq, &wait);
854 /* - the one who refresh the cred for us should also be responsible
855 * to set the status of cred, we can simply return.
856 * - if cred flags has been set, we also don't need to do that again,
857 * no matter signal pending or timeout etc.
859 if (!gss_new || cred->pc_flags & PTLRPC_CRED_FLAGS_MASK)
862 if (signal_pending(current)) {
863 CERROR("%s: cred %p: interrupted upcall\n",
864 current->comm, cred);
865 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
867 } else if (res == 0) {
868 CERROR("cred %p: upcall timedout\n", cred);
869 set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
875 gss_release_msg(gss_msg);
879 #else /* !__KERNEL__ */
880 extern int lgss_handle_krb5_upcall(uid_t uid, __u32 dest_ip,
881 char *obd_name, char *buf, int bufsize,
882 int (*callback)(char*, unsigned long));
884 static int gss_cred_refresh(struct ptlrpc_cred *cred)
888 struct obd_import *imp;
889 struct gss_sec *gsec;
890 struct gss_api_mech *mech;
891 struct gss_cl_ctx *ctx = NULL;
896 struct gss_upcall_msg_data gmd = { 0 };
899 LASSERT(cred->pc_sec);
900 LASSERT(cred->pc_sec->ps_import);
901 LASSERT(cred->pc_sec->ps_import->imp_obd);
903 if (ptlrpcs_cred_is_uptodate(cred))
906 imp = cred->pc_sec->ps_import;
907 peer_nid = imp->imp_connection->c_peer.peer_id.nid;
908 dest_ip = (__u32) (peer_nid & 0xFFFFFFFF);
909 subflavor = cred->pc_sec->ps_flavor;
911 if (subflavor != PTLRPCS_SUBFLVR_KRB5I) {
912 CERROR("unknown subflavor %u\n", subflavor);
913 GOTO(err_out, rc = -EINVAL);
916 rc = lgss_handle_krb5_upcall(cred->pc_uid, dest_ip,
917 imp->imp_obd->obd_name,
919 gss_send_secinit_rpc);
927 gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
928 mech = gsec->gs_mech;
931 rc = gss_parse_init_downcall(mech, &obj, &ctx, &gmd,
934 CERROR("parse init downcall: rpc %d, gss 0x%x\n", rc, gss_err);
935 if (rc != -ERESTART || gss_err != 0)
936 set_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags);
943 gss_cred_set_ctx(cred, ctx);
944 LASSERT(gss_cred_is_uptodate_ctx(cred));
948 set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
953 static int gss_cred_match(struct ptlrpc_cred *cred,
954 struct vfs_cred *vcred)
956 RETURN(cred->pc_pag == vcred->vc_pag);
959 static int gss_cred_sign(struct ptlrpc_cred *cred,
960 struct ptlrpc_request *req)
962 struct gss_cred *gcred;
963 struct gss_cl_ctx *ctx;
965 __u32 *vp, *vpsave, vlen, seclen;
966 __u32 seqnum, major, rc = 0;
969 LASSERT(req->rq_reqbuf);
970 LASSERT(req->rq_cred == cred);
972 gcred = container_of(cred, struct gss_cred, gc_base);
973 ctx = gss_cred_get_ctx(cred);
975 CERROR("cred %p("LPU64"/%u) invalidated?\n",
976 cred, cred->pc_pag, cred->pc_uid);
980 lmsg.len = req->rq_reqlen;
981 lmsg.data = (__u8 *) req->rq_reqmsg;
983 vp = (__u32 *) (lmsg.data + lmsg.len);
984 vlen = req->rq_reqbuf_len - sizeof(struct ptlrpcs_wire_hdr) -
988 if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
989 CERROR("vlen %d, need %d\n",
990 vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
995 spin_lock(&ctx->gc_seq_lock);
996 seqnum = ctx->gc_seq++;
997 spin_unlock(&ctx->gc_seq_lock);
999 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* version */
1000 *vp++ = cpu_to_le32(PTLRPCS_FLVR_KRB5I); /* subflavor */
1001 *vp++ = cpu_to_le32(ctx->gc_proc); /* proc */
1002 *vp++ = cpu_to_le32(seqnum); /* seq */
1003 *vp++ = cpu_to_le32(PTLRPCS_GSS_SVC_INTEGRITY); /* service */
1006 if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
1010 CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
1012 vpsave = vp++; /* reserve for size */
1016 mic.data = (unsigned char *)vp;
1018 CDEBUG(D_SEC, "reqbuf at %p, lmsg at %p, len %d, mic at %p, len %d\n",
1019 req->rq_reqbuf, lmsg.data, lmsg.len, mic.data, mic.len);
1020 major = kgss_get_mic(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, &lmsg, &mic);
1022 CERROR("cred %p: req %p compute mic error, major %x\n",
1028 *vpsave = cpu_to_le32(mic.len);
1030 seclen = seclen - vlen + mic.len;
1031 buf_to_sec_hdr(req->rq_reqbuf)->sec_len = cpu_to_le32(seclen);
1032 req->rq_reqdata_len += size_round(seclen);
1033 CDEBUG(D_SEC, "msg size %d, checksum size %d, total sec size %d\n",
1034 lmsg.len, mic.len, seclen);
1040 static int gss_cred_verify(struct ptlrpc_cred *cred,
1041 struct ptlrpc_request *req)
1043 struct gss_cred *gcred;
1044 struct gss_cl_ctx *ctx;
1045 struct ptlrpcs_wire_hdr *sec_hdr;
1047 __u32 *vp, vlen, subflavor, proc, seq, svc;
1048 __u32 major, minor, rc;
1051 LASSERT(req->rq_repbuf);
1052 LASSERT(req->rq_cred == cred);
1054 sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
1055 vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr) + sec_hdr->msg_len);
1056 vlen = sec_hdr->sec_len;
1059 CERROR("reply sec size %u too small\n", vlen);
1063 if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
1064 CERROR("reply have different gss version\n");
1067 subflavor = le32_to_cpu(*vp++);
1068 proc = le32_to_cpu(*vp++);
1072 case PTLRPCS_GSS_PROC_DATA:
1073 seq = le32_to_cpu(*vp++);
1074 svc = le32_to_cpu(*vp++);
1075 if (svc != PTLRPCS_GSS_SVC_INTEGRITY) {
1076 CERROR("Unknown svc %d\n", svc);
1080 CERROR("Unexpected ctx handle\n");
1083 mic.len = le32_to_cpu(*vp++);
1085 if (vlen < mic.len) {
1086 CERROR("vlen %d, mic.len %d\n", vlen, mic.len);
1089 mic.data = (unsigned char *)vp;
1091 gcred = container_of(cred, struct gss_cred, gc_base);
1092 ctx = gss_cred_get_ctx(cred);
1095 lmsg.len = sec_hdr->msg_len;
1096 lmsg.data = (__u8 *) buf_to_lustre_msg(req->rq_repbuf);
1098 major = kgss_verify_mic(ctx->gc_gss_ctx, &lmsg, &mic, NULL);
1099 if (major != GSS_S_COMPLETE) {
1100 CERROR("cred %p: req %p verify mic error: major %x\n",
1103 if (major == GSS_S_CREDENTIALS_EXPIRED ||
1104 major == GSS_S_CONTEXT_EXPIRED) {
1105 ptlrpcs_cred_expire(cred);
1106 req->rq_ptlrpcs_restart = 1;
1111 GOTO(proc_data_out, rc);
1114 req->rq_repmsg = (struct lustre_msg *) lmsg.data;
1115 req->rq_replen = lmsg.len;
1117 /* here we could check the seq number is the same one
1118 * we sent to server. but portals has prevent us from
1119 * replay attack, so maybe we don't need check it again.
1125 case PTLRPCS_GSS_PROC_ERR:
1126 major = le32_to_cpu(*vp++);
1127 minor = le32_to_cpu(*vp++);
1128 /* server return NO_CONTEXT might be caused by context expire
1129 * or server reboot/failover. we refresh the cred transparently
1131 * In some cases, our gss handle is possible to be incidentally
1132 * identical to another handle since the handle itself is not
1133 * fully random. In krb5 case, the GSS_S_BAD_SIG will be
1134 * returned, maybe other gss error for other mechanism. Here we
1135 * only consider krb5 mech (FIXME) and try to establish new
1138 if (major == GSS_S_NO_CONTEXT ||
1139 major == GSS_S_BAD_SIG) {
1140 CWARN("req %p: server report cred %p %s, expired?\n",
1141 req, cred, (major == GSS_S_NO_CONTEXT) ?
1142 "NO_CONTEXT" : "BAD_SIG");
1144 ptlrpcs_cred_expire(cred);
1145 req->rq_ptlrpcs_restart = 1;
1148 CERROR("req %p: unrecognized gss error (%x/%x)\n",
1154 CERROR("unknown gss proc %d\n", proc);
1161 static int gss_cred_seal(struct ptlrpc_cred *cred,
1162 struct ptlrpc_request *req)
1164 struct gss_cred *gcred;
1165 struct gss_cl_ctx *ctx;
1166 struct ptlrpcs_wire_hdr *sec_hdr;
1167 rawobj_buf_t msg_buf;
1168 rawobj_t cipher_buf;
1169 __u32 *vp, *vpsave, vlen, seclen;
1170 __u32 major, seqnum, rc = 0;
1173 LASSERT(req->rq_reqbuf);
1174 LASSERT(req->rq_cred == cred);
1176 gcred = container_of(cred, struct gss_cred, gc_base);
1177 ctx = gss_cred_get_ctx(cred);
1179 CERROR("cred %p("LPU64"/%u) invalidated?\n",
1180 cred, cred->pc_pag, cred->pc_uid);
1184 vp = (__u32 *) (req->rq_reqbuf + sizeof(*sec_hdr));
1185 vlen = req->rq_reqbuf_len - sizeof(*sec_hdr);
1188 if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
1189 CERROR("vlen %d, need %d\n",
1190 vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
1195 spin_lock(&ctx->gc_seq_lock);
1196 seqnum = ctx->gc_seq++;
1197 spin_unlock(&ctx->gc_seq_lock);
1199 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* version */
1200 *vp++ = cpu_to_le32(PTLRPCS_FLVR_KRB5P); /* subflavor */
1201 *vp++ = cpu_to_le32(ctx->gc_proc); /* proc */
1202 *vp++ = cpu_to_le32(seqnum); /* seq */
1203 *vp++ = cpu_to_le32(PTLRPCS_GSS_SVC_PRIVACY); /* service */
1206 if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
1210 CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
1212 vpsave = vp++; /* reserve for size */
1215 msg_buf.buf = (__u8 *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1216 msg_buf.buflen = req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
1217 GSS_PRIVBUF_SUFFIX_LEN;
1218 msg_buf.dataoff = GSS_PRIVBUF_PREFIX_LEN;
1219 msg_buf.datalen = req->rq_reqlen;
1221 cipher_buf.data = (__u8 *) vp;
1222 cipher_buf.len = vlen;
1224 major = kgss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1225 &msg_buf, &cipher_buf);
1227 CERROR("cred %p: error wrap: major 0x%x\n", cred, major);
1228 GOTO(out, rc = -EINVAL);
1231 *vpsave = cpu_to_le32(cipher_buf.len);
1233 seclen = seclen - vlen + cipher_buf.len;
1234 sec_hdr = buf_to_sec_hdr(req->rq_reqbuf);
1235 sec_hdr->sec_len = cpu_to_le32(seclen);
1236 req->rq_reqdata_len += size_round(seclen);
1238 CDEBUG(D_SEC, "msg size %d, total sec size %d\n",
1239 req->rq_reqlen, seclen);
1245 static int gss_cred_unseal(struct ptlrpc_cred *cred,
1246 struct ptlrpc_request *req)
1248 struct gss_cred *gcred;
1249 struct gss_cl_ctx *ctx;
1250 struct ptlrpcs_wire_hdr *sec_hdr;
1251 rawobj_t cipher_text, plain_text;
1252 __u32 *vp, vlen, subflavor, proc, seq, svc;
1256 LASSERT(req->rq_repbuf);
1257 LASSERT(req->rq_cred == cred);
1259 sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
1260 if (sec_hdr->msg_len != 0) {
1261 CERROR("unexpected msg_len %u\n", sec_hdr->msg_len);
1265 vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr));
1266 vlen = sec_hdr->sec_len;
1269 CERROR("reply sec size %u too small\n", vlen);
1273 if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
1274 CERROR("reply have different gss version\n");
1277 subflavor = le32_to_cpu(*vp++);
1278 proc = le32_to_cpu(*vp++);
1279 seq = le32_to_cpu(*vp++);
1280 svc = le32_to_cpu(*vp++);
1284 case PTLRPCS_GSS_PROC_DATA:
1285 if (svc != PTLRPCS_GSS_SVC_PRIVACY) {
1286 CERROR("Unknown svc %d\n", svc);
1290 CERROR("Unexpected ctx handle\n");
1295 cipher_text.len = le32_to_cpu(*vp++);
1296 cipher_text.data = (__u8 *) vp;
1299 if (vlen < cipher_text.len) {
1300 CERROR("cipher text to be %u while buf only %u\n",
1301 cipher_text.len, vlen);
1305 plain_text = cipher_text;
1307 gcred = container_of(cred, struct gss_cred, gc_base);
1308 ctx = gss_cred_get_ctx(cred);
1311 major = kgss_unwrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1312 &cipher_text, &plain_text);
1314 CERROR("cred %p: error unwrap: major 0x%x\n",
1317 if (major == GSS_S_CREDENTIALS_EXPIRED ||
1318 major == GSS_S_CONTEXT_EXPIRED) {
1319 ptlrpcs_cred_expire(cred);
1320 req->rq_ptlrpcs_restart = 1;
1328 req->rq_repmsg = (struct lustre_msg *) vp;
1329 req->rq_replen = plain_text.len;
1336 CERROR("unknown gss proc %d\n", proc);
1343 static void destroy_gss_context(struct ptlrpc_cred *cred)
1345 struct ptlrpcs_wire_hdr *hdr;
1346 struct lustre_msg *lmsg;
1347 struct gss_cred *gcred;
1348 struct ptlrpc_request req;
1349 struct obd_import *imp;
1350 __u32 *vp, lmsg_size;
1351 struct ptlrpc_request *raw_req = NULL;
1352 const int repbuf_len = 256;
1357 imp = cred->pc_sec->ps_import;
1360 if (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags) ||
1361 !test_bit(PTLRPC_CRED_UPTODATE_BIT, &cred->pc_flags)) {
1362 CDEBUG(D_SEC, "Destroy dead cred %p(%u@%s)\n",
1363 cred, cred->pc_uid, imp->imp_target_uuid.uuid);
1370 /* cred's refcount is 0, steal one */
1371 atomic_inc(&cred->pc_refcount);
1373 gcred = container_of(cred, struct gss_cred, gc_base);
1374 gcred->gc_ctx->gc_proc = PTLRPCS_GSS_PROC_DESTROY;
1376 CDEBUG(D_SEC, "client destroy gss cred %p(%u@%s)\n",
1377 gcred, cred->pc_uid, imp->imp_target_uuid.uuid);
1379 lmsg_size = lustre_msg_size(0, NULL);
1380 req.rq_req_secflvr = cred->pc_sec->ps_flavor;
1382 req.rq_reqbuf_len = sizeof(*hdr) + lmsg_size +
1383 ptlrpcs_est_req_payload(&req, lmsg_size);
1385 OBD_ALLOC(req.rq_reqbuf, req.rq_reqbuf_len);
1386 if (!req.rq_reqbuf) {
1387 CERROR("Fail to alloc reqbuf, cancel anyway\n");
1388 atomic_dec(&cred->pc_refcount);
1394 hdr = buf_to_sec_hdr(req.rq_reqbuf);
1395 hdr->flavor = cpu_to_le32(PTLRPCS_FLVR_GSS_AUTH);
1396 hdr->msg_len = cpu_to_le32(lmsg_size);
1397 hdr->sec_len = cpu_to_le32(0);
1399 /* lustre message */
1400 lmsg = buf_to_lustre_msg(req.rq_reqbuf);
1401 lustre_init_msg(lmsg, 0, NULL, NULL);
1402 lmsg->handle = imp->imp_remote_handle;
1403 lmsg->type = PTL_RPC_MSG_REQUEST;
1404 lmsg->opc = SEC_FINI;
1406 lmsg->conn_cnt = imp->imp_conn_cnt;
1407 /* add this for randomize */
1408 get_random_bytes(&lmsg->last_xid, sizeof(lmsg->last_xid));
1409 get_random_bytes(&lmsg->transno, sizeof(lmsg->transno));
1411 vp = (__u32 *) req.rq_reqbuf;
1414 req.rq_reqmsg = buf_to_lustre_msg(req.rq_reqbuf);
1415 req.rq_reqlen = lmsg_size;
1416 req.rq_reqdata_len = sizeof(*hdr) + lmsg_size;
1418 if (gss_cred_sign(cred, &req)) {
1419 CERROR("failed to sign, cancel anyway\n");
1420 atomic_dec(&cred->pc_refcount);
1423 atomic_dec(&cred->pc_refcount);
1425 OBD_ALLOC(repbuf, repbuf_len);
1429 raw_req = ptl_do_rawrpc(imp, req.rq_reqbuf, req.rq_reqbuf_len,
1430 req.rq_reqdata_len, repbuf, repbuf_len, &replen,
1431 SECFINI_RPC_TIMEOUT, &rc);
1433 OBD_FREE(repbuf, repbuf_len);
1436 if (raw_req == NULL)
1437 OBD_FREE(req.rq_reqbuf, req.rq_reqbuf_len);
1439 rawrpc_req_finished(raw_req);
1443 static void gss_cred_destroy(struct ptlrpc_cred *cred)
1445 struct gss_cred *gcred;
1449 LASSERT(!atomic_read(&cred->pc_refcount));
1451 gcred = container_of(cred, struct gss_cred, gc_base);
1452 if (gcred->gc_ctx) {
1453 destroy_gss_context(cred);
1454 gss_put_ctx(gcred->gc_ctx);
1457 CDEBUG(D_SEC, "sec.gss %p: destroy cred %p\n", cred->pc_sec, gcred);
1459 OBD_FREE(gcred, sizeof(*gcred));
1463 static struct ptlrpc_credops gss_credops = {
1464 .refresh = gss_cred_refresh,
1465 .match = gss_cred_match,
1466 .sign = gss_cred_sign,
1467 .verify = gss_cred_verify,
1468 .seal = gss_cred_seal,
1469 .unseal = gss_cred_unseal,
1470 .destroy = gss_cred_destroy,
1474 /*******************************************
1476 *******************************************/
1478 gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
1479 char *dst, size_t buflen)
1481 char *data = (char *)msg->data + msg->copied;
1482 ssize_t mlen = msg->len;
1488 left = copy_to_user(dst, data, mlen);
1494 msg->copied += mlen;
1500 gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
1503 const int bufsize = 1024;
1505 struct inode *inode = filp->f_dentry->d_inode;
1506 struct rpc_inode *rpci = RPC_I(inode);
1507 struct obd_import *import;
1508 struct ptlrpc_sec *sec;
1509 struct gss_sec *gsec;
1511 struct gss_api_mech *mech;
1512 struct vfs_cred vcred = { 0 };
1513 struct ptlrpc_cred *cred;
1514 struct gss_upcall_msg *gss_msg;
1515 struct gss_upcall_msg_data gmd = { 0 };
1516 struct gss_cl_ctx *ctx = NULL;
1521 if (mlen > bufsize) {
1522 CERROR("mlen %ld > bufsize %d\n", (long)mlen, bufsize);
1526 OBD_ALLOC(buf, bufsize);
1528 CERROR("alloc mem failed\n");
1532 left = copy_from_user(buf, src, mlen);
1534 GOTO(err_free, err = -EFAULT);
1536 obj.data = (unsigned char *)buf;
1539 LASSERT(rpci->private);
1540 gsec = (struct gss_sec *)rpci->private;
1541 sec = &gsec->gs_base;
1542 LASSERT(sec->ps_import);
1543 import = class_import_get(sec->ps_import);
1544 LASSERT(import->imp_obd);
1545 obdname = import->imp_obd->obd_name;
1546 mech = gsec->gs_mech;
1548 err = gss_parse_init_downcall(mech, &obj, &ctx, &gmd, &gss_err);
1550 CERROR("parse init downcall err %d\n", err);
1552 vcred.vc_pag = gmd.gum_pag;
1553 vcred.vc_uid = gmd.gum_uid;
1555 cred = ptlrpcs_cred_lookup(sec, &vcred);
1557 CWARN("didn't find cred for uid %u\n", vcred.vc_uid);
1558 GOTO(err, err = -EINVAL);
1561 if (err || gss_err) {
1562 set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
1563 if (err != -ERESTART || gss_err != 0)
1564 set_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags);
1565 CERROR("cred %p: rpc err %d, gss err 0x%x, fatal %d\n",
1567 (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags) != 0));
1569 CDEBUG(D_SEC, "get initial ctx:\n");
1570 gss_cred_set_ctx(cred, ctx);
1573 spin_lock(&gsec->gs_lock);
1574 gss_msg = gss_find_upcall(gsec, obdname, &gmd);
1576 gss_unhash_msg_nolock(gss_msg);
1577 spin_unlock(&gsec->gs_lock);
1578 gss_release_msg(gss_msg);
1580 spin_unlock(&gsec->gs_lock);
1582 ptlrpcs_cred_put(cred, 1);
1583 class_import_put(import);
1584 OBD_FREE(buf, bufsize);
1588 gss_destroy_ctx(ctx);
1589 class_import_put(import);
1591 OBD_FREE(buf, bufsize);
1592 CDEBUG(D_SEC, "gss_pipe_downcall returning %d\n", err);
1597 void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
1599 struct gss_upcall_msg *gmsg;
1600 static unsigned long ratelimit;
1603 LASSERT(list_empty(&msg->list));
1605 if (msg->errno >= 0) {
1610 gmsg = container_of(msg, struct gss_upcall_msg, gum_base);
1611 CDEBUG(D_SEC, "destroy gmsg %p\n", gmsg);
1612 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
1613 atomic_inc(&gmsg->gum_refcount);
1614 gss_unhash_msg(gmsg);
1615 if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
1616 unsigned long now = get_seconds();
1617 if (time_after(now, ratelimit)) {
1618 CWARN("sec.gss upcall timed out.\n"
1619 "Please check user daemon is running!\n");
1620 ratelimit = now + 15;
1623 gss_release_msg(gmsg);
1628 void gss_pipe_release(struct inode *inode)
1630 struct rpc_inode *rpci = RPC_I(inode);
1631 struct ptlrpc_sec *sec;
1632 struct gss_sec *gsec;
1635 gsec = (struct gss_sec *)rpci->private;
1636 sec = &gsec->gs_base;
1637 spin_lock(&gsec->gs_lock);
1638 while (!list_empty(&gsec->gs_upcalls)) {
1639 struct gss_upcall_msg *gmsg;
1641 gmsg = list_entry(gsec->gs_upcalls.next,
1642 struct gss_upcall_msg, gum_list);
1643 LASSERT(list_empty(&gmsg->gum_base.list));
1644 gmsg->gum_base.errno = -EPIPE;
1645 atomic_inc(&gmsg->gum_refcount);
1646 gss_unhash_msg_nolock(gmsg);
1647 gss_release_msg(gmsg);
1649 spin_unlock(&gsec->gs_lock);
1653 static struct rpc_pipe_ops gss_upcall_ops = {
1654 .upcall = gss_pipe_upcall,
1655 .downcall = gss_pipe_downcall,
1656 .destroy_msg = gss_pipe_destroy_msg,
1657 .release_pipe = gss_pipe_release,
1659 #endif /* __KERNEL__ */
1661 /*********************************************
1662 * GSS security APIs *
1663 *********************************************/
1666 struct ptlrpc_sec* gss_create_sec(__u32 flavor,
1667 const char *pipe_dir,
1670 struct gss_sec *gsec;
1671 struct ptlrpc_sec *sec;
1680 LASSERT(SEC_FLAVOR_MAJOR(flavor) == PTLRPCS_FLVR_MAJOR_GSS);
1682 OBD_ALLOC(gsec, sizeof(*gsec));
1684 CERROR("can't alloc gsec\n");
1688 gsec->gs_mech = kgss_subflavor_to_mech(SEC_FLAVOR_SUB(flavor));
1689 if (!gsec->gs_mech) {
1690 CERROR("subflavor 0x%x not found\n", flavor);
1694 /* initialize gss sec */
1696 INIT_LIST_HEAD(&gsec->gs_upcalls);
1697 spin_lock_init(&gsec->gs_lock);
1699 pipepath_len = strlen(LUSTRE_PIPEDIR) + strlen(pipe_dir) +
1700 strlen(gsec->gs_mech->gm_name) + 3;
1701 OBD_ALLOC(gsec->gs_pipepath, pipepath_len);
1702 if (!gsec->gs_pipepath)
1705 /* pipe rpc require root permission */
1706 save_uid = current->fsuid;
1709 sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s", pipe_dir);
1710 if (IS_ERR(rpc_mkdir(gsec->gs_pipepath, NULL))) {
1711 CERROR("can't make pipedir %s\n", gsec->gs_pipepath);
1715 sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s/%s", pipe_dir,
1716 gsec->gs_mech->gm_name);
1717 gsec->gs_depipe = rpc_mkpipe(gsec->gs_pipepath, gsec,
1718 &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
1719 if (IS_ERR(gsec->gs_depipe)) {
1720 CERROR("failed to make rpc_pipe %s: %ld\n",
1721 gsec->gs_pipepath, PTR_ERR(gsec->gs_depipe));
1724 CDEBUG(D_SEC, "gss sec %p, pipe path %s\n", gsec, gsec->gs_pipepath);
1727 sec = &gsec->gs_base;
1728 sec->ps_expire = GSS_CREDCACHE_EXPIRE;
1729 sec->ps_nextgc = get_seconds() + sec->ps_expire;
1732 current->fsuid = save_uid;
1734 CDEBUG(D_SEC, "Create sec.gss %p\n", gsec);
1739 pos = strrchr(gsec->gs_pipepath, '/');
1742 rpc_rmdir(gsec->gs_pipepath);
1744 current->fsuid = save_uid;
1745 OBD_FREE(gsec->gs_pipepath, pipepath_len);
1748 kgss_mech_put(gsec->gs_mech);
1750 OBD_FREE(gsec, sizeof(*gsec));
1755 void gss_destroy_sec(struct ptlrpc_sec *sec)
1757 struct gss_sec *gsec;
1764 gsec = container_of(sec, struct gss_sec, gs_base);
1765 CDEBUG(D_SEC, "Destroy sec.gss %p\n", gsec);
1767 LASSERT(gsec->gs_mech);
1768 LASSERT(!atomic_read(&sec->ps_refcount));
1769 LASSERT(!atomic_read(&sec->ps_credcount));
1771 pipepath_len = strlen(gsec->gs_pipepath) + 1;
1772 rpc_unlink(gsec->gs_pipepath);
1773 pos = strrchr(gsec->gs_pipepath, '/');
1776 rpc_rmdir(gsec->gs_pipepath);
1777 OBD_FREE(gsec->gs_pipepath, pipepath_len);
1780 kgss_mech_put(gsec->gs_mech);
1781 OBD_FREE(gsec, sizeof(*gsec));
1786 struct ptlrpc_cred * gss_create_cred(struct ptlrpc_sec *sec,
1787 struct vfs_cred *vcred)
1789 struct gss_cred *gcred;
1790 struct ptlrpc_cred *cred;
1793 OBD_ALLOC(gcred, sizeof(*gcred));
1797 cred = &gcred->gc_base;
1798 INIT_LIST_HEAD(&cred->pc_hash);
1799 atomic_set(&cred->pc_refcount, 0);
1801 cred->pc_ops = &gss_credops;
1802 cred->pc_expire = 0;
1804 cred->pc_pag = vcred->vc_pag;
1805 cred->pc_uid = vcred->vc_uid;
1806 CDEBUG(D_SEC, "create a gss cred at %p("LPU64"/%u)\n",
1807 cred, vcred->vc_pag, vcred->vc_uid);
1812 static int gss_estimate_payload(struct ptlrpc_sec *sec,
1813 struct ptlrpc_request *req,
1816 switch (SEC_FLAVOR_SVC(req->rq_req_secflvr)) {
1817 case PTLRPCS_SVC_AUTH:
1818 return GSS_MAX_AUTH_PAYLOAD;
1819 case PTLRPCS_SVC_PRIV:
1820 return size_round16(GSS_MAX_AUTH_PAYLOAD + msgsize +
1821 GSS_PRIVBUF_PREFIX_LEN +
1822 GSS_PRIVBUF_SUFFIX_LEN);
1829 static int gss_alloc_reqbuf(struct ptlrpc_sec *sec,
1830 struct ptlrpc_request *req,
1833 int msg_payload, sec_payload;
1837 /* In PRIVACY mode, lustre message is always 0 (already encoded into
1838 * security payload).
1840 privacy = (SEC_FLAVOR_SVC(req->rq_req_secflvr) == PTLRPCS_SVC_PRIV);
1841 msg_payload = privacy ? 0 : lmsg_size;
1842 sec_payload = gss_estimate_payload(sec, req, lmsg_size);
1844 rc = sec_alloc_reqbuf(sec, req, msg_payload, sec_payload);
1849 int buflen = lmsg_size + GSS_PRIVBUF_PREFIX_LEN +
1850 GSS_PRIVBUF_SUFFIX_LEN;
1853 OBD_ALLOC(buf, buflen);
1855 CERROR("Fail to alloc %d\n", buflen);
1856 sec_free_reqbuf(sec, req);
1859 req->rq_reqmsg = (struct lustre_msg *)
1860 (buf + GSS_PRIVBUF_PREFIX_LEN);
1866 static void gss_free_reqbuf(struct ptlrpc_sec *sec,
1867 struct ptlrpc_request *req)
1873 LASSERT(req->rq_reqmsg);
1874 LASSERT(req->rq_reqlen);
1876 privacy = SEC_FLAVOR_SVC(req->rq_req_secflvr) == PTLRPCS_SVC_PRIV;
1878 buf = (char *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1879 LASSERT(buf < req->rq_reqbuf ||
1880 buf >= req->rq_reqbuf + req->rq_reqbuf_len);
1881 OBD_FREE(buf, req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
1882 GSS_PRIVBUF_SUFFIX_LEN);
1883 req->rq_reqmsg = NULL;
1886 sec_free_reqbuf(sec, req);
1889 static struct ptlrpc_secops gss_secops = {
1890 .create_sec = gss_create_sec,
1891 .destroy_sec = gss_destroy_sec,
1892 .create_cred = gss_create_cred,
1893 .est_req_payload = gss_estimate_payload,
1894 .est_rep_payload = gss_estimate_payload,
1895 .alloc_reqbuf = gss_alloc_reqbuf,
1896 .free_reqbuf = gss_free_reqbuf,
1899 static struct ptlrpc_sec_type gss_type = {
1900 .pst_owner = THIS_MODULE,
1901 .pst_name = "sec.gss",
1902 .pst_inst = ATOMIC_INIT(0),
1903 .pst_flavor = PTLRPCS_FLVR_MAJOR_GSS,
1904 .pst_ops = &gss_secops,
1908 (*lustre_secinit_downcall_handler)(char *buffer, unsigned long count);
1910 int __init ptlrpcs_gss_init(void)
1914 rc = ptlrpcs_register(&gss_type);
1921 rc = PTR_ERR(rpc_mkdir(LUSTRE_PIPEDIR, NULL));
1922 if (IS_ERR((void *)rc) && rc != -EEXIST) {
1923 CERROR("fail to make rpcpipedir for lustre\n");
1925 ptlrpcs_unregister(&gss_type);
1931 rc = init_kerberos_module();
1933 ptlrpcs_unregister(&gss_type);
1936 lustre_secinit_downcall_handler = gss_send_secinit_rpc;
1942 static void __exit ptlrpcs_gss_exit(void)
1944 lustre_secinit_downcall_handler = NULL;
1946 cleanup_kerberos_module();
1947 rpc_rmdir(LUSTRE_PIPEDIR);
1949 ptlrpcs_unregister(&gss_type);
1953 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
1954 MODULE_DESCRIPTION("GSS Security module for Lustre");
1955 MODULE_LICENSE("GPL");
1957 module_init(ptlrpcs_gss_init);
1958 module_exit(ptlrpcs_gss_exit);