Whamcloud - gitweb
d5f83c160afad8bb82ecf7be0e8df8016924f618
[fs/lustre-release.git] / lustre / sec / gss / sec_gss.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Modifications for Lustre
5  * Copyright 2004, Cluster File Systems, Inc.
6  * All rights reserved
7  * Author: Eric Mei <ericm@clusterfs.com>
8  */
9
10 /*
11  * linux/net/sunrpc/auth_gss.c
12  *
13  * RPCSEC_GSS client authentication.
14  *
15  *  Copyright (c) 2000 The Regents of the University of Michigan.
16  *  All rights reserved.
17  *
18  *  Dug Song       <dugsong@monkey.org>
19  *  Andy Adamson   <andros@umich.edu>
20  *
21  *  Redistribution and use in source and binary forms, with or without
22  *  modification, are permitted provided that the following conditions
23  *  are met:
24  *
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.
33  *
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.
45  *
46  */
47
48 #ifndef EXPORT_SYMTAB
49 # define EXPORT_SYMTAB
50 #endif
51 #define DEBUG_SUBSYSTEM S_SEC
52 #ifdef __KERNEL__
53 #include <linux/init.h>
54 #include <linux/module.h>
55 #include <linux/slab.h>
56 #include <linux/dcache.h>
57 #include <linux/fs.h>
58 #include <linux/random.h>
59 /* for rpc_pipefs */
60 struct rpc_clnt;
61 #include <linux/sunrpc/rpc_pipe_fs.h>
62 #else
63 #include <liblustre.h>
64 #endif
65
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>
74
75 #include "gss_err.h"
76 #include "gss_internal.h"
77 #include "gss_api.h"
78
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)
83
84 #define LUSTRE_PIPEDIR          "/lustre"
85
86 /**********************************************
87  * gss security init/fini helper              *
88  **********************************************/
89
90 #define SECINIT_RPC_TIMEOUT     (30)
91 #define SECFINI_RPC_TIMEOUT     (10)
92
93 static int secinit_compose_request(struct obd_import *imp,
94                                    char *buf, int bufsize,
95                                    int lustre_srv,
96                                    uid_t uid, gid_t gid,
97                                    long token_size,
98                                    char __user *token)
99 {
100         struct ptlrpcs_wire_hdr *hdr;
101         struct lustre_msg       *lmsg;
102         struct mds_req_sec_desc *secdesc;
103         int                      size = sizeof(*secdesc);
104         __u32                    lmsg_size, *p;
105         int                      rc;
106
107         lmsg_size = lustre_msg_size(1, &size);
108
109         if (sizeof(*hdr) + lmsg_size + size_round(token_size) > bufsize) {
110                 CERROR("token size %ld too large\n", token_size);
111                 return -EINVAL;
112         }
113
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);
120
121         /* lustre message & secdesc */
122         lmsg = buf_to_lustre_msg(buf);
123
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;
129
130         lmsg->handle   = imp->imp_remote_handle;
131         lmsg->type     = PTL_RPC_MSG_REQUEST;
132         lmsg->opc      = SEC_INIT;
133         lmsg->flags    = 0;
134         lmsg->conn_cnt = imp->imp_conn_cnt;
135
136         p = (__u32 *) (buf + sizeof(*hdr) + lmsg_size);
137
138         /* gss hdr */
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 */
145
146         /* plus lustre svc type */
147         *p++ = cpu_to_le32(lustre_srv);
148
149         /* now the token part */
150         *p++ = cpu_to_le32((__u32) token_size);
151         LASSERT(((char *)p - buf) + token_size <= bufsize);
152
153         rc = copy_from_user(p, token, token_size);
154         if (rc) {
155                 CERROR("can't copy token\n");
156                 return -EFAULT;
157         }
158
159         rc = size_round(((char *)p - buf) + token_size);
160         return rc;
161 }
162
163 static int secinit_parse_reply(char *repbuf, int replen,
164                                char __user *outbuf, long outlen)
165 {
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;
170         __u32                    effective = 0;
171
172         if (replen <= (4 + 6) * 4) {
173                 CERROR("reply size %d too small\n", replen);
174                 return -EINVAL;
175         }
176
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);
181
182         lmsg_len = le32_to_cpu(p[2]);
183         sec_len = le32_to_cpu(p[3]);
184
185         /* sanity checks */
186         if (hdr->flavor != PTLRPC_SEC_GSS ||
187             hdr->sectype != PTLRPC_SEC_TYPE_NONE) {
188                 CERROR("unexpected reply\n");
189                 return -EINVAL;
190         }
191         if (hdr->msg_len % 8 ||
192             sizeof(*hdr) + hdr->msg_len + hdr->sec_len > replen) {
193                 CERROR("unexpected reply\n");
194                 return -EINVAL;
195         }
196         if (hdr->sec_len > outlen) {
197                 CERROR("outbuf too small\n");
198                 return -EINVAL;
199         }
200
201         p = (__u32 *) buf_to_sec_data(repbuf);
202         effective = 0;
203
204         status = le32_to_cpu(*p++);
205         major = le32_to_cpu(*p++);
206         minor = le32_to_cpu(*p++);
207         seq = le32_to_cpu(*p++);
208         effective += 4 * 4;
209
210         if (copy_to_user(outbuf, &status, 4))
211                 return -EFAULT;
212         outbuf += 4;
213         if (copy_to_user(outbuf, &major, 4))
214                 return -EFAULT;
215         outbuf += 4;
216         if (copy_to_user(outbuf, &minor, 4))
217                 return -EFAULT;
218         outbuf += 4;
219         if (copy_to_user(outbuf, &seq, 4))
220                 return -EFAULT;
221         outbuf += 4;
222
223         obj_len = le32_to_cpu(*p++);
224         round_len = (obj_len + 3) & ~ 3;
225         if (copy_to_user(outbuf, &obj_len, 4))
226                 return -EFAULT;
227         outbuf += 4;
228         if (copy_to_user(outbuf, (char *)p, round_len))
229                 return -EFAULT;
230         p += round_len / 4;
231         outbuf += round_len;
232         effective += 4 + round_len;
233
234         obj_len = le32_to_cpu(*p++);
235         round_len = (obj_len + 3) & ~ 3;
236         if (copy_to_user(outbuf, &obj_len, 4))
237                 return -EFAULT;
238         outbuf += 4;
239         if (copy_to_user(outbuf, (char *)p, round_len))
240                 return -EFAULT;
241         p += round_len / 4;
242         outbuf += round_len;
243         effective += 4 + round_len;
244
245         return effective;
246 }
247
248 /* XXX move to where lgssd could see */
249 struct lgssd_ioctl_param {
250         int             version;        /* in   */
251         char           *uuid;           /* in   */
252         int             lustre_svc;     /* in   */
253         uid_t           uid;            /* in   */
254         gid_t           gid;            /* 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  */
261 };
262
263 static int gss_send_secinit_rpc(__user char *buffer, unsigned long count)
264 {
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;
272         char                      obdname[64];
273         long                      lsize;
274         int                       rc, reqlen, replen;
275
276         if (count != sizeof(param)) {
277                 CERROR("ioctl size %lu, expect %d, please check lgssd version\n",
278                         count, sizeof(param));
279                 RETURN(-EINVAL);
280         }
281         if (copy_from_user(&param, buffer, sizeof(param))) {
282                 CERROR("failed copy data from lgssd\n");
283                 RETURN(-EFAULT);
284         }
285
286         if (param.version != GSSD_INTERFACE_VERSION) {
287                 CERROR("gssd interface version %d (expect %d)\n",
288                         param.version, GSSD_INTERFACE_VERSION);
289                 RETURN(-EINVAL);
290         }
291
292         /* take name */
293         if (strncpy_from_user(obdname, param.uuid,
294                               sizeof(obdname)) <= 0) {
295                 CERROR("Invalid obdname pointer\n");
296                 RETURN(-EFAULT);
297         }
298
299         obd = class_name2obd(obdname);
300         if (!obd) {
301                 CERROR("no such obd %s\n", obdname);
302                 RETURN(-EINVAL);
303         }
304
305         imp = class_import_get(obd->u.cli.cl_import);
306
307         OBD_ALLOC(reqbuf, reqbuf_size);
308         OBD_ALLOC(repbuf, reqbuf_size);
309
310         if (!reqbuf || !repbuf) {
311                 CERROR("Can't alloc buffer: %p/%p\n", reqbuf, repbuf);
312                 param.status = -ENOMEM;
313                 goto out_copy;
314         }
315
316         /* get token */
317         reqlen = secinit_compose_request(imp, reqbuf, reqbuf_size,
318                                          param.lustre_svc,
319                                          param.uid, param.gid,
320                                          param.send_token_size,
321                                          param.send_token);
322         if (reqlen < 0) {
323                 param.status = reqlen;
324                 goto out_copy;
325         }
326
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) {
331                 param.status = rc;
332                 goto out_copy;
333         }
334
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;
339                 goto out_copy;
340         }
341
342         lsize = secinit_parse_reply(repbuf, replen,
343                                     param.reply_buf, param.reply_buf_size);
344         if (lsize < 0) {
345                 param.status = (int) lsize;
346                 goto out_copy;
347         }
348
349         param.status = 0;
350         param.reply_length = lsize;
351
352 out_copy:
353         if (copy_to_user(buffer, &param, sizeof(param)))
354                 rc = -EFAULT;
355         else
356                 rc = 0;
357
358         class_import_put(imp);
359         if (request == NULL) {
360                 if (repbuf)
361                         OBD_FREE(repbuf, repbuf_size);
362                 if (reqbuf)
363                         OBD_FREE(reqbuf, reqbuf_size);
364         } else {
365                 rawrpc_req_finished(request);
366         }
367         RETURN(rc);
368 }
369
370 /**********************************************
371  * structure definitions                      *
372  **********************************************/
373 struct gss_sec {
374         struct ptlrpc_sec       gs_base;
375         struct gss_api_mech    *gs_mech;
376 #ifdef __KERNEL__
377         spinlock_t              gs_lock;
378         struct list_head        gs_upcalls;
379         char                   *gs_pipepath;
380         struct dentry          *gs_depipe;
381 #endif
382 };
383
384 #ifdef __KERNEL__
385
386 static rwlock_t gss_ctx_lock = RW_LOCK_UNLOCKED;
387
388 struct gss_upcall_msg_data {
389         __u32                           gum_uid;
390         __u32                           gum_svc;
391         __u32                           gum_nal;
392         __u32                           gum_netid;
393         __u64                           gum_nid;
394 };
395
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;
404 };
405
406 /**********************************************
407  * rpc_pipe upcall helpers                    *
408  **********************************************/
409 static
410 void gss_release_msg(struct gss_upcall_msg *gmsg)
411 {
412         ENTRY;
413         LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
414
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));
418                 EXIT;
419                 return;
420         }
421         LASSERT(list_empty(&gmsg->gum_list));
422         LASSERT(list_empty(&gmsg->gum_base.list));
423         OBD_FREE(gmsg, sizeof(*gmsg));
424         EXIT;
425 }
426
427 static void
428 gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg)
429 {
430         ENTRY;
431         if (list_empty(&gmsg->gum_list)) {
432                 EXIT;
433                 return;
434         }
435
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);
442         EXIT;
443 }
444
445 static void
446 gss_unhash_msg(struct gss_upcall_msg *gmsg)
447 {
448         struct gss_sec *gsec = gmsg->gum_gsec;
449
450         spin_lock(&gsec->gs_lock);
451         gss_unhash_msg_nolock(gmsg);
452         spin_unlock(&gsec->gs_lock);
453 }
454
455 static
456 struct gss_upcall_msg * gss_find_upcall(struct gss_sec *gsec,
457                                         char *obdname,
458                                         struct gss_upcall_msg_data *gmd)
459 {
460         struct gss_upcall_msg *gmsg;
461         ENTRY;
462
463         list_for_each_entry(gmsg, &gsec->gs_upcalls, gum_list) {
464                 if (memcmp(&gmsg->gum_data, gmd, sizeof(*gmd)))
465                         continue;
466                 if (strcmp(gmsg->gum_obdname, obdname))
467                         continue;
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));
472                 RETURN(gmsg);
473         }
474         RETURN(NULL);
475 }
476
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)
480 {
481         struct rpc_pipe_msg *rpcmsg;
482         ENTRY;
483
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));
491
492         rpcmsg = &gmsg->gum_base;
493         rpcmsg->data = &gmsg->gum_data;
494         rpcmsg->len = sizeof(gmsg->gum_data);
495         EXIT;
496 }
497 #endif /* __KERNEL__ */
498
499 /********************************************
500  * gss cred manipulation helpers            *
501  ********************************************/
502 #if 0
503 static
504 int gss_cred_is_uptodate_ctx(struct ptlrpc_cred *cred)
505 {
506         struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
507         int res = 0;
508
509         read_lock(&gss_ctx_lock);
510         if (((cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) ==
511              PTLRPC_CRED_UPTODATE) &&
512             gcred->gc_ctx)
513                 res = 1;
514         read_unlock(&gss_ctx_lock);
515         return res;
516 }
517 #endif
518
519 static inline
520 struct gss_cl_ctx * gss_get_ctx(struct gss_cl_ctx *ctx)
521 {
522         atomic_inc(&ctx->gc_refcount);
523         return ctx;
524 }
525
526 static
527 void gss_destroy_ctx(struct gss_cl_ctx *ctx)
528 {
529         ENTRY;
530
531         CDEBUG(D_SEC, "destroy cl_ctx %p\n", ctx);
532         if (ctx->gc_gss_ctx)
533                 kgss_delete_sec_context(&ctx->gc_gss_ctx);
534
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;
538         }
539
540         OBD_FREE(ctx, sizeof(*ctx));
541 }
542
543 static
544 void gss_put_ctx(struct gss_cl_ctx *ctx)
545 {
546         if (atomic_dec_and_test(&ctx->gc_refcount))
547                 gss_destroy_ctx(ctx);
548 }
549
550 static
551 struct gss_cl_ctx *gss_cred_get_ctx(struct ptlrpc_cred *cred)
552 {
553         struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
554         struct gss_cl_ctx *ctx = NULL;
555
556         read_lock(&gss_ctx_lock);
557         if (gcred->gc_ctx)
558                 ctx = gss_get_ctx(gcred->gc_ctx);
559         read_unlock(&gss_ctx_lock);
560         return ctx;
561 }
562
563 static
564 void gss_cred_set_ctx(struct ptlrpc_cred *cred, struct gss_cl_ctx *ctx)
565 {
566         struct gss_cred *gcred = container_of(cred, struct gss_cred, gc_base);
567         struct gss_cl_ctx *old;
568         __u64 ctx_expiry;
569         ENTRY;
570
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 */
574         }
575         cred->pc_expire = (unsigned long) ctx_expiry;
576
577         write_lock(&gss_ctx_lock);
578         old = gcred->gc_ctx;
579         gcred->gc_ctx = ctx;
580         set_bit(PTLRPC_CRED_UPTODATE_BIT, &cred->pc_flags);
581         write_unlock(&gss_ctx_lock);
582         if (old)
583                 gss_put_ctx(old);
584
585         CDEBUG(D_SEC, "client refreshed gss cred %p(uid %u)\n",
586                cred, cred->pc_uid);
587         EXIT;
588 }
589
590 static int
591 simple_get_bytes(char **buf, __u32 *buflen, void *res, __u32 reslen)
592 {
593         if (*buflen < reslen) {
594                 CERROR("buflen %u < %u\n", *buflen, reslen);
595                 return -EINVAL;
596         }
597
598         memcpy(res, *buf, reslen);
599         *buf += reslen;
600         *buflen -= reslen;
601         return 0;
602 }
603
604 /* data passed down:
605  *  - uid
606  *  - timeout
607  *  - gc_win / error
608  *  - wire_ctx (rawobj)
609  *  - mech_ctx? (rawobj)
610  */
611 static
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)
615 {
616         char *p = (char *)buf->data;
617         struct gss_cl_ctx *ctx;
618         __u32 len = buf->len;
619         unsigned int timeout;
620         rawobj_t tmp_buf;
621         int err = -EPERM;
622         ENTRY;
623
624         *gc = NULL;
625         *gss_err = 0;
626
627         OBD_ALLOC(ctx, sizeof(*ctx));
628         if (!ctx)
629                 RETURN(-ENOMEM);
630
631         ctx->gc_proc = RPC_GSS_PROC_DATA;
632         ctx->gc_seq = 0;
633         spin_lock_init(&ctx->gc_seq_lock);
634         atomic_set(&ctx->gc_refcount,1);
635
636         if (simple_get_bytes(&p, &len, &gmd->gum_uid, sizeof(gmd->gum_uid)))
637                 goto err_free_ctx;
638         if (simple_get_bytes(&p, &len, &gmd->gum_svc, sizeof(gmd->gum_svc)))
639                 goto err_free_ctx;
640         if (simple_get_bytes(&p, &len, &gmd->gum_nal, sizeof(gmd->gum_nal)))
641                 goto err_free_ctx;
642         if (simple_get_bytes(&p, &len, &gmd->gum_netid, sizeof(gmd->gum_netid)))
643                 goto err_free_ctx;
644         if (simple_get_bytes(&p, &len, &gmd->gum_nid, sizeof(gmd->gum_nid)))
645                 goto err_free_ctx;
646         /* FIXME: discarded timeout for now */
647         if (simple_get_bytes(&p, &len, &timeout, sizeof(timeout)))
648                 goto err_free_ctx;
649         if (simple_get_bytes(&p, &len, &ctx->gc_win, sizeof(ctx->gc_win)))
650                 goto err_free_ctx;
651
652         /* lgssd signals an error by passing ctx->gc_win = 0: */
653         if (!ctx->gc_win) {
654                 /* in which case the next 2 int are:
655                  * - rpc error
656                  * - gss error
657                  */
658                 if (simple_get_bytes(&p, &len, &err, sizeof(err))) {
659                         err = -EPERM;
660                         goto err_free_ctx;
661                 }
662                 if (simple_get_bytes(&p, &len, gss_err, sizeof(*gss_err))) {
663                         err = -EPERM;
664                         goto err_free_ctx;
665                 }
666                 if (err == 0 && *gss_err == 0) {
667                         CERROR("no error passed from downcall\n");
668                         err = -EPERM;
669                 }
670                 goto err_free_ctx;
671         }
672
673         if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
674                 goto err_free_ctx;
675         if (rawobj_dup(&ctx->gc_wire_ctx, &tmp_buf)) {
676                 err = -ENOMEM;
677                 goto err_free_ctx;
678         }
679         if (rawobj_extract_local(&tmp_buf, (__u32 **) ((void *)&p), &len))
680                 goto err_free_wire_ctx;
681         if (len) {
682                 CERROR("unexpected trailing %u bytes\n", len);
683                 goto err_free_wire_ctx;
684         }
685         if (kgss_import_sec_context(&tmp_buf, gm, &ctx->gc_gss_ctx))
686                 goto err_free_wire_ctx;
687
688         *gc = ctx;
689         RETURN(0);
690
691 err_free_wire_ctx:
692         if (ctx->gc_wire_ctx.data)
693                 OBD_FREE(ctx->gc_wire_ctx.data, ctx->gc_wire_ctx.len);
694 err_free_ctx:
695         OBD_FREE(ctx, sizeof(*ctx));
696         CDEBUG(D_SEC, "err_code %d, gss code %d\n", err, *gss_err);
697         return err;
698 }
699
700 /***************************************
701  * cred APIs                           *
702  ***************************************/
703 #ifdef __KERNEL__
704 #define CRED_REFRESH_UPCALL_TIMEOUT     (50)
705 static int gss_cred_refresh(struct ptlrpc_cred *cred)
706 {
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;
713         wait_queue_t                wait;
714         uid_t                       uid = cred->pc_uid;
715         int                         res;
716         ENTRY;
717
718         might_sleep();
719
720         /* any flags means it has been handled, do nothing */
721         if (cred->pc_flags & PTLRPC_CRED_FLAGS_MASK)
722                 RETURN(0);
723
724         LASSERT(cred->pc_sec);
725         LASSERT(cred->pc_sec->ps_import);
726         LASSERT(cred->pc_sec->ps_import->imp_obd);
727
728         import = cred->pc_sec->ps_import;
729         if (!import->imp_connection) {
730                 CERROR("import has no connection set\n");
731                 RETURN(-EINVAL);
732         }
733
734         gmd.gum_uid = uid;
735         gmd.gum_nal = import->imp_connection->c_peer.peer_ni->pni_number;
736         gmd.gum_netid = 0;
737         gmd.gum_nid = import->imp_connection->c_peer.peer_id.nid;
738
739         obdtype = import->imp_obd->obd_type->typ_name;
740         if (!strcmp(obdtype, "mdc"))
741                 gmd.gum_svc = LUSTRE_GSS_SVC_MDS;
742         else if (!strcmp(obdtype, "osc"))
743                 gmd.gum_svc = LUSTRE_GSS_SVC_OSS;
744         else {
745                 CERROR("gss on %s?\n", obdtype);
746                 RETURN(-EINVAL);
747         }
748
749         gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
750         obdname = import->imp_obd->obd_name;
751         dentry = gsec->gs_depipe;
752         gss_new = NULL;
753         res = 0;
754
755         CDEBUG(D_SEC, "Initiate gss context %p(%u@%s)\n",
756                container_of(cred, struct gss_cred, gc_base),
757                uid, import->imp_target_uuid.uuid);
758
759 again:
760         spin_lock(&gsec->gs_lock);
761         gss_msg = gss_find_upcall(gsec, obdname, &gmd);
762         if (gss_msg) {
763                 if (gss_new) {
764                         OBD_FREE(gss_new, sizeof(*gss_new));
765                         gss_new = NULL;
766                 }
767                 GOTO(waiting, res);
768         }
769
770         if (!gss_new) {
771                 spin_unlock(&gsec->gs_lock);
772                 OBD_ALLOC(gss_new, sizeof(*gss_new));
773                 if (!gss_new)
774                         RETURN(-ENOMEM);
775                 goto again;
776         }
777         /* so far we'v created gss_new */
778         gss_init_upcall_msg(gss_new, gsec, obdname, &gmd);
779
780         /* we'v created upcall msg, nobody else should touch the
781          * flag of this cred, unless be set as dead/expire by
782          * administrator via lctl etc.
783          */
784         if (cred->pc_flags & PTLRPC_CRED_FLAGS_MASK) {
785                 CWARN("cred %p("LPU64"/%u) was set flags %lx unexpectedly\n",
786                       cred, cred->pc_pag, cred->pc_uid, cred->pc_flags);
787                 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
788                 gss_unhash_msg_nolock(gss_new);
789                 spin_unlock(&gsec->gs_lock);
790                 gss_release_msg(gss_new);
791                 RETURN(0);
792         }
793
794         /* need to make upcall now */
795         spin_unlock(&gsec->gs_lock);
796         res = rpc_queue_upcall(dentry->d_inode, &gss_new->gum_base);
797         if (res) {
798                 CERROR("rpc_queue_upcall failed: %d\n", res);
799                 gss_unhash_msg(gss_new);
800                 gss_release_msg(gss_new);
801                 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
802                 RETURN(res);
803         }
804         gss_msg = gss_new;
805         spin_lock(&gsec->gs_lock);
806
807 waiting:
808         /* upcall might finish quickly */
809         if (list_empty(&gss_msg->gum_list)) {
810                 spin_unlock(&gsec->gs_lock);
811                 res = 0;
812                 goto out;
813         }
814
815         init_waitqueue_entry(&wait, current);
816         set_current_state(TASK_INTERRUPTIBLE);
817         add_wait_queue(&gss_msg->gum_waitq, &wait);
818         spin_unlock(&gsec->gs_lock);
819
820         if (gss_new)
821                 res = schedule_timeout(CRED_REFRESH_UPCALL_TIMEOUT * HZ);
822         else {
823                 schedule();
824                 res = 0;
825         }
826
827         remove_wait_queue(&gss_msg->gum_waitq, &wait);
828
829         /* - the one who refresh the cred for us should also be responsible
830          *   to set the status of cred, we can simply return.
831          * - if cred flags has been set, we also don't need to do that again,
832          *   no matter signal pending or timeout etc.
833          */
834         if (!gss_new || cred->pc_flags & PTLRPC_CRED_FLAGS_MASK)
835                 goto out;
836
837         if (signal_pending(current)) {
838                 CERROR("%s: cred %p: interrupted upcall\n",
839                        current->comm, cred);
840                 cred->pc_flags |= PTLRPC_CRED_DEAD | PTLRPC_CRED_ERROR;
841                 res = -EINTR;
842         } else if (res == 0) {
843                 CERROR("cred %p: upcall timedout\n", cred);
844                 set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
845                 res = -ETIMEDOUT;
846         } else
847                 res = 0;
848
849 out:
850         gss_release_msg(gss_msg);
851
852         RETURN(res);
853 }
854 #else /* !__KERNEL__ */
855 extern int lgss_handle_krb5_upcall(uid_t uid, __u32 dest_ip,
856                                    char *obd_name,
857                                    char *buf, int bufsize,
858                                    int (*callback)(char*, unsigned long));
859
860 static int gss_cred_refresh(struct ptlrpc_cred *cred)
861 {
862         char                    buf[4096];
863         rawobj_t                obj;
864         struct obd_import      *imp;
865         struct gss_sec         *gsec;
866         struct gss_api_mech    *mech;
867         struct gss_cl_ctx      *ctx = NULL;
868         struct vfs_cred         vcred = { 0 };
869         ptl_nid_t               peer_nid;
870         __u32                   dest_ip;
871         __u32                   subflavor;
872         int                     rc, gss_err;
873
874         LASSERT(cred);
875         LASSERT(cred->pc_sec);
876         LASSERT(cred->pc_sec->ps_import);
877         LASSERT(cred->pc_sec->ps_import->imp_obd);
878
879         if (ptlrpcs_cred_is_uptodate(cred))
880                 RETURN(0);
881
882         imp = cred->pc_sec->ps_import;
883         peer_nid = imp->imp_connection->c_peer.peer_id.nid;
884         dest_ip = (__u32) (peer_nid & 0xFFFFFFFF);
885         subflavor = cred->pc_sec->ps_flavor.subflavor;
886
887         if (subflavor != PTLRPC_SEC_GSS_KRB5I) {
888                 CERROR("unknown subflavor %u\n", subflavor);
889                 GOTO(err_out, rc = -EINVAL);
890         }
891
892         rc = lgss_handle_krb5_upcall(cred->pc_uid, dest_ip,
893                                      imp->imp_obd->obd_name,
894                                      buf, sizeof(buf),
895                                      gss_send_secinit_rpc);
896         LASSERT(rc != 0);
897         if (rc < 0)
898                 goto err_out;
899
900         obj.data = buf;
901         obj.len = rc;
902
903         gsec = container_of(cred->pc_sec, struct gss_sec, gs_base);
904         mech = gsec->gs_mech;
905         LASSERT(mech);
906         rc = gss_parse_init_downcall(mech, &obj, &ctx, &vcred, &dest_ip,
907                                      &gss_err);
908         if (rc || gss_err) {
909                 CERROR("parse init downcall: rpc %d, gss 0x%x\n", rc, gss_err);
910                 if (rc != -ERESTART || gss_err != 0)
911                         set_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags);
912                 if (rc == 0)
913                         rc = -EPERM;
914                 goto err_out;
915         }
916
917         LASSERT(ctx);
918         gss_cred_set_ctx(cred, ctx);
919         LASSERT(gss_cred_is_uptodate_ctx(cred));
920
921         return 0;
922 err_out:
923         set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
924         return rc;
925 }
926 #endif
927
928 static int gss_cred_match(struct ptlrpc_cred *cred,
929                           struct vfs_cred *vcred)
930 {
931         RETURN(cred->pc_pag == vcred->vc_pag);
932 }
933
934 static int gss_cred_sign(struct ptlrpc_cred *cred,
935                          struct ptlrpc_request *req)
936 {
937         struct gss_cred         *gcred;
938         struct gss_cl_ctx       *ctx;
939         rawobj_t                 lmsg, mic;
940         __u32                   *vp, *vpsave, vlen, seclen;
941         __u32                    seqnum, major, rc = 0;
942         ENTRY;
943
944         LASSERT(req->rq_reqbuf);
945         LASSERT(req->rq_cred == cred);
946
947         gcred = container_of(cred, struct gss_cred, gc_base);
948         ctx = gss_cred_get_ctx(cred);
949         if (!ctx) {
950                 CERROR("cred %p("LPU64"/%u) invalidated?\n",
951                         cred, cred->pc_pag, cred->pc_uid);
952                 RETURN(-EPERM);
953         }
954
955         lmsg.len = req->rq_reqlen;
956         lmsg.data = (__u8 *) req->rq_reqmsg;
957
958         vp = (__u32 *) (lmsg.data + lmsg.len);
959         vlen = req->rq_reqbuf_len - sizeof(struct ptlrpcs_wire_hdr) -
960                lmsg.len;
961         seclen = vlen;
962
963         if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
964                 CERROR("vlen %d, need %d\n",
965                         vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
966                 rc = -EIO;
967                 goto out;
968         }
969
970         spin_lock(&ctx->gc_seq_lock);
971         seqnum = ctx->gc_seq++;
972         spin_unlock(&ctx->gc_seq_lock);
973
974         *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION);    /* version */
975         *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I);      /* subflavor */
976         *vp++ = cpu_to_le32(ctx->gc_proc);              /* proc */
977         *vp++ = cpu_to_le32(seqnum);                    /* seq */
978         *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_INTEGRITY);  /* service */
979         vlen -= 5 * 4;
980
981         if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
982                 rc = -EIO;
983                 goto out;
984         }
985         CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
986
987         vpsave = vp++;  /* reserve for size */
988         vlen -= 4;
989
990         mic.len = vlen;
991         mic.data = (unsigned char *)vp;
992
993         CDEBUG(D_SEC, "reqbuf at %p, lmsg at %p, len %d, mic at %p, len %d\n",
994                req->rq_reqbuf, lmsg.data, lmsg.len, mic.data, mic.len);
995         major = kgss_get_mic(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, &lmsg, &mic);
996         if (major) {
997                 CERROR("cred %p: req %p compute mic error, major %x\n",
998                        cred, req, major);
999                 rc = -EACCES;
1000                 goto out;
1001         }
1002
1003         *vpsave = cpu_to_le32(mic.len);
1004         
1005         seclen = seclen - vlen + mic.len;
1006         buf_to_sec_hdr(req->rq_reqbuf)->sec_len = cpu_to_le32(seclen);
1007         req->rq_reqdata_len += size_round(seclen);
1008         CDEBUG(D_SEC, "msg size %d, checksum size %d, total sec size %d\n",
1009                lmsg.len, mic.len, seclen);
1010 out:
1011         gss_put_ctx(ctx);
1012         RETURN(rc);
1013 }
1014
1015 static int gss_cred_verify(struct ptlrpc_cred *cred,
1016                            struct ptlrpc_request *req)
1017 {
1018         struct gss_cred        *gcred;
1019         struct gss_cl_ctx      *ctx;
1020         struct ptlrpcs_wire_hdr *sec_hdr;
1021         rawobj_t                lmsg, mic;
1022         __u32                   *vp, vlen, subflavor, proc, seq, svc;
1023         __u32                   major, minor, rc;
1024         ENTRY;
1025
1026         LASSERT(req->rq_repbuf);
1027         LASSERT(req->rq_cred == cred);
1028
1029         sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
1030         vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr) + sec_hdr->msg_len);
1031         vlen = sec_hdr->sec_len;
1032
1033         if (vlen < 7 * 4) {
1034                 CERROR("reply sec size %u too small\n", vlen);
1035                 RETURN(-EPROTO);
1036         }
1037
1038         if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
1039                 CERROR("reply have different gss version\n");
1040                 RETURN(-EPROTO);
1041         }
1042         subflavor = le32_to_cpu(*vp++);
1043         proc = le32_to_cpu(*vp++);
1044         vlen -= 3 * 4;
1045
1046         switch (proc) {
1047         case PTLRPC_GSS_PROC_DATA:
1048                 seq = le32_to_cpu(*vp++);
1049                 svc = le32_to_cpu(*vp++);
1050                 if (svc != PTLRPC_GSS_SVC_INTEGRITY) {
1051                         CERROR("Unknown svc %d\n", svc);
1052                         RETURN(-EPROTO);
1053                 }
1054                 if (*vp++ != 0) {
1055                         CERROR("Unexpected ctx handle\n");
1056                         RETURN(-EPROTO);
1057                 }
1058                 mic.len = le32_to_cpu(*vp++);
1059                 vlen -= 4 * 4;
1060                 if (vlen < mic.len) {
1061                         CERROR("vlen %d, mic.len %d\n", vlen, mic.len);
1062                         RETURN(-EINVAL);
1063                 }
1064                 mic.data = (unsigned char *)vp;
1065
1066                 gcred = container_of(cred, struct gss_cred, gc_base);
1067                 ctx = gss_cred_get_ctx(cred);
1068                 LASSERT(ctx);
1069
1070                 lmsg.len = sec_hdr->msg_len;
1071                 lmsg.data = (__u8 *) buf_to_lustre_msg(req->rq_repbuf);
1072
1073                 major = kgss_verify_mic(ctx->gc_gss_ctx, &lmsg, &mic, NULL);
1074                 if (major != GSS_S_COMPLETE) {
1075                         CERROR("cred %p: req %p verify mic error: major %x\n",
1076                                cred, req, major);
1077
1078                         if (major == GSS_S_CREDENTIALS_EXPIRED ||
1079                             major == GSS_S_CONTEXT_EXPIRED) {
1080                                 ptlrpcs_cred_expire(cred);
1081                                 req->rq_ptlrpcs_restart = 1;
1082                                 rc = 0;
1083                         } else
1084                                 rc = -EINVAL;
1085
1086                         GOTO(proc_data_out, rc);
1087                 }
1088
1089                 req->rq_repmsg = (struct lustre_msg *) lmsg.data;
1090                 req->rq_replen = lmsg.len;
1091
1092                 /* here we could check the seq number is the same one
1093                  * we sent to server. but portals has prevent us from
1094                  * replay attack, so maybe we don't need check it again.
1095                  */
1096                 rc = 0;
1097 proc_data_out:
1098                 gss_put_ctx(ctx);
1099                 break;
1100         case PTLRPC_GSS_PROC_ERR:
1101                 major = le32_to_cpu(*vp++);
1102                 minor = le32_to_cpu(*vp++);
1103                 /* server return NO_CONTEXT might be caused by context expire
1104                  * or server reboot/failover. we refresh the cred transparently
1105                  * to upper layer.
1106                  * In some cases, our gss handle is possible to be incidentally
1107                  * identical to another handle since the handle itself is not
1108                  * fully random. In krb5 case, the GSS_S_BAD_SIG will be
1109                  * returned, maybe other gss error for other mechanism. Here we
1110                  * only consider krb5 mech (FIXME) and try to establish new
1111                  * context.
1112                  */
1113                 if (major == GSS_S_NO_CONTEXT ||
1114                     major == GSS_S_BAD_SIG) {
1115                         CWARN("req %p: server report cred %p %s, expired?\n",
1116                                req, cred, (major == GSS_S_NO_CONTEXT) ?
1117                                            "NO_CONTEXT" : "BAD_SIG");
1118
1119                         ptlrpcs_cred_expire(cred);
1120                         req->rq_ptlrpcs_restart = 1;
1121                         rc = 0;
1122                 } else {
1123                         CERROR("req %p: unrecognized gss error (%x/%x)\n",
1124                                 req, major, minor);
1125                         rc = -EACCES;
1126                 }
1127                 break;
1128         default:
1129                 CERROR("unknown gss proc %d\n", proc);
1130                 rc = -EPROTO;
1131         }
1132
1133         RETURN(rc);
1134 }
1135
1136 static int gss_cred_seal(struct ptlrpc_cred *cred,
1137                          struct ptlrpc_request *req)
1138 {
1139         struct gss_cred         *gcred;
1140         struct gss_cl_ctx       *ctx;
1141         struct ptlrpcs_wire_hdr *sec_hdr;
1142         rawobj_buf_t             msg_buf;
1143         rawobj_t                 cipher_buf;
1144         __u32                   *vp, *vpsave, vlen, seclen;
1145         __u32                    major, seqnum, rc = 0;
1146         ENTRY;
1147
1148         LASSERT(req->rq_reqbuf);
1149         LASSERT(req->rq_cred == cred);
1150
1151         gcred = container_of(cred, struct gss_cred, gc_base);
1152         ctx = gss_cred_get_ctx(cred);
1153         if (!ctx) {
1154                 CERROR("cred %p("LPU64"/%u) invalidated?\n",
1155                         cred, cred->pc_pag, cred->pc_uid);
1156                 RETURN(-EPERM);
1157         }
1158
1159         vp = (__u32 *) (req->rq_reqbuf + sizeof(*sec_hdr));
1160         vlen = req->rq_reqbuf_len - sizeof(*sec_hdr);
1161         seclen = vlen;
1162
1163         if (vlen < 6 * 4 + size_round4(ctx->gc_wire_ctx.len)) {
1164                 CERROR("vlen %d, need %d\n",
1165                         vlen, 6 * 4 + size_round4(ctx->gc_wire_ctx.len));
1166                 rc = -EIO;
1167                 goto out;
1168         }
1169
1170         spin_lock(&ctx->gc_seq_lock);
1171         seqnum = ctx->gc_seq++;
1172         spin_unlock(&ctx->gc_seq_lock);
1173
1174         *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION);    /* version */
1175         *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5P);      /* subflavor */
1176         *vp++ = cpu_to_le32(ctx->gc_proc);              /* proc */
1177         *vp++ = cpu_to_le32(seqnum);                    /* seq */
1178         *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_PRIVACY);    /* service */
1179         vlen -= 5 * 4;
1180
1181         if (rawobj_serialize(&ctx->gc_wire_ctx, &vp, &vlen)) {
1182                 rc = -EIO;
1183                 goto out;
1184         }
1185         CDEBUG(D_SEC, "encoded wire_ctx length %d\n", ctx->gc_wire_ctx.len);
1186
1187         vpsave = vp++;  /* reserve for size */
1188         vlen -= 4;
1189
1190         msg_buf.buf = (__u8 *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1191         msg_buf.buflen = req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
1192                                           GSS_PRIVBUF_SUFFIX_LEN;
1193         msg_buf.dataoff = GSS_PRIVBUF_PREFIX_LEN;
1194         msg_buf.datalen = req->rq_reqlen;
1195
1196         cipher_buf.data = (__u8 *) vp;
1197         cipher_buf.len = vlen;
1198
1199         major = kgss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1200                           &msg_buf, &cipher_buf);
1201         if (major) {
1202                 CERROR("cred %p: error wrap: major 0x%x\n", cred, major);
1203                 GOTO(out, rc = -EINVAL);
1204         }
1205
1206         *vpsave = cpu_to_le32(cipher_buf.len);
1207
1208         seclen = seclen - vlen + cipher_buf.len;
1209         sec_hdr = buf_to_sec_hdr(req->rq_reqbuf);
1210         sec_hdr->sec_len = cpu_to_le32(seclen);
1211         req->rq_reqdata_len += size_round(seclen);
1212
1213         CDEBUG(D_SEC, "msg size %d, total sec size %d\n",
1214                req->rq_reqlen, seclen);
1215 out:
1216         gss_put_ctx(ctx);
1217         RETURN(rc);
1218 }
1219
1220 static int gss_cred_unseal(struct ptlrpc_cred *cred,
1221                            struct ptlrpc_request *req)
1222 {
1223         struct gss_cred        *gcred;
1224         struct gss_cl_ctx      *ctx;
1225         struct ptlrpcs_wire_hdr *sec_hdr;
1226         rawobj_t                cipher_text, plain_text;
1227         __u32                   *vp, vlen, subflavor, proc, seq, svc;
1228         __u32                   major, rc;
1229         ENTRY;
1230
1231         LASSERT(req->rq_repbuf);
1232         LASSERT(req->rq_cred == cred);
1233
1234         sec_hdr = buf_to_sec_hdr(req->rq_repbuf);
1235         if (sec_hdr->msg_len != 0) {
1236                 CERROR("unexpected msg_len %u\n", sec_hdr->msg_len);
1237                 RETURN(-EPROTO);
1238         }
1239
1240         vp = (__u32 *) (req->rq_repbuf + sizeof(*sec_hdr));
1241         vlen = sec_hdr->sec_len;
1242
1243         if (vlen < 7 * 4) {
1244                 CERROR("reply sec size %u too small\n", vlen);
1245                 RETURN(-EPROTO);
1246         }
1247
1248         if (*vp++ != cpu_to_le32(PTLRPC_SEC_GSS_VERSION)) {
1249                 CERROR("reply have different gss version\n");
1250                 RETURN(-EPROTO);
1251         }
1252         subflavor = le32_to_cpu(*vp++);
1253         proc = le32_to_cpu(*vp++);
1254         seq = le32_to_cpu(*vp++);
1255         svc = le32_to_cpu(*vp++);
1256         vlen -= 5 * 4;
1257
1258         switch (proc) {
1259         case PTLRPC_GSS_PROC_DATA:
1260                 if (svc != PTLRPC_GSS_SVC_PRIVACY) {
1261                         CERROR("Unknown svc %d\n", svc);
1262                         RETURN(-EPROTO);
1263                 }
1264                 if (*vp++ != 0) {
1265                         CERROR("Unexpected ctx handle\n");
1266                         RETURN(-EPROTO);
1267                 }
1268                 vlen -= 4;
1269
1270                 cipher_text.len = le32_to_cpu(*vp++);
1271                 cipher_text.data = (__u8 *) vp;
1272                 vlen -= 4;
1273
1274                 if (vlen < cipher_text.len) {
1275                         CERROR("cipher text to be %u while buf only %u\n",
1276                                 cipher_text.len, vlen);
1277                         RETURN(-EPROTO);
1278                 }
1279
1280                 plain_text = cipher_text;
1281
1282                 gcred = container_of(cred, struct gss_cred, gc_base);
1283                 ctx = gss_cred_get_ctx(cred);
1284                 LASSERT(ctx);
1285
1286                 major = kgss_unwrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
1287                                     &cipher_text, &plain_text);
1288                 if (major) {
1289                         CERROR("cred %p: error unwrap: major 0x%x\n",
1290                                cred, major);
1291
1292                         if (major == GSS_S_CREDENTIALS_EXPIRED ||
1293                             major == GSS_S_CONTEXT_EXPIRED) {
1294                                 ptlrpcs_cred_expire(cred);
1295                                 req->rq_ptlrpcs_restart = 1;
1296                                 rc = 0;
1297                         } else
1298                                 rc = -EINVAL;
1299
1300                         GOTO(proc_out, rc);
1301                 }
1302
1303                 req->rq_repmsg = (struct lustre_msg *) vp;
1304                 req->rq_replen = plain_text.len;
1305
1306                 rc = 0;
1307 proc_out:
1308                 gss_put_ctx(ctx);
1309                 break;
1310         default:
1311                 CERROR("unknown gss proc %d\n", proc);
1312                 rc = -EPROTO;
1313         }
1314
1315         RETURN(rc);
1316 }
1317
1318 static void destroy_gss_context(struct ptlrpc_cred *cred)
1319 {
1320         struct ptlrpcs_wire_hdr *hdr;
1321         struct lustre_msg       *lmsg;
1322         struct gss_cred         *gcred;
1323         struct ptlrpc_request    req;
1324         struct obd_import       *imp;
1325         __u32                   *vp, lmsg_size;
1326         struct ptlrpc_request   *raw_req = NULL;
1327         const int                repbuf_len = 256;
1328         char                    *repbuf;
1329         int                      replen, rc;
1330         ENTRY;
1331
1332         imp = cred->pc_sec->ps_import;
1333         LASSERT(imp);
1334
1335         if (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags) ||
1336             !test_bit(PTLRPC_CRED_UPTODATE_BIT, &cred->pc_flags)) {
1337                 CDEBUG(D_SEC, "Destroy dead cred %p(%u@%s)\n",
1338                        cred, cred->pc_uid, imp->imp_target_uuid.uuid);
1339                 EXIT;
1340                 return;
1341         }
1342
1343         might_sleep();
1344
1345         /* cred's refcount is 0, steal one */
1346         atomic_inc(&cred->pc_refcount);
1347
1348         gcred = container_of(cred, struct gss_cred, gc_base);
1349         gcred->gc_ctx->gc_proc = PTLRPC_GSS_PROC_DESTROY;
1350
1351         CDEBUG(D_SEC, "client destroy gss cred %p(%u@%s)\n",
1352                gcred, cred->pc_uid, imp->imp_target_uuid.uuid);
1353
1354         lmsg_size = lustre_msg_size(0, NULL);
1355         req.rq_reqbuf_len = sizeof(*hdr) + lmsg_size +
1356                             ptlrpcs_est_req_payload(cred->pc_sec, lmsg_size);
1357
1358         OBD_ALLOC(req.rq_reqbuf, req.rq_reqbuf_len);
1359         if (!req.rq_reqbuf) {
1360                 CERROR("Fail to alloc reqbuf, cancel anyway\n");
1361                 atomic_dec(&cred->pc_refcount);
1362                 EXIT;
1363                 return;
1364         }
1365
1366         /* wire hdr */
1367         hdr = buf_to_sec_hdr(req.rq_reqbuf);
1368         hdr->flavor  = cpu_to_le32(PTLRPC_SEC_GSS);
1369         hdr->sectype = cpu_to_le32(PTLRPC_SEC_TYPE_AUTH);
1370         hdr->msg_len = cpu_to_le32(lmsg_size);
1371         hdr->sec_len = cpu_to_le32(0);
1372
1373         /* lustre message */
1374         lmsg = buf_to_lustre_msg(req.rq_reqbuf);
1375         lustre_init_msg(lmsg, 0, NULL, NULL);
1376         lmsg->handle   = imp->imp_remote_handle;
1377         lmsg->type     = PTL_RPC_MSG_REQUEST;
1378         lmsg->opc      = SEC_FINI;
1379         lmsg->flags    = 0;
1380         lmsg->conn_cnt = imp->imp_conn_cnt;
1381         /* add this for randomize */
1382         get_random_bytes(&lmsg->last_xid, sizeof(lmsg->last_xid));
1383         get_random_bytes(&lmsg->transno, sizeof(lmsg->transno));
1384
1385         vp = (__u32 *) req.rq_reqbuf;
1386
1387         req.rq_cred = cred;
1388         req.rq_reqmsg = buf_to_lustre_msg(req.rq_reqbuf);
1389         req.rq_reqlen = lmsg_size;
1390         req.rq_reqdata_len = sizeof(*hdr) + lmsg_size;
1391
1392         if (gss_cred_sign(cred, &req)) {
1393                 CERROR("failed to sign, cancel anyway\n");
1394                 atomic_dec(&cred->pc_refcount);
1395                 goto exit;
1396         }
1397         atomic_dec(&cred->pc_refcount);
1398
1399         OBD_ALLOC(repbuf, repbuf_len);
1400         if (!repbuf)
1401                 goto exit;
1402
1403         raw_req = ptl_do_rawrpc(imp, req.rq_reqbuf, req.rq_reqbuf_len,
1404                                 req.rq_reqdata_len, repbuf, repbuf_len, &replen,
1405                                 SECFINI_RPC_TIMEOUT, &rc);
1406         if (!raw_req)
1407                 OBD_FREE(repbuf, repbuf_len);
1408
1409 exit:
1410         if (raw_req == NULL)
1411                 OBD_FREE(req.rq_reqbuf, req.rq_reqbuf_len);
1412         else
1413                 rawrpc_req_finished(raw_req);
1414         EXIT;
1415 }
1416
1417 static void gss_cred_destroy(struct ptlrpc_cred *cred)
1418 {
1419         struct gss_cred *gcred;
1420         ENTRY;
1421
1422         LASSERT(cred);
1423         LASSERT(!atomic_read(&cred->pc_refcount));
1424
1425         gcred = container_of(cred, struct gss_cred, gc_base);
1426         if (gcred->gc_ctx) {
1427                 destroy_gss_context(cred);
1428                 gss_put_ctx(gcred->gc_ctx);
1429         }
1430
1431         CDEBUG(D_SEC, "GSS_SEC: destroy cred %p\n", gcred);
1432
1433         OBD_FREE(gcred, sizeof(*gcred));
1434         EXIT;
1435 }
1436
1437 static struct ptlrpc_credops gss_credops = {
1438         .refresh        = gss_cred_refresh,
1439         .match          = gss_cred_match,
1440         .sign           = gss_cred_sign,
1441         .verify         = gss_cred_verify,
1442         .seal           = gss_cred_seal,
1443         .unseal         = gss_cred_unseal,
1444         .destroy        = gss_cred_destroy,
1445 };
1446
1447 #ifdef __KERNEL__
1448 /*******************************************
1449  * rpc_pipe APIs                           *
1450  *******************************************/
1451 static ssize_t
1452 gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
1453                 char *dst, size_t buflen)
1454 {
1455         char *data = (char *)msg->data + msg->copied;
1456         ssize_t mlen = msg->len;
1457         ssize_t left;
1458         ENTRY;
1459
1460         if (mlen > buflen)
1461                 mlen = buflen;
1462         left = copy_to_user(dst, data, mlen);
1463         if (left < 0) {
1464                 msg->errno = left;
1465                 RETURN(left);
1466         }
1467         mlen -= left;
1468         msg->copied += mlen;
1469         msg->errno = 0;
1470         RETURN(mlen);
1471 }
1472
1473 static ssize_t
1474 gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
1475 {
1476         char *buf;
1477         const int bufsize = 1024;
1478         rawobj_t obj;
1479         struct inode *inode = filp->f_dentry->d_inode;
1480         struct rpc_inode *rpci = RPC_I(inode);
1481         struct obd_import *import;
1482         struct ptlrpc_sec *sec;
1483         struct gss_sec *gsec;
1484         char *obdname;
1485         struct gss_api_mech *mech;
1486         struct vfs_cred vcred = { 0 };
1487         struct ptlrpc_cred *cred;
1488         struct gss_upcall_msg *gss_msg;
1489         struct gss_upcall_msg_data gmd = { 0 };
1490         struct gss_cl_ctx *ctx = NULL;
1491         ssize_t left;
1492         int err, gss_err;
1493         ENTRY;
1494
1495         if (mlen > bufsize) {
1496                 CERROR("mlen %ld > bufsize %d\n", (long)mlen, bufsize);
1497                 RETURN(-ENOSPC);
1498         }
1499
1500         OBD_ALLOC(buf, bufsize);
1501         if (!buf) {
1502                 CERROR("alloc mem failed\n");
1503                 RETURN(-ENOMEM);
1504         }
1505
1506         left = copy_from_user(buf, src, mlen);
1507         if (left)
1508                 GOTO(err_free, err = -EFAULT);
1509
1510         obj.data = (unsigned char *)buf;
1511         obj.len = mlen;
1512
1513         LASSERT(rpci->private);
1514         gsec = (struct gss_sec *)rpci->private;
1515         sec = &gsec->gs_base;
1516         LASSERT(sec->ps_import);
1517         import = class_import_get(sec->ps_import);
1518         LASSERT(import->imp_obd);
1519         obdname = import->imp_obd->obd_name;
1520         mech = gsec->gs_mech;
1521
1522         err = gss_parse_init_downcall(mech, &obj, &ctx, &gmd, &gss_err);
1523         if (err)
1524                 CERROR("parse init downcall err %d\n", err);
1525
1526         vcred.vc_uid = gmd.gum_uid;
1527         vcred.vc_pag = vcred.vc_uid; /* FIXME */
1528
1529         cred = ptlrpcs_cred_lookup(sec, &vcred);
1530         if (!cred) {
1531                 CWARN("didn't find cred for uid %u\n", vcred.vc_uid);
1532                 GOTO(err, err = -EINVAL);
1533         }
1534
1535         if (err || gss_err) {
1536                 set_bit(PTLRPC_CRED_DEAD_BIT, &cred->pc_flags);
1537                 if (err != -ERESTART || gss_err != 0)
1538                         set_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags);
1539                 CERROR("cred %p: rpc err %d, gss err 0x%x, fatal %d\n",
1540                        cred, err, gss_err,
1541                        (test_bit(PTLRPC_CRED_ERROR_BIT, &cred->pc_flags) != 0));
1542         } else {
1543                 CDEBUG(D_SEC, "get initial ctx:\n");
1544                 gss_cred_set_ctx(cred, ctx);
1545         }
1546
1547         spin_lock(&gsec->gs_lock);
1548         gss_msg = gss_find_upcall(gsec, obdname, &gmd);
1549         if (gss_msg) {
1550                 gss_unhash_msg_nolock(gss_msg);
1551                 spin_unlock(&gsec->gs_lock);
1552                 gss_release_msg(gss_msg);
1553         } else
1554                 spin_unlock(&gsec->gs_lock);
1555
1556         ptlrpcs_cred_put(cred, 1);
1557         class_import_put(import);
1558         OBD_FREE(buf, bufsize);
1559         RETURN(mlen);
1560 err:
1561         if (ctx)
1562                 gss_destroy_ctx(ctx);
1563         class_import_put(import);
1564 err_free:
1565         OBD_FREE(buf, bufsize);
1566         CDEBUG(D_SEC, "gss_pipe_downcall returning %d\n", err);
1567         RETURN(err);
1568 }
1569
1570 static
1571 void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
1572 {
1573         struct gss_upcall_msg *gmsg;
1574         static unsigned long ratelimit;
1575         ENTRY;
1576
1577         if (msg->errno >= 0) {
1578                 EXIT;
1579                 return;
1580         }
1581
1582         gmsg = container_of(msg, struct gss_upcall_msg, gum_base);
1583         CDEBUG(D_SEC, "destroy gmsg %p\n", gmsg);
1584         atomic_inc(&gmsg->gum_refcount);
1585         gss_unhash_msg(gmsg);
1586         if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
1587                 unsigned long now = get_seconds();
1588                 if (time_after(now, ratelimit)) {
1589                         CWARN("GSS_SEC upcall timed out.\n"
1590                               "Please check user daemon is running!\n");
1591                         ratelimit = now + 15;
1592                 }
1593         }
1594         gss_release_msg(gmsg);
1595         EXIT;
1596 }
1597
1598 static
1599 void gss_pipe_release(struct inode *inode)
1600 {
1601         struct rpc_inode *rpci = RPC_I(inode);
1602         struct ptlrpc_sec *sec;
1603         struct gss_sec *gsec;
1604         ENTRY;
1605
1606         gsec = (struct gss_sec *)rpci->private;
1607         sec = &gsec->gs_base;
1608         spin_lock(&gsec->gs_lock);
1609         while (!list_empty(&gsec->gs_upcalls)) {
1610                 struct gss_upcall_msg *gmsg;
1611
1612                 gmsg = list_entry(gsec->gs_upcalls.next,
1613                                   struct gss_upcall_msg, gum_list);
1614                 gmsg->gum_base.errno = -EPIPE;
1615                 atomic_inc(&gmsg->gum_refcount);
1616                 gss_unhash_msg_nolock(gmsg);
1617                 gss_release_msg(gmsg);
1618         }
1619         spin_unlock(&gsec->gs_lock);
1620         EXIT;
1621 }
1622
1623 static struct rpc_pipe_ops gss_upcall_ops = {
1624         .upcall         = gss_pipe_upcall,
1625         .downcall       = gss_pipe_downcall,
1626         .destroy_msg    = gss_pipe_destroy_msg,
1627         .release_pipe   = gss_pipe_release,
1628 };
1629 #endif /* __KERNEL__ */
1630
1631 /*********************************************
1632  * GSS security APIs                         *
1633  *********************************************/
1634
1635 static
1636 struct ptlrpc_sec* gss_create_sec(ptlrpcs_flavor_t *flavor,
1637                                   const char *pipe_dir,
1638                                   void *pipe_data)
1639 {
1640         struct gss_sec *gsec;
1641         struct ptlrpc_sec *sec;
1642 #ifdef __KERNEL__
1643         char *pos;
1644         int   pipepath_len;
1645 #endif
1646         ENTRY;
1647
1648         LASSERT(flavor->flavor == PTLRPC_SEC_GSS);
1649
1650         OBD_ALLOC(gsec, sizeof(*gsec));
1651         if (!gsec) {
1652                 CERROR("can't alloc gsec\n");
1653                 RETURN(NULL);
1654         }
1655
1656         gsec->gs_mech = kgss_subflavor_to_mech(flavor->subflavor);
1657         if (!gsec->gs_mech) {
1658                 CERROR("subflavor %d not found\n", flavor->subflavor);
1659                 goto err_free;
1660         }
1661
1662         /* initialize gss sec */
1663 #ifdef __KERNEL__
1664         INIT_LIST_HEAD(&gsec->gs_upcalls);
1665         spin_lock_init(&gsec->gs_lock);
1666
1667         pipepath_len = strlen(LUSTRE_PIPEDIR) + strlen(pipe_dir) +
1668                        strlen(gsec->gs_mech->gm_name) + 3;
1669         OBD_ALLOC(gsec->gs_pipepath, pipepath_len);
1670         if (!gsec->gs_pipepath)
1671                 goto err_mech_put;
1672
1673         sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s", pipe_dir);
1674         if (IS_ERR(rpc_mkdir(gsec->gs_pipepath, NULL))) {
1675                 CERROR("can't make pipedir %s\n", gsec->gs_pipepath);
1676                 goto err_free_path;
1677         }
1678
1679         sprintf(gsec->gs_pipepath, LUSTRE_PIPEDIR"/%s/%s", pipe_dir,
1680                 gsec->gs_mech->gm_name); 
1681         gsec->gs_depipe = rpc_mkpipe(gsec->gs_pipepath, gsec,
1682                                      &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
1683         if (IS_ERR(gsec->gs_depipe)) {
1684                 CERROR("failed to make rpc_pipe %s: %ld\n",
1685                         gsec->gs_pipepath, PTR_ERR(gsec->gs_depipe));
1686                 goto err_rmdir;
1687         }
1688         CDEBUG(D_SEC, "gss sec %p, pipe path %s\n", gsec, gsec->gs_pipepath);
1689 #endif
1690
1691         sec = &gsec->gs_base;
1692
1693         switch (flavor->subflavor) {
1694         case PTLRPC_SEC_GSS_KRB5I:
1695                 sec->ps_sectype = PTLRPC_SEC_TYPE_AUTH;
1696                 break;
1697         case PTLRPC_SEC_GSS_KRB5P:
1698                 sec->ps_sectype = PTLRPC_SEC_TYPE_PRIV;
1699                 break;
1700         default:
1701                 LBUG();
1702         }
1703
1704         sec->ps_expire = GSS_CREDCACHE_EXPIRE;
1705         sec->ps_nextgc = get_seconds() + sec->ps_expire;
1706         sec->ps_flags = 0;
1707
1708         CDEBUG(D_SEC, "Create GSS security instance at %p(external %p)\n",
1709                gsec, sec);
1710         RETURN(sec);
1711
1712 #ifdef __KERNEL__
1713 err_rmdir:
1714         pos = strrchr(gsec->gs_pipepath, '/');
1715         LASSERT(pos);
1716         *pos = 0;
1717         rpc_rmdir(gsec->gs_pipepath);
1718 err_free_path:
1719         OBD_FREE(gsec->gs_pipepath, pipepath_len);
1720 err_mech_put:
1721 #endif
1722         kgss_mech_put(gsec->gs_mech);
1723 err_free:
1724         OBD_FREE(gsec, sizeof(*gsec));
1725         RETURN(NULL);
1726 }
1727
1728 static
1729 void gss_destroy_sec(struct ptlrpc_sec *sec)
1730 {
1731         struct gss_sec *gsec;
1732 #ifdef __KERNEL__
1733         char *pos;
1734         int   pipepath_len;
1735 #endif
1736         ENTRY;
1737
1738         gsec = container_of(sec, struct gss_sec, gs_base);
1739         CDEBUG(D_SEC, "Destroy GSS security instance at %p\n", gsec);
1740
1741         LASSERT(gsec->gs_mech);
1742         LASSERT(!atomic_read(&sec->ps_refcount));
1743         LASSERT(!atomic_read(&sec->ps_credcount));
1744 #ifdef __KERNEL__
1745         pipepath_len = strlen(gsec->gs_pipepath) + 1;
1746         rpc_unlink(gsec->gs_pipepath);
1747         pos = strrchr(gsec->gs_pipepath, '/');
1748         LASSERT(pos);
1749         *pos = 0;
1750         rpc_rmdir(gsec->gs_pipepath);
1751         OBD_FREE(gsec->gs_pipepath, pipepath_len);
1752 #endif
1753
1754         kgss_mech_put(gsec->gs_mech);
1755         OBD_FREE(gsec, sizeof(*gsec));
1756         EXIT;
1757 }
1758
1759 static
1760 struct ptlrpc_cred * gss_create_cred(struct ptlrpc_sec *sec,
1761                                      struct vfs_cred *vcred)
1762 {
1763         struct gss_cred *gcred;
1764         struct ptlrpc_cred *cred;
1765         ENTRY;
1766
1767         OBD_ALLOC(gcred, sizeof(*gcred));
1768         if (!gcred)
1769                 RETURN(NULL);
1770
1771         cred = &gcred->gc_base;
1772         INIT_LIST_HEAD(&cred->pc_hash);
1773         atomic_set(&cred->pc_refcount, 0);
1774         cred->pc_sec = sec;
1775         cred->pc_ops = &gss_credops;
1776         cred->pc_expire = 0;
1777         cred->pc_flags = 0;
1778         cred->pc_pag = vcred->vc_pag;
1779         cred->pc_uid = vcred->vc_uid;
1780         CDEBUG(D_SEC, "create a gss cred at %p("LPU64"/%u)\n",
1781                cred, vcred->vc_pag, vcred->vc_uid);
1782
1783         RETURN(cred);
1784 }
1785
1786 static int gss_estimate_payload(struct ptlrpc_sec *sec, int msgsize)
1787 {
1788         switch (sec->ps_sectype) {
1789         case PTLRPC_SEC_TYPE_AUTH:
1790                 return GSS_MAX_AUTH_PAYLOAD;
1791         case PTLRPC_SEC_TYPE_PRIV:
1792                 return size_round16(GSS_MAX_AUTH_PAYLOAD + msgsize +
1793                                     GSS_PRIVBUF_PREFIX_LEN +
1794                                     GSS_PRIVBUF_SUFFIX_LEN);
1795         default:
1796                 LBUG();
1797                 return 0;
1798         }
1799 }
1800
1801 static int gss_alloc_reqbuf(struct ptlrpc_sec *sec,
1802                             struct ptlrpc_request *req,
1803                             int lmsg_size)
1804 {
1805         int msg_payload, sec_payload;
1806         int privacy, rc;
1807         ENTRY;
1808
1809         /* In PRIVACY mode, lustre message is always 0 (already encoded into
1810          * security payload).
1811          */
1812         privacy = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV;
1813         msg_payload = privacy ? 0 : lmsg_size;
1814         sec_payload = gss_estimate_payload(sec, lmsg_size);
1815
1816         rc = sec_alloc_reqbuf(sec, req, msg_payload, sec_payload);
1817         if (rc)
1818                 return rc;
1819
1820         if (privacy) {
1821                 int buflen = lmsg_size + GSS_PRIVBUF_PREFIX_LEN +
1822                              GSS_PRIVBUF_SUFFIX_LEN;
1823                 char *buf;
1824
1825                 OBD_ALLOC(buf, buflen);
1826                 if (!buf) {
1827                         CERROR("Fail to alloc %d\n", buflen);
1828                         sec_free_reqbuf(sec, req);
1829                         RETURN(-ENOMEM);
1830                 }
1831                 req->rq_reqmsg = (struct lustre_msg *)
1832                                         (buf + GSS_PRIVBUF_PREFIX_LEN);
1833         }
1834
1835         RETURN(0);
1836 }
1837
1838 static void gss_free_reqbuf(struct ptlrpc_sec *sec,
1839                             struct ptlrpc_request *req)
1840 {
1841         char *buf;
1842         int privacy;
1843         ENTRY;
1844
1845         LASSERT(req->rq_reqmsg);
1846         LASSERT(req->rq_reqlen);
1847
1848         privacy = sec->ps_sectype == PTLRPC_SEC_TYPE_PRIV;
1849         if (privacy) {
1850                 buf = (char *) req->rq_reqmsg - GSS_PRIVBUF_PREFIX_LEN;
1851                 LASSERT(buf < req->rq_reqbuf ||
1852                         buf >= req->rq_reqbuf + req->rq_reqbuf_len);
1853                 OBD_FREE(buf, req->rq_reqlen + GSS_PRIVBUF_PREFIX_LEN +
1854                               GSS_PRIVBUF_SUFFIX_LEN);
1855                 req->rq_reqmsg = NULL;
1856         }
1857
1858         sec_free_reqbuf(sec, req);
1859 }
1860
1861 static struct ptlrpc_secops gss_secops = {
1862         .create_sec             = gss_create_sec,
1863         .destroy_sec            = gss_destroy_sec,
1864         .create_cred            = gss_create_cred,
1865         .est_req_payload        = gss_estimate_payload,
1866         .est_rep_payload        = gss_estimate_payload,
1867         .alloc_reqbuf           = gss_alloc_reqbuf,
1868         .free_reqbuf            = gss_free_reqbuf,
1869 };
1870
1871 static struct ptlrpc_sec_type gss_type = {
1872         .pst_owner      = THIS_MODULE,
1873         .pst_name       = "GSS_SEC",
1874         .pst_inst       = ATOMIC_INIT(0),
1875         .pst_flavor     = {PTLRPC_SEC_GSS, 0},
1876         .pst_ops        = &gss_secops,
1877 };
1878
1879 extern int
1880 (*lustre_secinit_downcall_handler)(char *buffer, unsigned long count);
1881
1882 int __init ptlrpcs_gss_init(void)
1883 {
1884         int rc;
1885
1886         rc = ptlrpcs_register(&gss_type);
1887         if (rc)
1888                 return rc;
1889
1890 #ifdef __KERNEL__
1891         gss_svc_init();
1892
1893         rc = PTR_ERR(rpc_mkdir(LUSTRE_PIPEDIR, NULL));
1894         if (IS_ERR((void *)rc) && rc != -EEXIST) {
1895                 CERROR("fail to make rpcpipedir for lustre\n");
1896                 gss_svc_exit();
1897                 ptlrpcs_unregister(&gss_type);
1898                 return -1;
1899         }
1900         rc = 0;
1901 #else
1902 #endif
1903         rc = init_kerberos_module();
1904         if (rc) {
1905                 ptlrpcs_unregister(&gss_type);
1906         }
1907
1908         lustre_secinit_downcall_handler = gss_send_secinit_rpc;
1909
1910         return rc;
1911 }
1912
1913 #ifdef __KERNEL__
1914 static void __exit ptlrpcs_gss_exit(void)
1915 {
1916         lustre_secinit_downcall_handler = NULL;
1917
1918         cleanup_kerberos_module();
1919         rpc_rmdir(LUSTRE_PIPEDIR);
1920         gss_svc_exit();
1921         ptlrpcs_unregister(&gss_type);
1922 }
1923 #endif
1924
1925 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
1926 MODULE_DESCRIPTION("GSS Security module for Lustre");
1927 MODULE_LICENSE("GPL");
1928
1929 module_init(ptlrpcs_gss_init);
1930 module_exit(ptlrpcs_gss_exit);