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