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