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