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