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