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 (10)
91 #define SECFINI_RPC_TIMEOUT (10)
93 static int secinit_compose_request(struct obd_import *imp,
94 char *buf, int bufsize,
99 struct ptlrpcs_wire_hdr *hdr;
100 struct lustre_msg *lmsg;
101 struct mds_req_sec_desc *secdesc;
102 __u32 size = sizeof(*secdesc);
106 lmsg_size = lustre_msg_size(1, &size);
108 if (sizeof(*hdr) + lmsg_size + size_round(token_size) > bufsize) {
109 CERROR("token size %ld too large\n", token_size);
113 /* security wire hdr */
114 hdr = buf_to_sec_hdr(buf);
115 hdr->flavor = cpu_to_le32(PTLRPC_SEC_GSS);
116 hdr->sectype = cpu_to_le32(PTLRPC_SEC_TYPE_NONE);
117 hdr->msg_len = cpu_to_le32(lmsg_size);
118 hdr->sec_len = cpu_to_le32(7 * 4 + token_size);
120 /* lustre message & secdesc */
121 lmsg = buf_to_lustre_msg(buf);
123 lustre_init_msg(lmsg, 1, &size, NULL);
124 secdesc = lustre_msg_buf(lmsg, 0, size);
125 secdesc->rsd_uid = secdesc->rsd_fsuid = uid;
126 secdesc->rsd_gid = secdesc->rsd_fsgid = gid;
127 secdesc->rsd_cap = secdesc->rsd_ngroups = 0;
129 lmsg->handle = imp->imp_remote_handle;
130 lmsg->type = PTL_RPC_MSG_REQUEST;
131 lmsg->opc = SEC_INIT;
133 lmsg->conn_cnt = imp->imp_conn_cnt;
135 p = (__u32 *) (buf + sizeof(*hdr) + lmsg_size);
138 *p++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* gss version */
139 *p++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I); /* subflavor */
140 *p++ = cpu_to_le32(PTLRPC_GSS_PROC_INIT); /* proc */
141 *p++ = cpu_to_le32(0); /* seq */
142 *p++ = cpu_to_le32(PTLRPC_GSS_SVC_NONE); /* service */
143 *p++ = cpu_to_le32(0); /* context handle */
145 /* now the token part */
146 *p++ = cpu_to_le32((__u32) token_size);
147 LASSERT(((char *)p - buf) + token_size <= bufsize);
149 rc = copy_from_user(p, token, token_size);
151 CERROR("can't copy token\n");
155 rc = size_round(((char *)p - buf) + token_size);
159 static int secinit_parse_reply(char *repbuf, int replen,
160 char __user *outbuf, long outlen)
162 __u32 *p = (__u32 *)repbuf;
163 struct ptlrpcs_wire_hdr *hdr = (struct ptlrpcs_wire_hdr *) repbuf;
164 __u32 lmsg_len, sec_len, status;
165 __u32 major, minor, seq, obj_len, round_len;
168 if (replen <= (4 + 6) * 4) {
169 CERROR("reply size %d too small\n", replen);
173 hdr->flavor = le32_to_cpu(hdr->flavor);
174 hdr->sectype = le32_to_cpu(hdr->sectype);
175 hdr->msg_len = le32_to_cpu(hdr->msg_len);
176 hdr->sec_len = le32_to_cpu(hdr->sec_len);
178 lmsg_len = le32_to_cpu(p[2]);
179 sec_len = le32_to_cpu(p[3]);
182 if (hdr->flavor != PTLRPC_SEC_GSS ||
183 hdr->sectype != PTLRPC_SEC_TYPE_NONE) {
184 CERROR("unexpected reply\n");
187 if (hdr->msg_len % 8 ||
188 sizeof(*hdr) + hdr->msg_len + hdr->sec_len > replen) {
189 CERROR("unexpected reply\n");
192 if (hdr->sec_len > outlen) {
193 CERROR("outbuf too small\n");
197 p = (__u32 *) buf_to_sec_data(repbuf);
200 status = le32_to_cpu(*p++);
201 major = le32_to_cpu(*p++);
202 minor = le32_to_cpu(*p++);
203 seq = le32_to_cpu(*p++);
206 if (copy_to_user(outbuf, &status, 4))
209 if (copy_to_user(outbuf, &major, 4))
212 if (copy_to_user(outbuf, &minor, 4))
215 if (copy_to_user(outbuf, &seq, 4))
219 obj_len = le32_to_cpu(*p++);
220 round_len = (obj_len + 3) & ~ 3;
221 if (copy_to_user(outbuf, &obj_len, 4))
224 if (copy_to_user(outbuf, (char *)p, round_len))
228 effective += 4 + round_len;
230 obj_len = le32_to_cpu(*p++);
231 round_len = (obj_len + 3) & ~ 3;
232 if (copy_to_user(outbuf, &obj_len, 4))
235 if (copy_to_user(outbuf, (char *)p, round_len))
239 effective += 4 + round_len;
244 /* XXX move to where lgssd could see */
245 struct lgssd_ioctl_param {
246 int version; /* in */
250 long send_token_size;/* in */
251 char *send_token; /* in */
252 long reply_buf_size; /* in */
253 char *reply_buf; /* in */
254 long status; /* out */
255 long reply_length; /* out */
258 static int gss_send_secinit_rpc(__user char *buffer, unsigned long count)
260 struct obd_import *imp;
261 struct lgssd_ioctl_param param;
262 const int reqbuf_size = 1024;
263 const int repbuf_size = 1024;
264 char *reqbuf, *repbuf;
265 struct obd_device *obd;
268 int rc, reqlen, replen;
270 if (count != sizeof(param)) {
271 CERROR("partial write\n");
274 if (copy_from_user(¶m, buffer, sizeof(param)))
277 if (param.version != GSSD_INTERFACE_VERSION) {
278 CERROR("gssd interface version %d (expect %d)\n",
279 param.version, GSSD_INTERFACE_VERSION);
284 if (strncpy_from_user(obdname, param.uuid,
285 sizeof(obdname)) <= 0) {
286 CERROR("Invalid obdname pointer\n");
290 obd = class_name2obd(obdname);
292 CERROR("no such obd %s\n", obdname);
295 if (strcmp(obd->obd_type->typ_name, "mdc") &&
296 strcmp(obd->obd_type->typ_name, "osc")) {
297 CERROR("%s not a mdc/osc device\n", obdname);
301 imp = class_import_get(obd->u.cli.cl_import);
303 OBD_ALLOC(reqbuf, reqbuf_size);
304 OBD_ALLOC(repbuf, reqbuf_size);
306 if (!reqbuf || !repbuf) {
307 CERROR("Can't alloc buffer: %p/%p\n", reqbuf, repbuf);
308 GOTO(out_free, rc = -ENOMEM);
312 reqlen = secinit_compose_request(imp, reqbuf, reqbuf_size,
313 param.uid, param.gid,
314 param.send_token_size,
317 GOTO(out_free, rc = reqlen);
319 replen = repbuf_size;
320 rc = ptlrpc_do_rawrpc(imp, reqbuf, reqlen,
321 repbuf, &replen, SECINIT_RPC_TIMEOUT);
325 if (replen > param.reply_buf_size) {
326 CERROR("output buffer size %ld too small, need %d\n",
327 param.reply_buf_size, replen);
328 GOTO(out_free, rc = -EINVAL);
331 lsize = secinit_parse_reply(repbuf, replen,
332 param.reply_buf, param.reply_buf_size);
334 GOTO(out_free, rc = (int)lsize);
337 param.reply_length = lsize;
339 if (copy_to_user(buffer, ¶m, sizeof(param)))
344 class_import_put(imp);
346 OBD_FREE(repbuf, repbuf_size);
348 OBD_FREE(reqbuf, reqbuf_size);
352 static int gss_send_secfini_rpc(struct obd_import *imp,
353 char *reqbuf, int reqlen)
355 const int repbuf_size = 1024;
357 int replen = repbuf_size;
360 OBD_ALLOC(repbuf, repbuf_size);
362 CERROR("Out of memory\n");
366 rc = ptlrpc_do_rawrpc(imp, reqbuf, reqlen, repbuf, &replen,
367 SECFINI_RPC_TIMEOUT);
369 OBD_FREE(repbuf, repbuf_size);
373 /**********************************************
374 * structure definitions *
375 **********************************************/
377 struct ptlrpc_sec gs_base;
378 struct gss_api_mech *gs_mech;
381 struct list_head gs_upcalls;
383 struct dentry *gs_depipe;
389 static rwlock_t gss_ctx_lock = RW_LOCK_UNLOCKED;
391 struct gss_upcall_msg_data {
399 struct gss_upcall_msg {
400 struct rpc_pipe_msg gum_base;
401 atomic_t gum_refcount;
402 struct list_head gum_list;
403 struct gss_sec *gum_gsec;
404 wait_queue_head_t gum_waitq;
405 char gum_obdname[64];
406 struct gss_upcall_msg_data gum_data;
409 /**********************************************
410 * rpc_pipe upcall helpers *
411 **********************************************/
413 void gss_release_msg(struct gss_upcall_msg *gmsg)
416 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
418 if (!atomic_dec_and_test(&gmsg->gum_refcount)) {
419 CDEBUG(D_SEC, "gmsg %p ref %d\n", gmsg,
420 atomic_read(&gmsg->gum_refcount));
424 LASSERT(list_empty(&gmsg->gum_list));
425 OBD_FREE(gmsg, sizeof(*gmsg));
430 gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg)
433 if (list_empty(&gmsg->gum_list)) {
437 /* FIXME should not do this. when we in upper upcall queue,
438 * downcall will call unhash_msg, thus later put_msg might
439 * free msg buffer while it's not dequeued XXX */
440 list_del_init(&gmsg->gum_base.list);
443 list_del_init(&gmsg->gum_list);
444 wake_up(&gmsg->gum_waitq);
445 atomic_dec(&gmsg->gum_refcount);
446 CDEBUG(D_SEC, "gmsg %p refcount now %d\n",
447 gmsg, atomic_read(&gmsg->gum_refcount));
448 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
453 gss_unhash_msg(struct gss_upcall_msg *gmsg)
455 struct gss_sec *gsec = gmsg->gum_gsec;
457 spin_lock(&gsec->gs_lock);
458 gss_unhash_msg_nolock(gmsg);
459 spin_unlock(&gsec->gs_lock);
463 struct gss_upcall_msg * gss_find_upcall(struct gss_sec *gsec,
465 struct gss_upcall_msg_data *gmd)
467 struct gss_upcall_msg *gmsg;
470 list_for_each_entry(gmsg, &gsec->gs_upcalls, gum_list) {
471 if (memcmp(&gmsg->gum_data, gmd, sizeof(*gmd)))
473 if (strcmp(gmsg->gum_obdname, obdname))
475 atomic_inc(&gmsg->gum_refcount);
476 CDEBUG(D_SEC, "found gmsg at %p: obdname %s, uid %d, ref %d\n",
477 gmsg, obdname, gmd->gum_uid,
478 atomic_read(&gmsg->gum_refcount));
484 static void gss_init_upcall_msg(struct gss_upcall_msg *gmsg,
485 struct gss_sec *gsec, char *obdname,
486 struct gss_upcall_msg_data *gmd)
488 struct rpc_pipe_msg *rpcmsg;
491 /* 2 refs: 1 for hash, 1 for current user */
492 init_waitqueue_head(&gmsg->gum_waitq);
493 list_add(&gmsg->gum_list, &gsec->gs_upcalls);
494 atomic_set(&gmsg->gum_refcount, 2);
495 gmsg->gum_gsec = gsec;
496 strncpy(gmsg->gum_obdname, obdname, sizeof(gmsg->gum_obdname));
497 memcpy(&gmsg->gum_data, gmd, sizeof(*gmd));
499 rpcmsg = &gmsg->gum_base;
500 rpcmsg->data = &gmsg->gum_data;
501 rpcmsg->len = sizeof(gmsg->gum_data);
504 #endif /* __KERNEL__ */
506 /********************************************
507 * gss cred manupulation helpers *
508 ********************************************/
510 int gss_cred_is_uptodate_ctx(struct ptlrpc_cred *cred)
512 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
515 read_lock(&gss_ctx_lock);
516 if ((cred->pc_flags & PTLRPC_CRED_UPTODATE) && gcred->gc_ctx)
518 read_unlock(&gss_ctx_lock);
523 struct gss_cl_ctx * gss_get_ctx(struct gss_cl_ctx *ctx)
525 atomic_inc(&ctx->gc_refcount);
530 void gss_destroy_ctx(struct gss_cl_ctx *ctx)
534 CDEBUG(D_SEC, "destroy cl_ctx %p\n", ctx);
536 kgss_delete_sec_context(&ctx->gc_gss_ctx);
538 if (ctx->gc_wire_ctx.len > 0) {
539 OBD_FREE(ctx->gc_wire_ctx.data, ctx->gc_wire_ctx.len);
540 ctx->gc_wire_ctx.len = 0;
543 OBD_FREE(ctx, sizeof(*ctx));
547 void gss_put_ctx(struct gss_cl_ctx *ctx)
549 if (atomic_dec_and_test(&ctx->gc_refcount))
550 gss_destroy_ctx(ctx);
554 struct gss_cl_ctx *gss_cred_get_ctx(struct ptlrpc_cred *cred)
556 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
557 struct gss_cl_ctx *ctx = NULL;
559 read_lock(&gss_ctx_lock);
561 ctx = gss_get_ctx(gcred->gc_ctx);
562 read_unlock(&gss_ctx_lock);
567 void gss_cred_set_ctx(struct ptlrpc_cred *cred, struct gss_cl_ctx *ctx)
569 struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
570 struct gss_cl_ctx *old;
574 if (kgss_inquire_context(ctx->gc_gss_ctx, &ctx_expiry)) {
575 CERROR("unable to get expire time\n");
576 ctx_expiry = 1; /* make it expired now */
578 cred->pc_expire = (unsigned long) ctx_expiry;
580 write_lock(&gss_ctx_lock);
583 cred->pc_flags |= PTLRPC_CRED_UPTODATE;
584 write_unlock(&gss_ctx_lock);
588 CWARN("client refreshed gss cred %p(uid %u)\n", cred, cred->pc_uid);
593 simple_get_bytes(char **buf, __u32 *buflen, void *res, __u32 reslen)
595 if (*buflen < reslen) {
596 CERROR("buflen %u < %u\n", *buflen, reslen);
600 memcpy(res, *buf, reslen);
610 * - wire_ctx (rawobj)
611 * - mech_ctx? (rawobj)
614 int gss_parse_init_downcall(struct gss_api_mech *gm, rawobj_t *buf,
615 struct gss_cl_ctx **gc,
616 struct gss_upcall_msg_data *gmd, int *gss_err)
619 __u32 len = buf->len;
620 struct gss_cl_ctx *ctx;
622 unsigned int timeout;
628 OBD_ALLOC(ctx, sizeof(*ctx));
632 ctx->gc_proc = RPC_GSS_PROC_DATA;
634 spin_lock_init(&ctx->gc_seq_lock);
635 atomic_set(&ctx->gc_refcount,1);
637 if (simple_get_bytes(&p, &len, &gmd->gum_uid, sizeof(gmd->gum_uid)))
638 GOTO(err_free_ctx, err);
639 if (simple_get_bytes(&p, &len, &gmd->gum_svc, sizeof(gmd->gum_svc)))
640 GOTO(err_free_ctx, err);
641 if (simple_get_bytes(&p, &len, &gmd->gum_nal, sizeof(gmd->gum_nal)))
642 GOTO(err_free_ctx, err);
643 if (simple_get_bytes(&p, &len, &gmd->gum_netid, sizeof(gmd->gum_netid)))
644 GOTO(err_free_ctx, err);
645 if (simple_get_bytes(&p, &len, &gmd->gum_nid, sizeof(gmd->gum_nid)))
646 GOTO(err_free_ctx, err);
647 /* FIXME: discarded timeout for now */
648 if (simple_get_bytes(&p, &len, &timeout, sizeof(timeout)))
649 GOTO(err_free_ctx, err);
651 if (simple_get_bytes(&p, &len, &ctx->gc_win, sizeof(ctx->gc_win)))
652 GOTO(err_free_ctx, err);
653 /* gssd signals an error by passing ctx->gc_win = 0: */
655 /* in which case the next int is an error code: */
656 if (simple_get_bytes(&p, &len, gss_err, sizeof(*gss_err)))
657 GOTO(err_free_ctx, err);
659 CERROR("error downcall pass no gss error\n");
660 GOTO(err_free_ctx, err);
662 GOTO(err_free_ctx, err = 0);
664 if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
665 GOTO(err_free_ctx, err);
666 if (rawobj_dup(&ctx->gc_wire_ctx, &tmp_buf)) {
667 GOTO(err_free_ctx, err = -ENOMEM);
669 if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
670 GOTO(err_free_wire_ctx, err);
672 CERROR("unexpected trailing %u bytes\n", len);
673 GOTO(err_free_wire_ctx, err);
675 if (kgss_import_sec_context(&tmp_buf, gm, &ctx->gc_gss_ctx))
676 GOTO(err_free_wire_ctx, err);
682 if (ctx->gc_wire_ctx.data)
683 OBD_FREE(ctx->gc_wire_ctx.data, ctx->gc_wire_ctx.len);
685 OBD_FREE(ctx, sizeof(*ctx));
686 CDEBUG(D_SEC, "err_code %d, gss code %d\n", err, *gss_err);
690 /***************************************
692 ***************************************/
694 #define CRED_REFRESH_UPCALL_TIMEOUT (20)
695 static int gss_cred_refresh(struct ptlrpc_cred *cred)
697 struct obd_import *import;
698 struct gss_sec *gsec;
699 struct gss_upcall_msg *gss_msg, *gss_new;
700 struct gss_upcall_msg_data gmd;
701 struct dentry *dentry;
702 char *obdname, *obdtype;
704 uid_t uid = cred->pc_uid;
708 if (ptlrpcs_cred_is_uptodate(cred))
711 LASSERT(cred->pc_sec);
712 LASSERT(cred->pc_sec->ps_import);
713 LASSERT(cred->pc_sec->ps_import->imp_obd);
715 import = cred->pc_sec->ps_import;
716 if (!import->imp_connection) {
717 CERROR("import has no connection set\n");
722 gmd.gum_nal = import->imp_connection->c_peer.peer_ni->pni_number;
724 gmd.gum_nid = import->imp_connection->c_peer.peer_id.nid;
726 obdtype = import->imp_obd->obd_type->typ_name;
727 if (!strcmp(obdtype, "mdc"))
729 else if (!strcmp(obdtype, "osc"))
732 CERROR("gss on %s?\n", obdtype);
736 gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
737 obdname = import->imp_obd->obd_name;
738 dentry = gsec->gs_depipe;
742 CWARN("Initiate gss context %p(%u@%s)\n",
743 container_of(cred, struct gss_cred, gc_base),
744 uid, import->imp_target_uuid.uuid);
747 spin_lock(&gsec->gs_lock);
748 gss_msg = gss_find_upcall(gsec, obdname, &gmd);
750 spin_unlock(&gsec->gs_lock);
754 spin_unlock(&gsec->gs_lock);
755 OBD_ALLOC(gss_new, sizeof(*gss_new));
757 CERROR("fail to alloc memory\n");
762 /* so far we'v created gss_new */
763 gss_init_upcall_msg(gss_new, gsec, obdname, &gmd);
765 if (gss_cred_is_uptodate_ctx(cred)) {
766 /* someone else had done it for us, simply cancel
768 CDEBUG(D_SEC, "cred("LPU64"/%u) has been refreshed by someone "
769 "else, simply drop our request\n",
770 cred->pc_pag, cred->pc_uid);
771 gss_unhash_msg_nolock(gss_new);
772 spin_unlock(&gsec->gs_lock);
773 gss_release_msg(gss_new);
777 /* need to make upcall now */
778 spin_unlock(&gsec->gs_lock);
779 res = rpc_queue_upcall(dentry->d_inode, &gss_new->gum_base);
781 CERROR("rpc_queue_upcall failed: %d\n", res);
782 gss_unhash_msg(gss_new);
783 gss_release_msg(gss_new);
789 init_waitqueue_entry(&wait, current);
790 spin_lock(&gsec->gs_lock);
791 add_wait_queue(&gss_msg->gum_waitq, &wait);
792 set_current_state(TASK_INTERRUPTIBLE);
793 spin_unlock(&gsec->gs_lock);
795 res = schedule_timeout(CRED_REFRESH_UPCALL_TIMEOUT * HZ);
797 remove_wait_queue(&gss_msg->gum_waitq, &wait);
798 if (signal_pending(current)) {
799 CERROR("interrupted gss upcall: cred %p\n", cred);
801 } else if (res == 0) {
802 CERROR("gss upcall timeout: cred %p\n", cred);
807 gss_release_msg(gss_msg);
810 #else /* !__KERNEL__ */
811 extern int lgss_handle_krb5_upcall(uid_t uid, __u32 dest_ip,
813 char *buf, int bufsize,
814 int (*callback)(char*, unsigned long));
816 static int gss_cred_refresh(struct ptlrpc_cred *cred)
820 struct obd_import *imp;
821 struct gss_sec *gsec;
822 struct gss_api_mech *mech;
823 struct gss_cl_ctx *ctx = NULL;
824 struct vfs_cred vcred = { 0 };
831 LASSERT(cred->pc_sec);
832 LASSERT(cred->pc_sec->ps_import);
833 LASSERT(cred->pc_sec->ps_import->imp_obd);
835 if (ptlrpcs_cred_is_uptodate(cred))
838 imp = cred->pc_sec->ps_import;
839 peer_nid = imp->imp_connection->c_peer.peer_id.nid;
840 dest_ip = (__u32) (peer_nid & 0xFFFFFFFF);
841 subflavor = cred->pc_sec->ps_flavor.subflavor;
843 if (subflavor != PTLRPC_SEC_GSS_KRB5I) {
844 CERROR("unknown subflavor %u\n", subflavor);
845 GOTO(err_out, rc = -EINVAL);
848 rc = lgss_handle_krb5_upcall(cred->pc_uid, dest_ip,
849 imp->imp_obd->obd_name,
851 gss_send_secinit_rpc);
859 gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
860 mech = gsec->gs_mech;
862 rc = gss_parse_init_downcall(mech, &obj, &ctx, &vcred, &dest_ip,
865 CERROR("parse init downcall error %d\n", rc);
870 CERROR("cred fresh got gss error %x\n", gss_err);
876 gss_cred_set_ctx(cred, ctx);
877 LASSERT(gss_cred_is_uptodate_ctx(cred));
881 cred->pc_flags |= PTLRPC_CRED_DEAD;
886 static int gss_cred_match(struct ptlrpc_cred *cred,
887 struct ptlrpc_request *req,
888 struct vfs_cred *vcred)
890 RETURN(cred->pc_pag == vcred->vc_pag);
893 static int gss_cred_sign(struct ptlrpc_cred *cred,
894 struct ptlrpc_request *req)
896 struct gss_cred *gcred;
897 struct gss_cl_ctx *ctx;
899 __u32 *vp, *vpsave, vlen, seclen;
900 __u32 seqnum, major, rc = 0;
903 LASSERT(req->rq_reqbuf);
904 LASSERT(req->rq_cred == cred);
906 gcred = container_of(cred, struct gss_cred, gc_base);
907 ctx = gss_cred_get_ctx(cred);
909 CERROR("cred %p("LPU64"/%u) invalidated?\n",
910 cred, cred->pc_pag, cred->pc_uid);
914 lmsg.len = req->rq_reqlen;
915 lmsg.data = (__u8 *) req->rq_reqmsg;
917 vp = (__u32 *) (lmsg.data + lmsg.len);
918 vlen = req->rq_reqbuf_len - sizeof(struct ptlrpcs_wire_hdr) -
922 if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
923 CERROR("vlen %d, need %d\n",
924 vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
929 spin_lock(&ctx->gc_seq_lock);
930 seqnum = ctx->gc_seq++;
931 spin_unlock(&ctx->gc_seq_lock);
933 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* version */
934 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I); /* subflavor */
935 *vp++ = cpu_to_le32(ctx->gc_proc); /* proc */
936 *vp++ = cpu_to_le32(seqnum); /* seq */
937 *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_INTEGRITY); /* service */
940 if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
944 CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
946 vpsave = vp++; /* reserve for size */
950 mic.data = (char *) vp;
952 CDEBUG(D_SEC, "reqbuf at %p, lmsg at %p, len %d, mic at %p, len %d\n",
953 req->rq_reqbuf, lmsg.data, lmsg.len, mic.data, mic.len);
954 major = kgss_get_mic(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, &lmsg, &mic);
956 CERROR("gss compute mic error, major %x\n", major);
961 *vpsave = cpu_to_le32(mic.len);
963 seclen = seclen - vlen + mic.len;
964 buf_to_sec_hdr(req->rq_reqbuf)->sec_len = cpu_to_le32(seclen);
965 req->rq_reqdata_len += size_round(seclen);
966 CDEBUG(D_SEC, "msg size %d, checksum size %d, total sec size %d\n",
967 lmsg.len, mic.len, seclen);
973 static int gss_cred_verify(struct ptlrpc_cred *cred,
974 struct ptlrpc_request *req)
976 struct gss_cred *gcred;
977 struct gss_cl_ctx *ctx;
978 struct ptlrpcs_wire_hdr *sec_hdr;
980 __u32 *vp, vlen, subflavor, proc, seq, svc;
981 __u32 major, minor, rc;
984 LASSERT(req->rq_repbuf);
985 LASSERT(req->rq_cred == cred);
987 sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
988 vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr) + sec_hdr->msg_len);
989 vlen = sec_hdr->sec_len;
992 CERROR("reply sec size %u too small\n", vlen);
996 if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
997 CERROR("reply have different gss version\n");
1000 subflavor = le32_to_cpu(*vp++);
1001 proc = le32_to_cpu(*vp++);
1005 case PTLRPC_GSS_PROC_DATA:
1006 seq = le32_to_cpu(*vp++);
1007 svc = le32_to_cpu(*vp++);
1008 if (svc != PTLRPC_GSS_SVC_INTEGRITY) {
1009 CERROR("Unknown svc %d\n", svc);
1013 CERROR("Unexpected ctx handle\n");
1016 mic.len = le32_to_cpu(*vp++);
1018 if (vlen < mic.len) {
1019 CERROR("vlen %d, mic.len %d\n", vlen, mic.len);
1022 mic.data = (char *) vp;
1024 gcred = container_of(cred, struct gss_cred, gc_base);
1025 ctx = gss_cred_get_ctx(cred);
1028 lmsg.len = sec_hdr->msg_len;
1029 lmsg.data = (__u8 *) buf_to_lustre_msg(req->rq_repbuf);
1031 major = kgss_verify_mic(ctx->gc_gss_ctx, &lmsg, &mic, NULL);
1032 if (major != GSS_S_COMPLETE) {
1033 CERROR("gss verify mic error: major %x\n", major);
1034 GOTO(proc_data_out, rc = -EINVAL);
1037 req->rq_repmsg = (struct lustre_msg *) lmsg.data;
1038 req->rq_replen = lmsg.len;
1040 /* here we could check the seq number is the same one
1041 * we sent to server. but portals has prevent us from
1042 * replay attack, so maybe we don't need check it again.
1048 case PTLRPC_GSS_PROC_ERR:
1049 major = le32_to_cpu(*vp++);
1050 minor = le32_to_cpu(*vp++);
1051 /* server return NO_CONTEXT might be caused by context expire
1052 * or server reboot/failover. we refresh the cred transparently
1054 * In some cases, our gss handle is possible to be incidentally
1055 * identical to another handle since the handle itself is not
1056 * fully random. In krb5 case, the GSS_S_BAD_SIG will be
1057 * returned, maybe other gss error for other mechanism. Here we
1058 * only consider krb5 mech (FIXME) and try to establish new
1061 if (major == GSS_S_NO_CONTEXT ||
1062 major == GSS_S_BAD_SIG) {
1063 CWARN("req %p: server report cred %p %s, expired?\n",
1064 req, cred, (major == GSS_S_NO_CONTEXT) ?
1065 "NO_CONTEXT" : "BAD_SIG");
1067 ptlrpcs_cred_die(cred);
1068 rc = ptlrpcs_req_replace_dead_cred(req);
1070 req->rq_ptlrpcs_restart = 1;
1072 CERROR("replace dead cred failed %d\n", rc);
1074 CERROR("Unrecognized gss error (%x/%x)\n",
1080 CERROR("unknown gss proc %d\n", proc);
1087 static int gss_cred_seal(struct ptlrpc_cred *cred,
1088 struct ptlrpc_request *req)
1090 struct gss_cred *gcred;
1091 struct gss_cl_ctx *ctx;
1092 struct ptlrpcs_wire_hdr *sec_hdr;
1093 rawobj_buf_t msg_buf;
1094 rawobj_t cipher_buf;
1095 __u32 *vp, *vpsave, vlen, seclen;
1096 __u32 major, seqnum, rc = 0;
1099 LASSERT(req->rq_reqbuf);
1100 LASSERT(req->rq_cred == cred);
1102 gcred = container_of(cred, struct gss_cred, gc_base);
1103 ctx = gss_cred_get_ctx(cred);
1105 CERROR("cred %p("LPU64"/%u) invalidated?\n",
1106 cred, cred->pc_pag, cred->pc_uid);
1110 vp = (__u32 *) (req->rq_reqbuf + sizeof(*sec_hdr));
1111 vlen = req->rq_reqbuf_len - sizeof(*sec_hdr);
1114 if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
1115 CERROR("vlen %d, need %d\n",
1116 vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
1121 spin_lock(&ctx->gc_seq_lock);
1122 seqnum = ctx->gc_seq++;
1123 spin_unlock(&ctx->gc_seq_lock);
1125 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION); /* version */
1126 *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5P); /* subflavor */
1127 *vp++ = cpu_to_le32(ctx->gc_proc); /* proc */
1128 *vp++ = cpu_to_le32(seqnum); /* seq */
1129 *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_PRIVACY); /* service */
1132 if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
1136 CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
1138 vpsave = vp++; /* reserve for size */
1141 msg_buf.buf = (__u8 *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1142 msg_buf.buflen = req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN + GSS_PRIVBUF_SUFFIX_LEN;
1143 msg_buf.dataoff = GSS_PRIVBUF_PREFIX_LEN;
1144 msg_buf.datalen = req->rq_reqlen;
1146 cipher_buf.data = (__u8 *) vp;
1147 cipher_buf.len = vlen;
1149 major = kgss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1150 &msg_buf, &cipher_buf);
1152 CERROR("error wrap: major 0x%x\n", major);
1153 GOTO(out, rc = -EINVAL);
1156 *vpsave = cpu_to_le32(cipher_buf.len);
1158 seclen = seclen - vlen + cipher_buf.len;
1159 sec_hdr = buf_to_sec_hdr(req->rq_reqbuf);
1160 sec_hdr->sec_len = cpu_to_le32(seclen);
1161 req->rq_reqdata_len += size_round(seclen);
1163 CDEBUG(D_SEC, "msg size %d, total sec size %d\n",
1164 req->rq_reqlen, seclen);
1170 static int gss_cred_unseal(struct ptlrpc_cred *cred,
1171 struct ptlrpc_request *req)
1173 struct gss_cred *gcred;
1174 struct gss_cl_ctx *ctx;
1175 struct ptlrpcs_wire_hdr *sec_hdr;
1176 rawobj_t cipher_text, plain_text;
1177 __u32 *vp, vlen, subflavor, proc, seq, svc;
1181 LASSERT(req->rq_repbuf);
1182 LASSERT(req->rq_cred == cred);
1184 sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
1185 if (sec_hdr->msg_len != 0) {
1186 CERROR("unexpected msg_len %u\n", sec_hdr->msg_len);
1190 vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr));
1191 vlen = sec_hdr->sec_len;
1194 CERROR("reply sec size %u too small\n", vlen);
1198 if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
1199 CERROR("reply have different gss version\n");
1202 subflavor = le32_to_cpu(*vp++);
1203 proc = le32_to_cpu(*vp++);
1204 seq = le32_to_cpu(*vp++);
1205 svc = le32_to_cpu(*vp++);
1209 case PTLRPC_GSS_PROC_DATA:
1210 if (svc != PTLRPC_GSS_SVC_PRIVACY) {
1211 CERROR("Unknown svc %d\n", svc);
1215 CERROR("Unexpected ctx handle\n");
1220 cipher_text.len = le32_to_cpu(*vp++);
1221 cipher_text.data = (__u8 *) vp;
1224 if (vlen < cipher_text.len) {
1225 CERROR("cipher text to be %u while buf only %u\n",
1226 cipher_text.len, vlen);
1230 plain_text = cipher_text;
1232 gcred = container_of(cred, struct gss_cred, gc_base);
1233 ctx = gss_cred_get_ctx(cred);
1236 rc = kgss_unwrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1237 &cipher_text, &plain_text);
1239 CERROR("error unwrap: 0x%x\n", rc);
1240 GOTO(proc_out, rc = -EINVAL);
1243 req->rq_repmsg = (struct lustre_msg *) vp;
1244 req->rq_replen = plain_text.len;
1251 CERROR("unknown gss proc %d\n", proc);
1258 static void destroy_gss_context(struct ptlrpc_cred *cred)
1260 struct ptlrpcs_wire_hdr *hdr;
1261 struct lustre_msg *lmsg;
1262 struct gss_cred *gcred;
1263 struct ptlrpc_request req;
1264 struct obd_import *imp;
1265 __u32 *vp, lmsg_size;
1268 /* cred's refcount is 0, steal one */
1269 atomic_inc(&cred->pc_refcount);
1271 gcred = container_of(cred, struct gss_cred, gc_base);
1272 gcred->gc_ctx->gc_proc = PTLRPC_GSS_PROC_DESTROY;
1273 imp = cred->pc_sec->ps_import;
1276 if (!(cred->pc_flags & PTLRPC_CRED_UPTODATE)) {
1277 CWARN("Destroy a dead gss cred %p(%u@%s), don't send rpc\n",
1278 gcred, cred->pc_uid, imp->imp_target_uuid.uuid);
1279 atomic_dec(&cred->pc_refcount);
1284 CWARN("client destroy gss cred %p(%u@%s)\n",
1285 gcred, cred->pc_uid, imp->imp_target_uuid.uuid);
1287 lmsg_size = lustre_msg_size(0, NULL);
1288 req.rq_reqbuf_len = sizeof(*hdr) + lmsg_size +
1289 ptlrpcs_est_req_payload(cred->pc_sec, lmsg_size);
1291 OBD_ALLOC(req.rq_reqbuf, req.rq_reqbuf_len);
1292 if (!req.rq_reqbuf) {
1293 CERROR("Fail to alloc reqbuf, cancel anyway\n");
1294 atomic_dec(&cred->pc_refcount);
1300 hdr = buf_to_sec_hdr(req.rq_reqbuf);
1301 hdr->flavor = cpu_to_le32(PTLRPC_SEC_GSS);
1302 hdr->sectype = cpu_to_le32(PTLRPC_SEC_TYPE_AUTH);
1303 hdr->msg_len = cpu_to_le32(lmsg_size);
1304 hdr->sec_len = cpu_to_le32(0);
1306 /* lustre message */
1307 lmsg = buf_to_lustre_msg(req.rq_reqbuf);
1308 lustre_init_msg(lmsg, 0, NULL, NULL);
1309 lmsg->handle = imp->imp_remote_handle;
1310 lmsg->type = PTL_RPC_MSG_REQUEST;
1311 lmsg->opc = SEC_FINI;
1313 lmsg->conn_cnt = imp->imp_conn_cnt;
1314 /* add this for randomize */
1315 get_random_bytes(&lmsg->last_xid, sizeof(lmsg->last_xid));
1316 get_random_bytes(&lmsg->transno, sizeof(lmsg->transno));
1318 vp = (__u32 *) req.rq_reqbuf;
1321 req.rq_reqmsg = buf_to_lustre_msg(req.rq_reqbuf);
1322 req.rq_reqlen = lmsg_size;
1323 req.rq_reqdata_len = sizeof(*hdr) + lmsg_size;
1325 if (gss_cred_sign(cred, &req)) {
1326 CERROR("failed to sign, cancel anyway\n");
1327 atomic_dec(&cred->pc_refcount);
1330 atomic_dec(&cred->pc_refcount);
1333 gss_send_secfini_rpc(imp, req.rq_reqbuf, req.rq_reqdata_len);
1335 OBD_FREE(req.rq_reqbuf, req.rq_reqbuf_len);
1339 static void gss_cred_destroy(struct ptlrpc_cred *cred)
1341 struct gss_cred *gcred;
1345 LASSERT(!atomic_read(&cred->pc_refcount));
1347 gcred = container_of(cred, struct gss_cred, gc_base);
1348 if (gcred->gc_ctx) {
1349 destroy_gss_context(cred);
1350 gss_put_ctx(gcred->gc_ctx);
1353 CDEBUG(D_SEC, "GSS_SEC: destroy cred %p\n", gcred);
1355 OBD_FREE(gcred, sizeof(*gcred));
1359 static struct ptlrpc_credops gss_credops = {
1360 .refresh = gss_cred_refresh,
1361 .match = gss_cred_match,
1362 .sign = gss_cred_sign,
1363 .verify = gss_cred_verify,
1364 .seal = gss_cred_seal,
1365 .unseal = gss_cred_unseal,
1366 .destroy = gss_cred_destroy,
1370 /*******************************************
1372 *******************************************/
1374 gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
1375 char *dst, size_t buflen)
1377 char *data = (char *)msg->data + msg->copied;
1378 ssize_t mlen = msg->len;
1384 left = copy_to_user(dst, data, mlen);
1390 msg->copied += mlen;
1396 gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
1399 const int bufsize = 1024;
1401 struct inode *inode = filp->f_dentry->d_inode;
1402 struct rpc_inode *rpci = RPC_I(inode);
1403 struct obd_import *import;
1404 struct ptlrpc_sec *sec;
1405 struct gss_sec *gsec;
1407 struct gss_api_mech *mech;
1408 struct vfs_cred vcred = { 0 };
1409 struct ptlrpc_cred *cred;
1410 struct gss_upcall_msg *gss_msg;
1411 struct gss_upcall_msg_data gmd = { 0 };
1412 struct gss_cl_ctx *ctx = NULL;
1417 if (mlen > bufsize) {
1418 CERROR("mlen %ld > bufsize %d\n", (long)mlen, bufsize);
1422 OBD_ALLOC(buf, bufsize);
1424 CERROR("alloc mem failed\n");
1428 left = copy_from_user(buf, src, mlen);
1430 GOTO(err_free, err = -EFAULT);
1435 LASSERT(rpci->private);
1436 gsec = (struct gss_sec *)rpci->private;
1437 sec = &gsec->gs_base;
1438 LASSERT(sec->ps_import);
1439 import = class_import_get(sec->ps_import);
1440 LASSERT(import->imp_obd);
1441 obdname = import->imp_obd->obd_name;
1442 mech = gsec->gs_mech;
1444 err = gss_parse_init_downcall(mech, &obj, &ctx, &gmd, &gss_err);
1446 CERROR("parse init downcall err %d\n", err);
1448 vcred.vc_uid = gmd.gum_uid;
1449 vcred.vc_pag = vcred.vc_uid; /* FIXME */
1451 cred = ptlrpcs_cred_lookup(sec, &vcred);
1453 CWARN("didn't find cred for uid %u\n", vcred.vc_uid);
1456 if (err || gss_err) {
1457 CERROR("got err %d, gss err %d, set cred %p dead\n",
1458 err, gss_err, cred);
1459 cred->pc_flags |= PTLRPC_CRED_DEAD;
1461 CDEBUG(D_SEC, "get initial ctx:\n");
1462 gss_cred_set_ctx(cred, ctx);
1465 spin_lock(&gsec->gs_lock);
1466 gss_msg = gss_find_upcall(gsec, obdname, &gmd);
1468 gss_unhash_msg_nolock(gss_msg);
1469 spin_unlock(&gsec->gs_lock);
1470 gss_release_msg(gss_msg);
1472 spin_unlock(&gsec->gs_lock);
1474 ptlrpcs_cred_put(cred, 1);
1475 class_import_put(import);
1476 OBD_FREE(buf, bufsize);
1480 gss_destroy_ctx(ctx);
1481 class_import_put(import);
1483 OBD_FREE(buf, bufsize);
1484 CDEBUG(D_SEC, "gss_pipe_downcall returning %d\n", err);
1489 void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
1491 struct gss_upcall_msg *gmsg;
1492 static unsigned long ratelimit;
1495 if (msg->errno >= 0) {
1500 gmsg = container_of(msg, struct gss_upcall_msg, gum_base);
1501 CDEBUG(D_SEC, "destroy gmsg %p\n", gmsg);
1502 atomic_inc(&gmsg->gum_refcount);
1503 gss_unhash_msg(gmsg);
1504 if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
1505 unsigned long now = get_seconds();
1506 if (time_after(now, ratelimit)) {
1507 CWARN("GSS_SEC upcall timed out.\n"
1508 "Please check user daemon is running!\n");
1509 ratelimit = now + 15;
1512 gss_release_msg(gmsg);
1517 void gss_pipe_release(struct inode *inode)
1519 struct rpc_inode *rpci = RPC_I(inode);
1520 struct ptlrpc_sec *sec;
1521 struct gss_sec *gsec;
1524 gsec = (struct gss_sec *)rpci->private;
1525 sec = &gsec->gs_base;
1526 spin_lock(&gsec->gs_lock);
1527 while (!list_empty(&gsec->gs_upcalls)) {
1528 struct gss_upcall_msg *gmsg;
1530 gmsg = list_entry(gsec->gs_upcalls.next,
1531 struct gss_upcall_msg, gum_list);
1532 gmsg->gum_base.errno = -EPIPE;
1533 atomic_inc(&gmsg->gum_refcount);
1534 gss_unhash_msg_nolock(gmsg);
1535 gss_release_msg(gmsg);
1537 spin_unlock(&gsec->gs_lock);
1541 static struct rpc_pipe_ops gss_upcall_ops = {
1542 .upcall = gss_pipe_upcall,
1543 .downcall = gss_pipe_downcall,
1544 .destroy_msg = gss_pipe_destroy_msg,
1545 .release_pipe = gss_pipe_release,
1547 #endif /* __KERNEL__ */
1549 /*********************************************
1550 * GSS security APIs *
1551 *********************************************/
1554 struct ptlrpc_sec* gss_create_sec(ptlrpcs_flavor_t *flavor,
1555 const char *pipe_dir,
1558 struct gss_sec *gsec;
1559 struct ptlrpc_sec *sec;
1566 LASSERT(flavor->flavor == PTLRPC_SEC_GSS);
1568 OBD_ALLOC(gsec, sizeof(*gsec));
1570 CERROR("can't alloc gsec\n");
1574 gsec->gs_mech = kgss_subflavor_to_mech(flavor->subflavor);
1575 if (!gsec->gs_mech) {
1576 CERROR("subflavor %d not found\n", flavor->subflavor);
1580 /* initialize gss sec */
1582 INIT_LIST_HEAD(&gsec->gs_upcalls);
1583 spin_lock_init(&gsec->gs_lock);
1585 pipepath_len = strlen(LUSTRE_PIPEDIR) + strlen(pipe_dir) +
1586 strlen(gsec->gs_mech->gm_name) + 3;
1587 OBD_ALLOC(gsec->gs_pipepath, pipepath_len);
1588 if (!gsec->gs_pipepath)
1591 sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s", pipe_dir);
1592 if (IS_ERR(rpc_mkdir(gsec->gs_pipepath, NULL))) {
1593 CERROR("can't make pipedir %s\n", gsec->gs_pipepath);
1597 sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s/%s", pipe_dir,
1598 gsec->gs_mech->gm_name);
1599 gsec->gs_depipe = rpc_mkpipe(gsec->gs_pipepath, gsec,
1600 &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
1601 if (IS_ERR(gsec->gs_depipe)) {
1602 CERROR("failed to make rpc_pipe %s: %ld\n",
1603 gsec->gs_pipepath, PTR_ERR(gsec->gs_depipe));
1606 CDEBUG(D_SEC, "gss sec %p, pipe path %s\n", gsec, gsec->gs_pipepath);
1609 sec = &gsec->gs_base;
1611 switch (flavor->subflavor) {
1612 case PTLRPC_SEC_GSS_KRB5I:
1613 sec->ps_sectype = PTLRPC_SEC_TYPE_AUTH;
1615 case PTLRPC_SEC_GSS_KRB5P:
1616 sec->ps_sectype = PTLRPC_SEC_TYPE_PRIV;
1622 sec->ps_expire = GSS_CREDCACHE_EXPIRE;
1623 sec->ps_nextgc = get_seconds() + sec->ps_expire;
1626 CDEBUG(D_SEC, "Create GSS security instance at %p(external %p)\n",
1632 pos = strrchr(gsec->gs_pipepath, '/');
1635 rpc_rmdir(gsec->gs_pipepath);
1637 OBD_FREE(gsec->gs_pipepath, pipepath_len);
1640 kgss_mech_put(gsec->gs_mech);
1642 OBD_FREE(gsec, sizeof(*gsec));
1647 void gss_destroy_sec(struct ptlrpc_sec *sec)
1649 struct gss_sec *gsec;
1656 gsec = container_of(sec, struct gss_sec, gs_base);
1657 CDEBUG(D_SEC, "Destroy GSS security instance at %p\n", gsec);
1659 LASSERT(gsec->gs_mech);
1660 LASSERT(!atomic_read(&sec->ps_refcount));
1661 LASSERT(!atomic_read(&sec->ps_credcount));
1663 pipepath_len = strlen(gsec->gs_pipepath) + 1;
1664 rpc_unlink(gsec->gs_pipepath);
1665 pos = strrchr(gsec->gs_pipepath, '/');
1668 rpc_rmdir(gsec->gs_pipepath);
1669 OBD_FREE(gsec->gs_pipepath, pipepath_len);
1672 kgss_mech_put(gsec->gs_mech);
1673 OBD_FREE(gsec, sizeof(*gsec));
1678 struct ptlrpc_cred * gss_create_cred(struct ptlrpc_sec *sec,
1679 struct ptlrpc_request *req,
1680 struct vfs_cred *vcred)
1682 struct gss_cred *gcred;
1683 struct ptlrpc_cred *cred;
1686 OBD_ALLOC(gcred, sizeof(*gcred));
1690 cred = &gcred->gc_base;
1691 INIT_LIST_HEAD(&cred->pc_hash);
1692 atomic_set(&cred->pc_refcount, 0);
1694 cred->pc_ops = &gss_credops;
1696 cred->pc_expire = get_seconds() + GSS_CRED_EXPIRE;
1698 cred->pc_pag = vcred->vc_pag;
1699 cred->pc_uid = vcred->vc_uid;
1700 CDEBUG(D_SEC, "create a gss cred at %p("LPU64"/%u)\n",
1701 cred, vcred->vc_pag, vcred->vc_uid);
1706 static int gss_estimate_payload(struct ptlrpc_sec *sec, int msgsize)
1708 switch (sec->ps_sectype) {
1709 case PTLRPC_SEC_TYPE_AUTH:
1710 return GSS_MAX_AUTH_PAYLOAD;
1711 case PTLRPC_SEC_TYPE_PRIV:
1712 return size_round16(GSS_MAX_AUTH_PAYLOAD + msgsize +
1713 GSS_PRIVBUF_PREFIX_LEN +
1714 GSS_PRIVBUF_SUFFIX_LEN);
1721 static int gss_alloc_reqbuf(struct ptlrpc_sec *sec,
1722 struct ptlrpc_request *req,
1725 int msg_payload, sec_payload;
1729 /* In PRIVACY mode, lustre message is always 0 (already encoded into
1730 * security payload).
1732 privacy = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV;
1733 msg_payload = privacy ? 0 : lmsg_size;
1734 sec_payload = gss_estimate_payload(sec, lmsg_size);
1736 rc = sec_alloc_reqbuf(sec, req, msg_payload, sec_payload);
1741 int buflen = lmsg_size + GSS_PRIVBUF_PREFIX_LEN +
1742 GSS_PRIVBUF_SUFFIX_LEN;
1745 OBD_ALLOC(buf, buflen);
1747 CERROR("Fail to alloc %d\n", buflen);
1748 sec_free_reqbuf(sec, req);
1751 req->rq_reqmsg = (struct lustre_msg *)
1752 (buf + GSS_PRIVBUF_PREFIX_LEN);
1758 static void gss_free_reqbuf(struct ptlrpc_sec *sec,
1759 struct ptlrpc_request *req)
1765 LASSERT(req->rq_reqmsg);
1766 LASSERT(req->rq_reqlen);
1768 privacy = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV;
1770 buf = (char *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1771 LASSERT(buf < req->rq_reqbuf ||
1772 buf >= req->rq_reqbuf + req->rq_reqbuf_len);
1773 OBD_FREE(buf, req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
1774 GSS_PRIVBUF_SUFFIX_LEN);
1775 req->rq_reqmsg = NULL;
1778 sec_free_reqbuf(sec, req);
1781 static struct ptlrpc_secops gss_secops = {
1782 .create_sec = gss_create_sec,
1783 .destroy_sec = gss_destroy_sec,
1784 .create_cred = gss_create_cred,
1785 .est_req_payload = gss_estimate_payload,
1786 .est_rep_payload = gss_estimate_payload,
1787 .alloc_reqbuf = gss_alloc_reqbuf,
1788 .free_reqbuf = gss_free_reqbuf,
1791 static struct ptlrpc_sec_type gss_type = {
1792 .pst_owner = THIS_MODULE,
1793 .pst_name = "GSS_SEC",
1794 .pst_inst = ATOMIC_INIT(0),
1795 .pst_flavor = {PTLRPC_SEC_GSS, 0},
1796 .pst_ops = &gss_secops,
1800 (*lustre_secinit_downcall_handler)(char *buffer, unsigned long count);
1802 int __init ptlrpcs_gss_init(void)
1806 rc = ptlrpcs_register(&gss_type);
1813 rc = PTR_ERR(rpc_mkdir(LUSTRE_PIPEDIR, NULL));
1814 if (IS_ERR((void *)rc) && rc != -EEXIST) {
1815 CERROR("fail to make rpcpipedir for lustre\n");
1817 ptlrpcs_unregister(&gss_type);
1823 rc = init_kerberos_module();
1825 ptlrpcs_unregister(&gss_type);
1828 lustre_secinit_downcall_handler = gss_send_secinit_rpc;
1834 static void __exit ptlrpcs_gss_exit(void)
1836 lustre_secinit_downcall_handler = NULL;
1838 cleanup_kerberos_module();
1839 rpc_rmdir(LUSTRE_PIPEDIR);
1841 ptlrpcs_unregister(&gss_type);
1845 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
1846 MODULE_DESCRIPTION("GSS Security module for Lustre");
1847 MODULE_LICENSE("GPL");
1849 module_init(ptlrpcs_gss_init);
1850 module_exit(ptlrpcs_gss_exit);