Whamcloud - gitweb
LU-6068 misc: update Intel copyright messages 2014
[fs/lustre-release.git] / lustre / utils / gss / lgss_keyring.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2014, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/gss/lgss_keyring.c
37  *
38  * user-space upcall to create GSS context, using keyring interface to kernel
39  *
40  * Author: Eric Mei <ericm@clusterfs.com>
41  */
42
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <fcntl.h>
47 #include <string.h>
48 #include <errno.h>
49 #include <pwd.h>
50 #include <keyutils.h>
51 #include <gssapi/gssapi.h>
52
53 #include "lsupport.h"
54 #include "lgss_utils.h"
55 #include "write_bytes.h"
56 #include "context.h"
57
58 /*
59  * gss target string of lustre service we are negotiating for
60  */
61 static char *g_service = NULL;
62
63 /*
64  * all data about negotiation
65  */
66 struct lgss_nego_data {
67         uint32_t        lnd_established:1;
68
69         int             lnd_secid;
70         uint32_t        lnd_uid;
71         uint32_t        lnd_lsvc;
72         char           *lnd_uuid;
73
74         gss_OID         lnd_mech;               /* mech OID */
75         gss_name_t      lnd_svc_name;           /* service name */
76         u_int           lnd_req_flags;          /* request flags */
77         gss_cred_id_t   lnd_cred;               /* credential */
78         gss_ctx_id_t    lnd_ctx;                /* session context */
79         gss_buffer_desc lnd_rmt_ctx;            /* remote handle of context */
80         uint32_t        lnd_seq_win;            /* sequence window */
81
82         int             lnd_rpc_err;
83         int             lnd_gss_err;
84 };
85
86 /*
87  * context creation response
88  */
89 struct lgss_init_res {
90         gss_buffer_desc gr_ctx;         /* context handle */
91         u_int           gr_major;       /* major status */
92         u_int           gr_minor;       /* minor status */
93         u_int           gr_win;         /* sequence window */
94         gss_buffer_desc gr_token;       /* token */
95 };
96
97 struct keyring_upcall_param {
98         uint32_t        kup_ver;
99         uint32_t        kup_secid;
100         uint32_t        kup_uid;
101         uint32_t        kup_fsuid;
102         uint32_t        kup_gid;
103         uint32_t        kup_fsgid;
104         uint32_t        kup_svc;
105         uint64_t        kup_nid;
106         char            kup_tgt[64];
107         char            kup_mech[16];
108         unsigned int    kup_is_root:1,
109                         kup_is_mdt:1,
110                         kup_is_ost:1;
111 };
112
113 /****************************************
114  * child process: gss negotiation       *
115  ****************************************/
116
117 #define INIT_CHANNEL    "/proc/fs/lustre/sptlrpc/gss/init_channel"
118
119 int do_nego_rpc(struct lgss_nego_data *lnd,
120                 gss_buffer_desc *gss_token,
121                 struct lgss_init_res *gr)
122 {
123         struct lgssd_ioctl_param  param;
124         struct passwd            *pw;
125         int                       fd, ret, res;
126         char                      outbuf[8192];
127         unsigned int             *p;
128
129         logmsg(LL_TRACE, "start negotiation rpc\n");
130
131         pw = getpwuid(lnd->lnd_uid);
132         if (!pw) {
133                 logmsg(LL_ERR, "no uid %u in local user database\n",
134                        lnd->lnd_uid);
135                 return -EACCES;
136         }
137
138         param.version = GSSD_INTERFACE_VERSION;
139         param.secid = lnd->lnd_secid;
140         param.uuid = lnd->lnd_uuid;
141         param.lustre_svc = lnd->lnd_lsvc;
142         param.uid = lnd->lnd_uid;
143         param.gid = pw->pw_gid;
144         param.send_token_size = gss_token->length;
145         param.send_token = (char *) gss_token->value;
146         param.reply_buf_size = sizeof(outbuf);
147         param.reply_buf = outbuf;
148
149         logmsg(LL_TRACE, "to open " INIT_CHANNEL "\n");
150
151         fd = open(INIT_CHANNEL, O_WRONLY);
152         if (fd < 0) {
153                 logmsg(LL_ERR, "can't open " INIT_CHANNEL "\n");
154                 return -EACCES;
155         }
156
157         logmsg(LL_TRACE, "to down-write\n");
158
159         ret = write(fd, &param, sizeof(param));
160         if (ret != sizeof(param)) {
161                 logmsg(LL_ERR, "lustre ioctl err: %d\n", strerror(errno));
162                 close(fd);
163                 return -EACCES;
164         }
165         close(fd);
166
167         logmsg(LL_TRACE, "do_nego_rpc: to parse reply\n");
168         if (param.status) {
169                 logmsg(LL_ERR, "status: %d (%s)\n",
170                        param.status, strerror((int)param.status));
171
172                 /* kernel return -ETIMEDOUT means the rpc timedout, we should
173                  * notify the caller to reinitiate the gss negotiation, by
174                  * returning -ERESTART
175                  */
176                 if (param.status == -ETIMEDOUT)
177                         return -ERESTART;
178                 else
179                         return param.status;
180         }
181
182         p = (unsigned int *)outbuf;
183         res = *p++;
184         gr->gr_major = *p++;
185         gr->gr_minor = *p++;
186         gr->gr_win = *p++;
187
188         gr->gr_ctx.length = *p++;
189         gr->gr_ctx.value = malloc(gr->gr_ctx.length);
190         memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
191         p += (((gr->gr_ctx.length + 3) & ~3) / 4);
192
193         gr->gr_token.length = *p++;
194         gr->gr_token.value = malloc(gr->gr_token.length);
195         memcpy(gr->gr_token.value, p, gr->gr_token.length);
196         p += (((gr->gr_token.length + 3) & ~3) / 4);
197
198         logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %d, token len %d, " \
199                "res %d\n", gr->gr_ctx.length, gr->gr_token.length, res);
200         return 0;
201 }
202
203 /*
204  * if return error, the lnd_rpc_err or lnd_gss_err is set.
205  */
206 static int lgssc_negotiation(struct lgss_nego_data *lnd)
207 {
208         struct lgss_init_res    gr;
209         gss_buffer_desc        *recv_tokenp, send_token;
210         OM_uint32               maj_stat, min_stat, ret_flags;
211
212         logmsg(LL_TRACE, "start gss negotiation\n");
213
214         /* GSS context establishment loop. */
215         memset(&gr, 0, sizeof(gr));
216         recv_tokenp = GSS_C_NO_BUFFER;
217
218         for (;;) {
219                 maj_stat = gss_init_sec_context(&min_stat,
220                                                 lnd->lnd_cred,
221                                                 &lnd->lnd_ctx,
222                                                 lnd->lnd_svc_name,
223                                                 lnd->lnd_mech,
224                                                 lnd->lnd_req_flags,
225                                                 0,            /* time req */
226                                                 NULL,         /* channel */
227                                                 recv_tokenp,
228                                                 NULL,         /* used mech */
229                                                 &send_token,
230                                                 &ret_flags,
231                                                 NULL);        /* time rec */
232
233                 if (recv_tokenp != GSS_C_NO_BUFFER) {
234                         gss_release_buffer(&min_stat, &gr.gr_token);
235                         recv_tokenp = GSS_C_NO_BUFFER;
236                 }
237
238                 if (maj_stat != GSS_S_COMPLETE &&
239                     maj_stat != GSS_S_CONTINUE_NEEDED) {
240                         lnd->lnd_gss_err = maj_stat;
241
242                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
243                                    "failed init context");
244                         break;
245                 }
246
247                 if (send_token.length != 0) {
248                         memset(&gr, 0, sizeof(gr));
249
250                         lnd->lnd_rpc_err = do_nego_rpc(lnd, &send_token, &gr);
251                         gss_release_buffer(&min_stat, &send_token);
252
253                         if (lnd->lnd_rpc_err) {
254                                 logmsg(LL_ERR, "negotiation rpc error: %d\n",
255                                        lnd->lnd_rpc_err);
256                                 return -1;
257                         }
258
259                         if (gr.gr_major != GSS_S_COMPLETE &&
260                             gr.gr_major != GSS_S_CONTINUE_NEEDED) {
261                                 lnd->lnd_gss_err = gr.gr_major;
262
263                                 logmsg(LL_ERR, "negotiation gss error %x\n",
264                                        lnd->lnd_gss_err);
265                                 return -1;
266                         }
267
268                         if (gr.gr_ctx.length != 0) {
269                                 if (lnd->lnd_rmt_ctx.value)
270                                         gss_release_buffer(&min_stat,
271                                                            &lnd->lnd_rmt_ctx);
272                                 lnd->lnd_rmt_ctx = gr.gr_ctx;
273                         }
274
275                         if (gr.gr_token.length != 0) {
276                                 if (maj_stat != GSS_S_CONTINUE_NEEDED)
277                                         break;
278                                 recv_tokenp = &gr.gr_token;
279                         }
280                 }
281
282                 /* GSS_S_COMPLETE => check gss header verifier,
283                  * usually checked in gss_validate
284                  */
285                 if (maj_stat == GSS_S_COMPLETE) {
286                         lnd->lnd_established = 1;
287                         lnd->lnd_seq_win = gr.gr_win;
288                         break;
289                 }
290         }
291
292         /* End context negotiation loop. */
293         if (!lnd->lnd_established) {
294                 if (gr.gr_token.length != 0)
295                         gss_release_buffer(&min_stat, &gr.gr_token);
296
297                 if (lnd->lnd_gss_err == GSS_S_COMPLETE)
298                         lnd->lnd_rpc_err = -EACCES;
299
300                 logmsg(LL_ERR, "context negotiation failed\n");
301                 return -1;
302         }
303
304         logmsg(LL_DEBUG, "successfully negotiated a context\n");
305         return 0;
306 }
307
308 /*
309  * if return error, the lnd_rpc_err or lnd_gss_err is set.
310  */
311 static int lgssc_init_nego_data(struct lgss_nego_data *lnd,
312                                 struct keyring_upcall_param *kup,
313                                 lgss_mech_t mech)
314 {
315         gss_buffer_desc         sname;
316         OM_uint32               maj_stat, min_stat;
317
318         memset(lnd, 0, sizeof(*lnd));
319
320         lnd->lnd_secid = kup->kup_secid;
321         lnd->lnd_uid = kup->kup_uid;
322         lnd->lnd_lsvc = kup->kup_svc;
323         lnd->lnd_uuid = kup->kup_tgt;
324
325         lnd->lnd_established = 0;
326         lnd->lnd_svc_name = GSS_C_NO_NAME;
327         lnd->lnd_cred = GSS_C_NO_CREDENTIAL;
328         lnd->lnd_ctx = GSS_C_NO_CONTEXT;
329         lnd->lnd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
330         lnd->lnd_seq_win = 0;
331
332         switch (mech) {
333         case LGSS_MECH_KRB5:
334                 lnd->lnd_mech = (gss_OID) &krb5oid;
335                 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
336                 break;
337         default:
338                 logmsg(LL_ERR, "invalid mech: %d\n", mech);
339                 lnd->lnd_rpc_err = -EACCES;
340                 return -1;
341         }
342
343         sname.value = g_service;
344         sname.length = strlen(g_service);
345
346         maj_stat = gss_import_name(&min_stat, &sname,
347                                    (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
348                                    &lnd->lnd_svc_name);
349         if (maj_stat != GSS_S_COMPLETE) {
350                 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
351                            "can't import svc name");
352                 lnd->lnd_gss_err = maj_stat;
353                 return -1;
354         }
355
356         return 0;
357 }
358
359 void lgssc_fini_nego_data(struct lgss_nego_data *lnd)
360 {
361         OM_uint32       maj_stat, min_stat;
362
363         if (lnd->lnd_svc_name != GSS_C_NO_NAME) {
364                 maj_stat = gss_release_name(&min_stat, &lnd->lnd_svc_name);
365                 if (maj_stat != GSS_S_COMPLETE)
366                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
367                                    "can't release service name");
368         }
369
370         if (lnd->lnd_cred != GSS_C_NO_CREDENTIAL) {
371                 maj_stat = gss_release_cred(&min_stat, &lnd->lnd_cred);
372                 if (maj_stat != GSS_S_COMPLETE)
373                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
374                                    "can't release credential");
375         }
376 }
377
378 static
379 int error_kernel_key(key_serial_t keyid, int rpc_error, int gss_error)
380 {
381         int      seqwin = 0;
382         char     buf[32];
383         char    *p, *end;
384
385         logmsg(LL_TRACE, "revoking kernel key %08x\n", keyid);
386
387         p = buf;
388         end = buf + sizeof(buf);
389
390         WRITE_BYTES(&p, end, seqwin);
391         WRITE_BYTES(&p, end, rpc_error);
392         WRITE_BYTES(&p, end, gss_error);
393
394 again:
395         if (keyctl_update(keyid, buf, p - buf)) {
396                 if (errno != EAGAIN) {
397                         logmsg(LL_ERR, "revoke key %08x: %s\n",
398                                keyid, strerror(errno));
399                         return -1;
400                 }
401
402                 logmsg(LL_WARN, "key %08x: revoking too soon, try again\n",
403                        keyid);
404                 sleep(2);
405                 goto again;
406         }
407
408         logmsg(LL_INFO, "key %08x: revoked\n", keyid);
409         return 0;
410 }
411
412 static
413 int update_kernel_key(key_serial_t keyid,
414                       struct lgss_nego_data *lnd,
415                       gss_buffer_desc *ctx_token)
416 {
417         char        *buf = NULL, *p = NULL, *end = NULL;
418         unsigned int buf_size = 0;
419         int          rc;
420
421         logmsg(LL_TRACE, "updating kernel key %08x\n", keyid);
422
423         buf_size = sizeof(lnd->lnd_seq_win) +
424                    sizeof(lnd->lnd_rmt_ctx.length) + lnd->lnd_rmt_ctx.length +
425                    sizeof(ctx_token->length) + ctx_token->length;
426         buf = malloc(buf_size);
427         if (buf == NULL) {
428                 logmsg(LL_ERR, "key %08x: can't alloc update buf: size %d\n",
429                        keyid, buf_size);
430                 return 1;
431         }
432
433         p = buf;
434         end = buf + buf_size;
435         rc = -1;
436
437         if (WRITE_BYTES(&p, end, lnd->lnd_seq_win))
438                 goto out;
439         if (write_buffer(&p, end, &lnd->lnd_rmt_ctx))
440                 goto out;
441         if (write_buffer(&p, end, ctx_token))
442                 goto out;
443
444 again:
445         if (keyctl_update(keyid, buf, p - buf)) {
446                 if (errno != EAGAIN) {
447                         logmsg(LL_ERR, "update key %08x: %s\n",
448                                keyid, strerror(errno));
449                         goto out;
450                 }
451
452                 logmsg(LL_DEBUG, "key %08x: updating too soon, try again\n",
453                        keyid);
454                 sleep(2);
455                 goto again;
456         }
457
458         rc = 0;
459         logmsg(LL_DEBUG, "key %08x: updated\n", keyid);
460 out:
461         free(buf);
462         return rc;
463 }
464
465 /*
466  * note we inherited assumed authority from parent process
467  */
468 static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
469                               struct keyring_upcall_param *kup)
470 {
471         struct lgss_nego_data   lnd;
472         gss_buffer_desc         token = GSS_C_EMPTY_BUFFER;
473         OM_uint32               min_stat;
474         int                     rc = -1;
475
476         logmsg(LL_TRACE, "child start on behalf of key %08x: "
477                "cred %p, uid %u, svc %u, nid %llx, uids: %u:%u/%u:%u\n",
478                keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
479                kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
480
481         if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
482                 logmsg(LL_ERR, "key %08x: failed to construct service "
483                        "string\n", keyid);
484                 error_kernel_key(keyid, -EACCES, 0);
485                 goto out_cred;
486         }
487
488         if (lgss_using_cred(cred)) {
489                 logmsg(LL_ERR, "key %08x: can't using cred\n", keyid);
490                 error_kernel_key(keyid, -EACCES, 0);
491                 goto out_cred;
492         }
493
494         if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) {
495                 logmsg(LL_ERR, "key %08x: failed to initialize "
496                        "negotiation data\n", keyid);
497                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
498                 goto out_cred;
499         }
500
501         rc = lgssc_negotiation(&lnd);
502         if (rc) {
503                 logmsg(LL_ERR, "key %08x: failed to negotiation\n", keyid);
504                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
505                 goto out;
506         }
507
508         rc = serialize_context_for_kernel(lnd.lnd_ctx, &token, lnd.lnd_mech);
509         if (rc) {
510                 logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
511                 error_kernel_key(keyid, rc, lnd.lnd_gss_err);
512                 goto out;
513         }
514
515         rc = update_kernel_key(keyid,  &lnd, &token);
516         if (rc)
517                 goto out;
518
519         rc = 0;
520         logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
521                keyid, kup->kup_uid);
522 out:
523         if (token.length != 0)
524                 gss_release_buffer(&min_stat, &token);
525
526         lgssc_fini_nego_data(&lnd);
527
528 out_cred:
529         lgss_release_cred(cred);
530         return rc;
531 }
532
533 /*
534  * call out info format: s[:s]...
535  *  [0]: secid          (uint)
536  *  [1]: mech_name      (string)
537  *  [2]: uid            (uint)
538  *  [3]: gid            (uint)
539  *  [4]: flags          (string) FMT: r-root; m-mdt; o-ost
540  *  [5]: lustre_svc     (uint)
541  *  [6]: target_nid     (uint64)
542  *  [7]: target_uuid    (string)
543  */
544 static int parse_callout_info(const char *coinfo,
545                               struct keyring_upcall_param *uparam)
546 {
547         const int       nargs = 8;
548         char            buf[1024];
549         char           *string = buf;
550         int             length, i;
551         char           *data[nargs];
552         char           *pos;
553
554         length = strlen(coinfo) + 1;
555         if (length > 1024) {
556                 logmsg(LL_ERR, "coinfo too long\n");
557                 return -1;
558         }
559         memcpy(buf, coinfo, length);
560
561         for (i = 0; i < nargs - 1; i++) {
562                 pos = strchr(string, ':');
563                 if (pos == NULL) {
564                         logmsg(LL_ERR, "short of components\n");
565                         return -1;
566                 }
567
568                 *pos = '\0';
569                 data[i] = string;
570                 string = pos + 1;
571         }
572         data[i] = string;
573
574         logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%s,%s,%s\n",
575                data[0], data[1], data[2], data[3], data[4], data[5],
576                data[6], data[7]);
577
578         uparam->kup_secid = strtol(data[0], NULL, 0);
579         strlcpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech));
580         uparam->kup_uid = strtol(data[2], NULL, 0);
581         uparam->kup_gid = strtol(data[3], NULL, 0);
582         if (strchr(data[4], 'r'))
583                 uparam->kup_is_root = 1;
584         if (strchr(data[4], 'm'))
585                 uparam->kup_is_mdt = 1;
586         if (strchr(data[4], 'o'))
587                 uparam->kup_is_ost = 1;
588         uparam->kup_svc = strtol(data[5], NULL, 0);
589         uparam->kup_nid = strtoll(data[6], NULL, 0);
590         strlcpy(uparam->kup_tgt, data[7], sizeof(uparam->kup_tgt));
591
592         logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u "
593                "is_root %d, is_mdt %d, is_ost %d, svc %d, nid 0x%llx, tgt %s\n",
594                uparam->kup_secid, uparam->kup_mech,
595                uparam->kup_uid, uparam->kup_gid,
596                uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
597                uparam->kup_svc, uparam->kup_nid, uparam->kup_tgt);
598         return 0;
599 }
600
601 #define LOG_LEVEL_PATH  "/proc/fs/lustre/sptlrpc/gss/lgss_keyring/debug_level"
602
603 static void set_log_level()
604 {
605         FILE         *file;
606         unsigned int  level;
607
608         file = fopen(LOG_LEVEL_PATH, "r");
609         if (file == NULL)
610                 return;
611
612         if (fscanf(file, "%u", &level) != 1)
613                 goto out;
614
615         if (level >= LL_MAX)
616                 goto out;
617
618         lgss_set_loglevel(level);
619 out:
620         fclose(file);
621 }
622
623 /****************************************
624  * main process                         *
625  ****************************************/
626
627 int main(int argc, char *argv[])
628 {
629         struct keyring_upcall_param     uparam;
630         key_serial_t                    keyid;
631         key_serial_t                    sring;
632         key_serial_t                    inst_keyring;
633         pid_t                           child;
634         struct lgss_mech_type          *mech;
635         struct lgss_cred               *cred;
636
637         set_log_level();
638
639         logmsg(LL_TRACE, "start parsing parameters\n");
640         /*
641          * parse & sanity check upcall parameters
642          * expected to be called with:
643          * [1]:  operation
644          * [2]:  key ID
645          * [3]:  key type
646          * [4]:  key description
647          * [5]:  call out info
648          * [6]:  UID
649          * [7]:  GID
650          * [8]:  thread keyring
651          * [9]:  process keyring
652          * [10]: session keyring
653          */
654         if (argc != 10 + 1) {
655                 logmsg(LL_ERR, "invalid parameter number %d\n", argc);
656                 return 1;
657         }
658
659         logmsg(LL_INFO, "key %s, desc %s, ugid %s:%s, sring %s, coinfo %s\n",
660                argv[2], argv[4], argv[6], argv[7], argv[10], argv[5]);
661
662         memset(&uparam, 0, sizeof(uparam));
663
664         if (strcmp(argv[1], "create") != 0) {
665                 logmsg(LL_ERR, "invalid OP %s\n", argv[1]);
666                 return 1;
667         }
668
669         if (sscanf(argv[2], "%d", &keyid) != 1) {
670                 logmsg(LL_ERR, "can't extract KeyID: %s\n", argv[2]);
671                 return 1;
672         }
673
674         if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) {
675                 logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]);
676                 return 1;
677         }
678
679         if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) {
680                 logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]);
681                 return 1;
682         }
683
684         if (sscanf(argv[10], "%d", &sring) != 1) {
685                 logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]);
686                 return 1;
687         }
688
689         if (parse_callout_info(argv[5], &uparam)) {
690                 logmsg(LL_ERR, "can't extract callout info: %s\n", argv[5]);
691                 return 1;
692         }
693
694         logmsg(LL_TRACE, "parsing parameters OK\n");
695
696         /*
697          * prepare a cred
698          */
699         mech = lgss_name2mech(uparam.kup_mech);
700         if (mech == NULL) {
701                 logmsg(LL_ERR, "key %08x: unsupported mech: %s\n",
702                        keyid, uparam.kup_mech);
703                 return 1;
704         }
705
706         if (lgss_mech_initialize(mech)) {
707                 logmsg(LL_ERR, "key %08x: can't initialize mech %s\n",
708                        keyid, mech->lmt_name);
709                 return 1;
710         }
711
712         cred = lgss_create_cred(mech);
713         if (cred == NULL) {
714                 logmsg(LL_ERR, "key %08x: can't create a new %s cred\n",
715                        keyid, mech->lmt_name);
716                 return 1;
717         }
718
719         cred->lc_uid = uparam.kup_uid;
720         cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0;
721         cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0;
722         cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0;
723         cred->lc_tgt_nid = uparam.kup_nid;
724         cred->lc_tgt_svc = uparam.kup_svc;
725
726         if (lgss_prepare_cred(cred)) {
727                 logmsg(LL_ERR, "key %08x: failed to prepare credentials "
728                        "for user %d\n", keyid, uparam.kup_uid);
729                 return 1;
730         }
731
732         /* pre initialize the key. note the keyring linked to is actually of the
733          * original requesting process, not _this_ upcall process. if it's for
734          * root user, don't link to any keyrings because we want fully control
735          * on it, and share it among all root sessions; otherswise link to
736          * session keyring.
737          */
738         if (cred->lc_root_flags != 0)
739                 inst_keyring = 0;
740         else
741                 inst_keyring = KEY_SPEC_SESSION_KEYRING;
742
743         if (keyctl_instantiate(keyid, NULL, 0, inst_keyring)) {
744                 logmsg(LL_ERR, "instantiate key %08x: %s\n",
745                        keyid, strerror(errno));
746                 return 1;
747         }
748
749         logmsg(LL_TRACE, "instantiated kernel key %08x\n", keyid);
750
751         /*
752          * fork a child to do the real gss negotiation
753          */
754         child = fork();
755         if (child == -1) {
756                 logmsg(LL_ERR, "key %08x: can't create child: %s\n",
757                        keyid, strerror(errno));
758                 return 1;
759         } else if (child == 0) {
760                 return lgssc_kr_negotiate(keyid, cred, &uparam);
761         }
762
763         logmsg(LL_TRACE, "forked child %d\n", child);
764         return 0;
765 }