Whamcloud - gitweb
- make HEAD from b_post_cmd3
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_cli_upcall.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2006 Cluster File Systems, Inc.
5  *
6  *   This file is part of the Lustre file system, http://www.lustre.org
7  *   Lustre is a trademark of Cluster File Systems, Inc.
8  *
9  *   You may have signed or agreed to another license before downloading
10  *   this software.  If so, you are bound by the terms and conditions
11  *   of that agreement, and the following does not apply to you.  See the
12  *   LICENSE file included with this distribution for more information.
13  *
14  *   If you did not agree to a different license, then this copy of Lustre
15  *   is open source software; you can redistribute it and/or modify it
16  *   under the terms of version 2 of the GNU General Public License as
17  *   published by the Free Software Foundation.
18  *
19  *   In either case, Lustre is distributed in the hope that it will be
20  *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty
21  *   of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *   license text for more details.
23  *
24  */
25
26 #ifndef EXPORT_SYMTAB
27 # define EXPORT_SYMTAB
28 #endif
29 #define DEBUG_SUBSYSTEM S_SEC
30 #ifdef __KERNEL__
31 #include <linux/init.h>
32 #include <linux/module.h>
33 #include <linux/slab.h>
34 #include <linux/dcache.h>
35 #include <linux/fs.h>
36 #include <linux/random.h>
37 /* for rpc_pipefs */
38 struct rpc_clnt;
39 #include <linux/sunrpc/rpc_pipe_fs.h>
40 #else
41 #include <liblustre.h>
42 #endif
43
44 #include <obd.h>
45 #include <obd_class.h>
46 #include <obd_support.h>
47 #include <lustre/lustre_idl.h>
48 #include <lustre_net.h>
49 #include <lustre_import.h>
50 #include <lustre_sec.h>
51
52 #include "gss_err.h"
53 #include "gss_internal.h"
54 #include "gss_api.h"
55
56 #define LUSTRE_PIPE_ROOT        "/lustre"
57 #define LUSTRE_PIPE_KRB5        LUSTRE_PIPE_ROOT"/krb5"
58
59 struct gss_upcall_msg_data {
60         __u32                           gum_seq;
61         __u32                           gum_uid;
62         __u32                           gum_gid;
63         __u32                           gum_svc;        /* MDS/OSS... */
64         __u64                           gum_nid;        /* peer NID */
65         __u8                            gum_obd[64];    /* client obd name */
66 };
67
68 struct gss_upcall_msg {
69         struct rpc_pipe_msg             gum_base;
70         atomic_t                        gum_refcount;
71         struct list_head                gum_list;
72         __u32                           gum_mechidx;
73         struct gss_sec                 *gum_gsec;
74         struct gss_cli_ctx             *gum_gctx;
75         struct gss_upcall_msg_data      gum_data;
76 };
77
78 static atomic_t upcall_seq = ATOMIC_INIT(0);
79
80 static inline
81 __u32 upcall_get_sequence(void)
82 {
83         return (__u32) atomic_inc_return(&upcall_seq);
84 }
85
86 enum mech_idx_t {
87         MECH_KRB5   = 0,
88         MECH_MAX
89 };
90
91 static inline
92 __u32 mech_name2idx(const char *name)
93 {
94         LASSERT(!strcmp(name, "krb5"));
95         return MECH_KRB5;
96 }
97
98 /* pipefs dentries for each mechanisms */
99 static struct dentry *de_pipes[MECH_MAX] = { NULL, };
100 /* all upcall messgaes linked here */
101 static struct list_head upcall_lists[MECH_MAX];
102 /* and protected by this */
103 static spinlock_t upcall_locks[MECH_MAX];
104
105 static inline
106 void upcall_list_lock(int idx)
107 {
108         spin_lock(&upcall_locks[idx]);
109 }
110
111 static inline
112 void upcall_list_unlock(int idx)
113 {
114         spin_unlock(&upcall_locks[idx]);
115 }
116
117 static
118 void upcall_msg_enlist(struct gss_upcall_msg *msg)
119 {
120         __u32 idx = msg->gum_mechidx;
121
122         upcall_list_lock(idx);
123         list_add(&msg->gum_list, &upcall_lists[idx]);
124         upcall_list_unlock(idx);
125 }
126
127 static
128 void upcall_msg_delist(struct gss_upcall_msg *msg)
129 {
130         __u32 idx = msg->gum_mechidx;
131
132         upcall_list_lock(idx);
133         list_del_init(&msg->gum_list);
134         upcall_list_unlock(idx);
135 }
136
137 /**********************************************
138  * rpc_pipe upcall helpers                    *
139  **********************************************/
140 static
141 void gss_release_msg(struct gss_upcall_msg *gmsg)
142 {
143         ENTRY;
144         LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
145
146         if (!atomic_dec_and_test(&gmsg->gum_refcount)) {
147                 EXIT;
148                 return;
149         }
150
151         if (gmsg->gum_gctx) {
152                 sptlrpc_ctx_wakeup(&gmsg->gum_gctx->gc_base);
153                 sptlrpc_ctx_put(&gmsg->gum_gctx->gc_base, 1);
154                 gmsg->gum_gctx = NULL;
155         }
156
157         LASSERT(list_empty(&gmsg->gum_list));
158         LASSERT(list_empty(&gmsg->gum_base.list));
159         OBD_FREE_PTR(gmsg);
160         EXIT;
161 }
162
163 static
164 void gss_unhash_msg_nolock(struct gss_upcall_msg *gmsg)
165 {
166         __u32 idx = gmsg->gum_mechidx;
167
168         LASSERT(idx < MECH_MAX);
169         LASSERT_SPIN_LOCKED(&upcall_locks[idx]);
170
171         if (list_empty(&gmsg->gum_list))
172                 return;
173
174         list_del_init(&gmsg->gum_list);
175         LASSERT(atomic_read(&gmsg->gum_refcount) > 1);
176         atomic_dec(&gmsg->gum_refcount);
177 }
178
179 static
180 void gss_unhash_msg(struct gss_upcall_msg *gmsg)
181 {
182         __u32 idx = gmsg->gum_mechidx;
183
184         LASSERT(idx < MECH_MAX);
185         upcall_list_lock(idx);
186         gss_unhash_msg_nolock(gmsg);
187         upcall_list_unlock(idx);
188 }
189
190 static
191 void gss_msg_fail_ctx(struct gss_upcall_msg *gmsg)
192 {
193         if (gmsg->gum_gctx) {
194                 struct ptlrpc_cli_ctx *ctx = &gmsg->gum_gctx->gc_base;
195
196                 LASSERT(atomic_read(&ctx->cc_refcount) > 0);
197                 sptlrpc_ctx_expire(ctx);
198                 set_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags);
199         }
200 }
201
202 static
203 struct gss_upcall_msg * gss_find_upcall(__u32 mechidx, __u32 seq)
204 {
205         struct gss_upcall_msg *gmsg;
206
207         upcall_list_lock(mechidx);
208         list_for_each_entry(gmsg, &upcall_lists[mechidx], gum_list) {
209                 if (gmsg->gum_data.gum_seq != seq)
210                         continue;
211
212                 LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
213                 LASSERT(gmsg->gum_mechidx == mechidx);
214
215                 atomic_inc(&gmsg->gum_refcount);
216                 upcall_list_unlock(mechidx);
217                 return gmsg;
218         }
219         upcall_list_unlock(mechidx);
220         return NULL;
221 }
222
223 static
224 int simple_get_bytes(char **buf, __u32 *buflen, void *res, __u32 reslen)
225 {
226         if (*buflen < reslen) {
227                 CERROR("buflen %u < %u\n", *buflen, reslen);
228                 return -EINVAL;
229         }
230
231         memcpy(res, *buf, reslen);
232         *buf += reslen;
233         *buflen -= reslen;
234         return 0;
235 }
236
237 /*******************************************
238  * rpc_pipe APIs                           *
239  *******************************************/
240 static
241 ssize_t gss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
242                         char *dst, size_t buflen)
243 {
244         char *data = (char *)msg->data + msg->copied;
245         ssize_t mlen = msg->len;
246         ssize_t left;
247         ENTRY;
248
249         if (mlen > buflen)
250                 mlen = buflen;
251         left = copy_to_user(dst, data, mlen);
252         if (left < 0) {
253                 msg->errno = left;
254                 RETURN(left);
255         }
256         mlen -= left;
257         msg->copied += mlen;
258         msg->errno = 0;
259         RETURN(mlen);
260 }
261
262 static
263 ssize_t gss_pipe_downcall(struct file *filp, const char *src, size_t mlen)
264 {
265         struct rpc_inode        *rpci = RPC_I(filp->f_dentry->d_inode);
266         struct gss_upcall_msg   *gss_msg;
267         struct ptlrpc_cli_ctx   *ctx;
268         struct gss_cli_ctx      *gctx = NULL;
269         char                    *buf, *data;
270         int                      datalen;
271         int                      timeout, rc;
272         __u32                    mechidx, seq, gss_err;
273         ENTRY;
274
275         mechidx = (__u32) (long) rpci->private;
276         LASSERT(mechidx < MECH_MAX);
277
278         OBD_ALLOC(buf, mlen);
279         if (!buf)
280                 RETURN(-ENOMEM);
281
282         if (copy_from_user(buf, src, mlen)) {
283                 CERROR("failed copy user space data\n");
284                 GOTO(out_free, rc = -EFAULT);
285         }
286         data = buf;
287         datalen = mlen;
288
289         /* data passed down format:
290          *  - seq
291          *  - timeout
292          *  - gc_win / error
293          *  - wire_ctx (rawobj)
294          *  - mech_ctx (rawobj)
295          */
296         if (simple_get_bytes(&data, &datalen, &seq, sizeof(seq))) {
297                 CERROR("fail to get seq\n");
298                 GOTO(out_free, rc = -EFAULT);
299         }
300
301         gss_msg = gss_find_upcall(mechidx, seq);
302         if (!gss_msg) {
303                 CERROR("upcall %u has aborted earlier\n", seq);
304                 GOTO(out_free, rc = -EINVAL);
305         }
306
307         gss_unhash_msg(gss_msg);
308         gctx = gss_msg->gum_gctx;
309         LASSERT(gctx);
310         LASSERT(atomic_read(&gctx->gc_base.cc_refcount) > 0);
311
312         /* timeout is not in use for now */
313         if (simple_get_bytes(&data, &datalen, &timeout, sizeof(timeout)))
314                 GOTO(out_msg, rc = -EFAULT);
315
316         /* lgssd signal an error by gc_win == 0 */
317         if (simple_get_bytes(&data, &datalen, &gctx->gc_win,
318                              sizeof(gctx->gc_win)))
319                 GOTO(out_msg, rc = -EFAULT);
320
321         if (gctx->gc_win == 0) {
322                 /* followed by:
323                  * - rpc error
324                  * - gss error
325                  */
326                 if (simple_get_bytes(&data, &datalen, &rc, sizeof(rc)))
327                         GOTO(out_msg, rc = -EFAULT);
328                 if (simple_get_bytes(&data, &datalen, &gss_err,sizeof(gss_err)))
329                         GOTO(out_msg, rc = -EFAULT);
330
331                 if (rc == 0 && gss_err == GSS_S_COMPLETE) {
332                         CWARN("both rpc & gss error code not set\n");
333                         rc = -EPERM;
334                 }
335         } else {
336                 rawobj_t tmpobj;
337
338                 /* handle */
339                 if (rawobj_extract_local(&tmpobj, (__u32 **) &data, &datalen))
340                         GOTO(out_msg, rc = -EFAULT);
341                 if (rawobj_dup(&gctx->gc_handle, &tmpobj))
342                         GOTO(out_msg, rc = -ENOMEM);
343
344                 /* mechctx */
345                 if (rawobj_extract_local(&tmpobj, (__u32 **) &data, &datalen))
346                         GOTO(out_msg, rc = -EFAULT);
347                 gss_err = lgss_import_sec_context(&tmpobj,
348                                                   gss_msg->gum_gsec->gs_mech,
349                                                   &gctx->gc_mechctx);
350                 rc = 0;
351         }
352
353         if (likely(rc == 0 && gss_err == GSS_S_COMPLETE)) {
354                 gss_cli_ctx_uptodate(gctx);
355         } else {
356                 ctx = &gctx->gc_base;
357                 sptlrpc_ctx_expire(ctx);
358                 if (rc != -ERESTART || gss_err != GSS_S_COMPLETE)
359                         set_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags);
360
361                 CERROR("refresh ctx %p(uid %d) failed: %d/0x%08x: %s\n",
362                        ctx, ctx->cc_vcred.vc_uid, rc, gss_err,
363                        test_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags) ?
364                        "fatal error" : "non-fatal");
365         }
366
367         rc = mlen;
368
369 out_msg:
370         gss_release_msg(gss_msg);
371
372 out_free:
373         OBD_FREE(buf, mlen);
374         /* FIXME
375          * hack pipefs: always return asked length unless all following
376          * downcalls might be messed up.
377          */
378         rc = mlen;
379         RETURN(rc);
380 }
381
382 static
383 void gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
384 {
385         struct gss_upcall_msg          *gmsg;
386         struct gss_upcall_msg_data     *gumd;
387         static cfs_time_t               ratelimit = 0;
388         ENTRY;
389
390         LASSERT(list_empty(&msg->list));
391
392         /* normally errno is >= 0 */
393         if (msg->errno >= 0) {
394                 EXIT;
395                 return;
396         }
397
398         gmsg = container_of(msg, struct gss_upcall_msg, gum_base);
399         gumd = &gmsg->gum_data;
400         LASSERT(atomic_read(&gmsg->gum_refcount) > 0);
401
402         CERROR("failed msg %p (seq %u, uid %u, svc %u, nid "LPX64", obd %.*s): "
403                "errno %d\n", msg, gumd->gum_seq, gumd->gum_uid, gumd->gum_svc,
404                gumd->gum_nid, (int) sizeof(gumd->gum_obd),
405                gumd->gum_obd, msg->errno);
406
407         atomic_inc(&gmsg->gum_refcount);
408         gss_unhash_msg(gmsg);
409         if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
410                 cfs_time_t now = cfs_time_current_sec();
411
412                 if (cfs_time_after(now, ratelimit)) {
413                         CWARN("upcall timed out, is lgssd running?\n");
414                         ratelimit = now + 15;
415                 }
416         }
417         gss_msg_fail_ctx(gmsg);
418         gss_release_msg(gmsg);
419         EXIT;
420 }
421
422 static
423 void gss_pipe_release(struct inode *inode)
424 {
425         struct rpc_inode *rpci = RPC_I(inode);
426         __u32             idx;
427         ENTRY;
428
429         idx = (__u32) (long) rpci->private;
430         LASSERT(idx < MECH_MAX);
431
432         upcall_list_lock(idx);
433         while (!list_empty(&upcall_lists[idx])) {
434                 struct gss_upcall_msg      *gmsg;
435                 struct gss_upcall_msg_data *gumd;
436
437                 gmsg = list_entry(upcall_lists[idx].next,
438                                   struct gss_upcall_msg, gum_list);
439                 gumd = &gmsg->gum_data;
440                 LASSERT(list_empty(&gmsg->gum_base.list));
441
442                 CERROR("failing remaining msg %p:seq %u, uid %u, svc %u, "
443                        "nid "LPX64", obd %.*s\n", gmsg,
444                        gumd->gum_seq, gumd->gum_uid, gumd->gum_svc,
445                        gumd->gum_nid, (int) sizeof(gumd->gum_obd),
446                        gumd->gum_obd);
447
448                 gmsg->gum_base.errno = -EPIPE;
449                 atomic_inc(&gmsg->gum_refcount);
450                 gss_unhash_msg_nolock(gmsg);
451
452                 gss_msg_fail_ctx(gmsg);
453
454                 upcall_list_unlock(idx);
455                 gss_release_msg(gmsg);
456                 upcall_list_lock(idx);
457         }
458         upcall_list_unlock(idx);
459         EXIT;
460 }
461
462 static struct rpc_pipe_ops gss_upcall_ops = {
463         .upcall         = gss_pipe_upcall,
464         .downcall       = gss_pipe_downcall,
465         .destroy_msg    = gss_pipe_destroy_msg,
466         .release_pipe   = gss_pipe_release,
467 };
468
469
470 /*******************************************
471  * upcall helper functions                 *
472  *******************************************/
473
474 static inline
475 __u32 import_to_gss_svc(struct obd_import *imp)
476 {
477         const char *name = imp->imp_obd->obd_type->typ_name;
478         if (!strcmp(name, LUSTRE_MDC_NAME))
479                 return LUSTRE_GSS_TGT_MDS;
480         if (!strcmp(name, LUSTRE_OSC_NAME))
481                 return LUSTRE_GSS_TGT_OSS;
482         LBUG();
483         return 0;
484 }
485
486 int gss_ctx_refresh_pipefs(struct ptlrpc_cli_ctx *ctx)
487 {
488         struct obd_import          *imp;
489         struct gss_sec             *gsec;
490         struct gss_upcall_msg      *gmsg;
491         int                         rc = 0;
492         ENTRY;
493
494         might_sleep();
495
496         LASSERT(ctx->cc_sec);
497         LASSERT(ctx->cc_sec->ps_import);
498         LASSERT(ctx->cc_sec->ps_import->imp_obd);
499
500         imp = ctx->cc_sec->ps_import;
501         if (!imp->imp_connection) {
502                 CERROR("import has no connection set\n");
503                 RETURN(-EINVAL);
504         }
505
506         gsec = container_of(ctx->cc_sec, struct gss_sec, gs_base);
507
508         OBD_ALLOC_PTR(gmsg);
509         if (!gmsg)
510                 RETURN(-ENOMEM);
511
512         /* initialize pipefs base msg */
513         INIT_LIST_HEAD(&gmsg->gum_base.list);
514         gmsg->gum_base.data = &gmsg->gum_data;
515         gmsg->gum_base.len = sizeof(gmsg->gum_data);
516         gmsg->gum_base.copied = 0;
517         gmsg->gum_base.errno = 0;
518
519         /* init upcall msg */
520         atomic_set(&gmsg->gum_refcount, 1);
521         gmsg->gum_mechidx = mech_name2idx(gsec->gs_mech->gm_name);
522         gmsg->gum_gsec = gsec;
523         gmsg->gum_gctx = container_of(sptlrpc_ctx_get(ctx),
524                                       struct gss_cli_ctx, gc_base);
525         gmsg->gum_data.gum_seq = upcall_get_sequence();
526         gmsg->gum_data.gum_uid = ctx->cc_vcred.vc_uid;
527         gmsg->gum_data.gum_gid = 0; /* not used for now */
528         gmsg->gum_data.gum_svc = import_to_gss_svc(imp);
529         gmsg->gum_data.gum_nid = imp->imp_connection->c_peer.nid;
530         strncpy(gmsg->gum_data.gum_obd, imp->imp_obd->obd_name,
531                 sizeof(gmsg->gum_data.gum_obd));
532
533         /* This only could happen when sysadmin set it dead/expired
534          * using lctl by force.
535          */
536         smp_mb();
537         if (ctx->cc_flags & PTLRPC_CTX_STATUS_MASK) {
538                 CWARN("ctx %p(%u->%s) was set flags %lx unexpectedly\n",
539                       ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec),
540                       ctx->cc_flags);
541
542                 LASSERT(!(ctx->cc_flags & PTLRPC_CTX_UPTODATE));
543                 ctx->cc_flags |= PTLRPC_CTX_DEAD | PTLRPC_CTX_ERROR;
544
545                 rc = -EIO;
546                 goto err_free;
547         }
548
549         upcall_msg_enlist(gmsg);
550
551         rc = rpc_queue_upcall(de_pipes[gmsg->gum_mechidx]->d_inode,
552                               &gmsg->gum_base);
553         if (rc) {
554                 CERROR("rpc_queue_upcall failed: %d\n", rc);
555
556                 upcall_msg_delist(gmsg);
557                 goto err_free;
558         }
559
560         RETURN(0);
561 err_free:
562         OBD_FREE_PTR(gmsg);
563         RETURN(rc);
564 }
565
566 int gss_sec_upcall_init(struct gss_sec *gsec)
567 {
568         return 0;
569 }
570
571 void gss_sec_upcall_cleanup(struct gss_sec *gsec)
572 {
573 }
574
575 int gss_init_pipefs(void)
576 {
577         struct dentry   *de;
578
579         /* pipe dir */
580         de = rpc_mkdir(LUSTRE_PIPE_ROOT, NULL);
581         if (IS_ERR(de) && PTR_ERR(de) != -EEXIST) {
582                 CERROR("Failed to create gss pipe dir: %ld\n", PTR_ERR(de));
583                 return PTR_ERR(de);
584         }
585         /* FIXME
586          * hack pipefs: dput will sometimes cause oops during module unload
587          * and lgssd close the pipe fds.
588          */
589         //dput(de);
590
591         /* krb5 mechanism */
592         de = rpc_mkpipe(LUSTRE_PIPE_KRB5, (void *) MECH_KRB5, &gss_upcall_ops,
593                         RPC_PIPE_WAIT_FOR_OPEN);
594         if (!de || IS_ERR(de)) {
595                 CERROR("failed to make rpc_pipe %s: %ld\n",
596                        LUSTRE_PIPE_KRB5, PTR_ERR(de));
597                 rpc_rmdir(LUSTRE_PIPE_ROOT);
598                 return PTR_ERR(de);
599         }
600
601         de_pipes[MECH_KRB5] = de;
602         INIT_LIST_HEAD(&upcall_lists[MECH_KRB5]);
603         upcall_locks[MECH_KRB5] = SPIN_LOCK_UNLOCKED;
604
605         return 0;
606 }
607
608 void gss_cleanup_pipefs(void)
609 {
610         __u32   i;
611
612         for (i = 0; i < MECH_MAX; i++) {
613                 LASSERT(list_empty(&upcall_lists[i]));
614                 /* FIXME
615                  * hack pipefs, dput pipe dentry here might cause lgssd oops.
616                  */
617                 //dput(de_pipes[i]);
618                 de_pipes[i] = NULL;
619         }
620
621         rpc_unlink(LUSTRE_PIPE_KRB5);
622         rpc_rmdir(LUSTRE_PIPE_ROOT);
623 }
624
625 /**********************************************
626  * gss context init/fini helper               *
627  **********************************************/
628
629 static
630 int ctx_init_pack_request(struct obd_import *imp,
631                           struct ptlrpc_request *req,
632                           int lustre_srv,
633                           uid_t uid, gid_t gid,
634                           long token_size,
635                           char __user *token)
636 {
637         struct lustre_msg       *msg = req->rq_reqbuf;
638         struct gss_sec          *gsec;
639         struct gss_header       *ghdr;
640         struct ptlrpc_user_desc *pud;
641         __u32                   *p, size, offset = 2;
642         rawobj_t                 obj;
643
644         LASSERT(msg->lm_bufcount <= 4);
645
646         /* gss hdr */
647         ghdr = lustre_msg_buf(msg, 0, sizeof(*ghdr));
648         ghdr->gh_version = PTLRPC_GSS_VERSION;
649         ghdr->gh_flags = 0;
650         ghdr->gh_proc = PTLRPC_GSS_PROC_INIT;
651         ghdr->gh_seq = 0;
652         ghdr->gh_svc = PTLRPC_GSS_SVC_NONE;
653         ghdr->gh_handle.len = 0;
654
655         /* fix the user desc */
656         if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
657                 pud = lustre_msg_buf(msg, offset, sizeof(*pud));
658                 LASSERT(pud);
659                 pud->pud_uid = pud->pud_fsuid = uid;
660                 pud->pud_gid = pud->pud_fsgid = gid;
661                 pud->pud_cap = 0;
662                 pud->pud_ngroups = 0;
663                 offset++;
664         }
665
666         /* security payload */
667         p = lustre_msg_buf(msg, offset, 0);
668         size = msg->lm_buflens[offset];
669
670         /* 1. lustre svc type */
671         LASSERT(size > 4);
672         *p++ = cpu_to_le32(lustre_srv);
673         size -= 4;
674
675         /* 2. target uuid */
676         obj.len = strlen(imp->imp_obd->u.cli.cl_target_uuid.uuid) + 1;
677         obj.data = imp->imp_obd->u.cli.cl_target_uuid.uuid;
678         if (rawobj_serialize(&obj, &p, &size))
679                 LBUG();
680
681         /* 3. reverse context handle. actually only needed by root user,
682          *    but we send it anyway.
683          */
684         gsec = container_of(imp->imp_sec, struct gss_sec, gs_base);
685         obj.len = sizeof(gsec->gs_rvs_hdl);
686         obj.data = (__u8 *) &gsec->gs_rvs_hdl;
687         if (rawobj_serialize(&obj, &p, &size))
688                 LBUG();
689
690         /* 4. now the token */
691         LASSERT(size >= (sizeof(__u32) + token_size));
692         *p++ = cpu_to_le32(((__u32) token_size));
693         if (copy_from_user(p, token, token_size)) {
694                 CERROR("can't copy token\n");
695                 return -EFAULT;
696         }
697         size -= sizeof(__u32) + size_round4(token_size);
698
699         req->rq_reqdata_len = lustre_shrink_msg(req->rq_reqbuf, offset,
700                                                 msg->lm_buflens[offset] - size, 0);
701         return 0;
702 }
703
704 static
705 int ctx_init_parse_reply(struct lustre_msg *msg,
706                          char __user *outbuf, long outlen)
707 {
708         struct gss_rep_header   *ghdr;
709         __u32                    obj_len, round_len;
710         __u32                    status, effective = 0;
711
712         if (msg->lm_bufcount != 3) {
713                 CERROR("unexpected bufcount %u\n", msg->lm_bufcount);
714                 return -EPROTO;
715         }
716
717         ghdr = (struct gss_rep_header *) gss_swab_header(msg, 0);
718         if (ghdr == NULL) {
719                 CERROR("unable to extract gss reply header\n");
720                 return -EPROTO;
721         }
722
723         if (ghdr->gh_version != PTLRPC_GSS_VERSION) {
724                 CERROR("invalid gss version %u\n", ghdr->gh_version);
725                 return -EPROTO;
726         }
727
728         if (outlen < (4 + 2) * 4 + size_round4(ghdr->gh_handle.len) +
729                      size_round4(msg->lm_buflens[2])) {
730                 CERROR("output buffer size %ld too small\n", outlen);
731                 return -EFAULT;
732         }
733
734         status = 0;
735         effective = 0;
736
737         if (copy_to_user(outbuf, &status, 4))
738                 return -EFAULT;
739         outbuf += 4;
740         if (copy_to_user(outbuf, &ghdr->gh_major, 4))
741                 return -EFAULT;
742         outbuf += 4;
743         if (copy_to_user(outbuf, &ghdr->gh_minor, 4))
744                 return -EFAULT;
745         outbuf += 4;
746         if (copy_to_user(outbuf, &ghdr->gh_seqwin, 4))
747                 return -EFAULT;
748         outbuf += 4;
749         effective += 4 * 4;
750
751         /* handle */
752         obj_len = ghdr->gh_handle.len;
753         round_len = (obj_len + 3) & ~ 3;
754         if (copy_to_user(outbuf, &obj_len, 4))
755                 return -EFAULT;
756         outbuf += 4;
757         if (copy_to_user(outbuf, (char *) ghdr->gh_handle.data, round_len))
758                 return -EFAULT;
759         outbuf += round_len;
760         effective += 4 + round_len;
761
762         /* out token */
763         obj_len = msg->lm_buflens[2];
764         round_len = (obj_len + 3) & ~ 3;
765         if (copy_to_user(outbuf, &obj_len, 4))
766                 return -EFAULT;
767         outbuf += 4;
768         if (copy_to_user(outbuf, lustre_msg_buf(msg, 2, 0), round_len))
769                 return -EFAULT;
770         outbuf += round_len;
771         effective += 4 + round_len;
772
773         return effective;
774 }
775
776 /* XXX move to where lgssd could see */
777 struct lgssd_ioctl_param {
778         int             version;        /* in   */
779         char           *uuid;           /* in   */
780         int             lustre_svc;     /* in   */
781         uid_t           uid;            /* in   */
782         gid_t           gid;            /* in   */
783         long            send_token_size;/* in   */
784         char           *send_token;     /* in   */
785         long            reply_buf_size; /* in   */
786         char           *reply_buf;      /* in   */
787         long            status;         /* out  */
788         long            reply_length;   /* out  */
789 };
790
791 int gss_do_ctx_init_rpc(__user char *buffer, unsigned long count)
792 {
793         struct obd_import        *imp;
794         struct ptlrpc_request    *req;
795         struct lgssd_ioctl_param  param;
796         struct obd_device        *obd;
797         char                      obdname[64];
798         long                      lsize;
799         int                       lmsg_size = sizeof(struct ptlrpc_body);
800         int                       rc;
801
802         if (count != sizeof(param)) {
803                 CERROR("ioctl size %lu, expect %lu, please check lgssd version\n",
804                         count, (unsigned long) sizeof(param));
805                 RETURN(-EINVAL);
806         }
807         if (copy_from_user(&param, buffer, sizeof(param))) {
808                 CERROR("failed copy data from lgssd\n");
809                 RETURN(-EFAULT);
810         }
811
812         if (param.version != GSSD_INTERFACE_VERSION) {
813                 CERROR("gssd interface version %d (expect %d)\n",
814                         param.version, GSSD_INTERFACE_VERSION);
815                 RETURN(-EINVAL);
816         }
817
818         /* take name */
819         if (strncpy_from_user(obdname, param.uuid, sizeof(obdname)) <= 0) {
820                 CERROR("Invalid obdname pointer\n");
821                 RETURN(-EFAULT);
822         }
823
824         obd = class_name2obd(obdname);
825         if (!obd) {
826                 CERROR("no such obd %s\n", obdname);
827                 RETURN(-EINVAL);
828         }
829
830         imp = class_import_get(obd->u.cli.cl_import);
831         LASSERT(imp->imp_sec);
832
833         /* force this import to use v2 msg */
834         imp->imp_msg_magic = LUSTRE_MSG_MAGIC_V2;
835
836         req = ptlrpc_prep_req(imp, LUSTRE_OBD_VERSION, SEC_CTX_INIT,
837                               1, &lmsg_size, NULL);
838         if (!req) {
839                 param.status = -ENOMEM;
840                 goto out_copy;
841         }
842
843         /* get token */
844         rc = ctx_init_pack_request(imp, req,
845                                    param.lustre_svc,
846                                    param.uid, param.gid,
847                                    param.send_token_size,
848                                    param.send_token);
849         if (rc) {
850                 param.status = rc;
851                 goto out_copy;
852         }
853
854         req->rq_replen = lustre_msg_size_v2(1, &lmsg_size);
855
856         rc = ptlrpc_queue_wait(req);
857         if (rc) {
858                 /* If any _real_ denial be made, we expect server return
859                  * -EACCES reply or return success but indicate gss error
860                  * inside reply messsage. All other errors are treated as
861                  * timeout, caller might try the negotiation repeatedly,
862                  * leave recovery decisions to general ptlrpc layer.
863                  *
864                  * FIXME maybe some other error code shouldn't be treated
865                  * as timeout.
866                  */
867                 param.status = rc;
868                 if (rc != -EACCES)
869                         param.status = -ETIMEDOUT;
870                 goto out_copy;
871         }
872
873         lsize = ctx_init_parse_reply(req->rq_repbuf,
874                                      param.reply_buf, param.reply_buf_size);
875         if (lsize < 0) {
876                 param.status = (int) lsize;
877                 goto out_copy;
878         }
879
880         param.status = 0;
881         param.reply_length = lsize;
882
883 out_copy:
884         if (copy_to_user(buffer, &param, sizeof(param)))
885                 rc = -EFAULT;
886         else
887                 rc = 0;
888
889         class_import_put(imp);
890         ptlrpc_req_finished(req);
891         RETURN(rc);
892 }
893
894 int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
895 {
896         struct ptlrpc_cli_ctx   *ctx = &gctx->gc_base;
897         struct obd_import       *imp = ctx->cc_sec->ps_import;
898         struct ptlrpc_request   *req;
899         struct ptlrpc_user_desc *pud;
900         int                      buflens = sizeof(struct ptlrpc_body);
901         int                      rc;
902         ENTRY;
903
904         if (ctx->cc_sec->ps_flags & PTLRPC_SEC_FL_REVERSE) {
905                 CWARN("ctx %p(%u) is reverse, don't send destroy rpc\n",
906                       ctx, ctx->cc_vcred.vc_uid);
907                 RETURN(0);
908         }
909
910         if (test_bit(PTLRPC_CTX_ERROR_BIT, &ctx->cc_flags) ||
911             !test_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags)) {
912                 CWARN("ctx %p(%u->%s) already dead, don't send destroy rpc\n",
913                       ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
914                 RETURN(0);
915         }
916
917         might_sleep();
918
919         CWARN("client destroy ctx %p(%u->%s)\n",
920               ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
921
922         /* context's refcount could be 0, steal one */
923         atomic_inc(&ctx->cc_refcount);
924
925         gctx->gc_proc = PTLRPC_GSS_PROC_DESTROY;
926
927         req = ptlrpc_prep_req_pool(imp, LUSTRE_OBD_VERSION, SEC_CTX_FINI,
928                                    1, &buflens, NULL, NULL, ctx);
929         if (!req) {
930                 CWARN("ctx %p(%u): fail to prepare rpc, destroy locally\n",
931                       ctx, ctx->cc_vcred.vc_uid);
932                 GOTO(out_ref, rc = -ENOMEM);
933         }
934
935         /* fix the user desc */
936         if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
937                 /* we rely the fact that this request is in AUTH mode,
938                  * and user_desc at offset 2.
939                  */
940                 pud = lustre_msg_buf(req->rq_reqbuf, 2, sizeof(*pud));
941                 LASSERT(pud);
942                 pud->pud_uid = pud->pud_fsuid = ctx->cc_vcred.vc_uid;
943                 pud->pud_gid = pud->pud_fsgid = ctx->cc_vcred.vc_gid;
944                 pud->pud_cap = 0;
945                 pud->pud_ngroups = 0;
946         }
947
948         req->rq_replen = lustre_msg_size_v2(1, &buflens);
949
950         rc = ptlrpc_queue_wait(req);
951         if (rc) {
952                 CWARN("ctx %p(%u): rpc error %d, destroy locally\n",
953                       ctx, ctx->cc_vcred.vc_uid, rc);
954         }
955
956         ptlrpc_req_finished(req);
957 out_ref:
958         atomic_dec(&ctx->cc_refcount);
959         RETURN(rc);
960 }
961
962 int __init gss_init_upcall(void)
963 {
964         int     rc;
965
966         rc = gss_svc_init_upcall();
967         if (rc)
968                 return rc;
969
970         rc = gss_init_pipefs();
971         if (rc)
972                 gss_svc_exit_upcall();
973
974         return rc;
975 }
976
977 void __exit gss_exit_upcall(void)
978 {
979         gss_svc_exit_upcall();
980         gss_cleanup_pipefs();
981 }