Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  *
31  * lustre/utils/gss/lgss_keyring.c
32  *
33  * user-space upcall to create GSS context, using keyring interface to kernel
34  *
35  * Author: Eric Mei <ericm@clusterfs.com>
36  */
37
38 #include <sched.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <fcntl.h>
45 #include <inttypes.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <pwd.h>
49 #include <keyutils.h>
50 #include <gssapi/gssapi.h>
51 #include <sys/wait.h>
52 #include <getopt.h>
53
54 #include <libcfs/util/param.h>
55 #include <libcfs/util/string.h>
56 #include <uapi/linux/lustre/lgss.h>
57 #include "lsupport.h"
58 #include "lgss_utils.h"
59 #include "lgss_krb5_utils.h"
60 #include "write_bytes.h"
61 #include "context.h"
62
63 /*
64  * gss target string of lustre service we are negotiating for
65  */
66 static char *g_service = NULL;
67
68 /*
69  * all data about negotiation
70  */
71 struct lgss_nego_data {
72         uint32_t        lnd_established:1;
73
74         int             lnd_secid;
75         uint32_t        lnd_uid;
76         uint32_t        lnd_lsvc;
77         char            *lnd_uuid;
78
79         gss_OID         lnd_mech;               /* mech OID */
80         gss_name_t      lnd_svc_name;           /* service name */
81         unsigned int    lnd_req_flags;          /* request flags */
82         gss_cred_id_t   lnd_cred;               /* credential */
83         gss_ctx_id_t    lnd_ctx;                /* session context */
84         gss_buffer_desc lnd_rmt_ctx;            /* remote handle of context */
85         gss_buffer_desc lnd_ctx_token;          /* context token for kernel */
86         uint32_t        lnd_seq_win;            /* sequence window */
87
88         int             lnd_rpc_err;
89         int             lnd_gss_err;
90 };
91
92 /*
93  * context creation response
94  */
95 struct lgss_init_res {
96         gss_buffer_desc gr_ctx;         /* context handle */
97         unsigned int    gr_major;       /* major status */
98         unsigned int    gr_minor;       /* minor status */
99         unsigned int    gr_win;         /* sequence window */
100         gss_buffer_desc gr_token;       /* token */
101 };
102
103 struct keyring_upcall_param {
104         uint32_t        kup_ver;
105         uint32_t        kup_secid;
106         uint32_t        kup_uid;
107         uint32_t        kup_fsuid;
108         uint32_t        kup_gid;
109         uint32_t        kup_fsgid;
110         uint32_t        kup_svc;
111         uint64_t        kup_nid;
112         uint64_t        kup_selfnid;
113         char            kup_svc_type;
114         char            kup_tgt[64];
115         char            kup_mech[16];
116         unsigned int    kup_is_root:1,
117                         kup_is_mdt:1,
118                         kup_is_ost:1;
119         uint32_t        kup_pid;
120 };
121
122 /****************************************
123  * child process: gss negotiation       *
124  ****************************************/
125
126 static int send_to(int fd, const void *buf, size_t size)
127 {
128         ssize_t sz;
129
130         sz = write(fd, buf, size);
131         if (sz == -1) {
132                 logmsg(LL_ERR, "cannot send to GSS process: %s\n",
133                        strerror(errno));
134                 return -errno;
135         }
136         if (sz < size) {
137                 logmsg(LL_ERR, "short write sending to GSS process: %d/%d\n",
138                        (int)sz, (int)size);
139                 return -EPROTO;
140         }
141
142         return 0;
143 }
144
145 static int receive_from(int fd, void *buf, size_t size)
146 {
147         ssize_t sz;
148
149         sz = read(fd, buf, size);
150         if (sz == -1) {
151                 logmsg(LL_ERR, "cannot receive from GSS process: %s\n",
152                        strerror(errno));
153                 return -errno;
154         }
155         if (sz < size) {
156                 logmsg(LL_ERR, "short read receiving from GSS process: %d/%d\n",
157                        (int)sz, (int)size);
158                 return -EPROTO;
159         }
160
161         return 0;
162 }
163
164 static int gss_do_ioctl(struct lgssd_ioctl_param *param)
165 {
166         int fd, ret;
167         glob_t path;
168         int rc;
169
170         rc = cfs_get_param_paths(&path, "sptlrpc/gss/init_channel");
171         if (rc != 0)
172                 return rc;
173
174         logmsg(LL_TRACE, "to open %s\n", path.gl_pathv[0]);
175
176         fd = open(path.gl_pathv[0], O_WRONLY);
177         if (fd < 0) {
178                 logmsg(LL_ERR, "can't open %s\n", path.gl_pathv[0]);
179                 rc = -EACCES;
180                 goto out_params;
181         }
182
183         logmsg(LL_TRACE, "to down-write\n");
184
185         ret = write(fd, param, sizeof(*param));
186         close(fd);
187         if (ret != sizeof(*param)) {
188                 logmsg(LL_ERR, "lustre ioctl err: %s\n", strerror(errno));
189                 rc = -EACCES;
190         }
191
192 out_params:
193         cfs_free_param_data(&path);
194         return rc;
195 }
196
197 static int do_nego_rpc(struct lgss_nego_data *lnd,
198                        gss_buffer_desc *gss_token,
199                        struct lgss_init_res *gr,
200                        int req_fd[2], int reply_fd[2])
201 {
202         struct lgssd_ioctl_param param;
203         struct passwd *pw;
204         int res;
205         char outbuf[8192] = { 0 };
206         unsigned int *p;
207         int rc = 0;
208
209         logmsg(LL_TRACE, "start negotiation rpc\n");
210
211         pw = getpwuid(lnd->lnd_uid);
212         if (!pw) {
213                 logmsg(LL_ERR, "no uid %u in local user database\n",
214                        lnd->lnd_uid);
215                 return -EACCES;
216         }
217
218         param.version = GSSD_INTERFACE_VERSION;
219         param.secid = lnd->lnd_secid;
220         param.uuid = lnd->lnd_uuid;
221         param.lustre_svc = lnd->lnd_lsvc;
222         param.uid = lnd->lnd_uid;
223         param.gid = pw->pw_gid;
224         param.send_token_size = gss_token->length;
225         param.send_token = (char *) gss_token->value;
226
227         if (req_fd[0] == -1 && reply_fd[0] == -1) {
228                 /* we can do the ioctl directly */
229                 param.reply_buf_size = sizeof(outbuf);
230                 param.reply_buf = outbuf;
231
232                 rc = gss_do_ioctl(&param);
233                 if (rc != 0)
234                         return rc;
235         } else {
236                 /* looks like we are running in a container,
237                  * so we cannot do the ioctl ourselves: delegate to
238                  * parent process running directly on host */
239
240                 /* send ioctl buffer to parent */
241                 rc = send_to(req_fd[1], &param, sizeof(param));
242                 if (rc != 0)
243                         return rc;
244                 /* send gss token to parent */
245                 rc = send_to(req_fd[1], gss_token->value, gss_token->length);
246                 if (rc != 0)
247                         return rc;
248
249                 /* read ioctl status from parent */
250                 rc = receive_from(reply_fd[0], &param.status,
251                                   sizeof(param.status));
252                 if (rc != 0)
253                         return rc;
254
255                 if (param.status == 0) {
256                         /* read reply buffer from parent */
257                         rc = receive_from(reply_fd[0], outbuf, sizeof(outbuf));
258                         if (rc != 0)
259                                 return rc;
260                 }
261         }
262
263         logmsg(LL_TRACE, "do_nego_rpc: to parse reply\n");
264         if (param.status) {
265                 logmsg(LL_ERR, "status: %ld (%s)\n",
266                        (long int)param.status, strerror((int)(-param.status)));
267                 return param.status;
268         }
269
270         p = (unsigned int *)outbuf;
271         res = *p++;
272         gr->gr_major = *p++;
273         gr->gr_minor = *p++;
274         gr->gr_win = *p++;
275
276         gr->gr_ctx.length = *p++;
277         gr->gr_ctx.value = malloc(gr->gr_ctx.length);
278         if (gr->gr_ctx.value == NULL)
279                 return -ENOMEM;
280         memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
281         p += (((gr->gr_ctx.length + 3) & ~3) / 4);
282
283         gr->gr_token.length = *p++;
284         gr->gr_token.value = malloc(gr->gr_token.length);
285         if (gr->gr_token.value == NULL) {
286                 free(gr->gr_ctx.value);
287                 return -ENOMEM;
288         }
289         memcpy(gr->gr_token.value, p, gr->gr_token.length);
290         p += (((gr->gr_token.length + 3) & ~3) / 4);
291
292         logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %zu, token len %zu, "
293                "res %d\n", gr->gr_ctx.length, gr->gr_token.length, res);
294
295         return rc;
296 }
297
298 /* This is used by incomplete GSSAPI implementations that can't use
299  * gss_init_sec_context and will parse the token themselves (gssnull and sk).
300  * Callers should have cred->lc_mech_token pointing to a gss_buffer_desc
301  * token to send to the peer as part of the SEC_CTX_INIT operation.  The return
302  * RPC's token with be in gr.gr_token which is validated using
303  * lgss_validate_cred. */
304 static int lgssc_negotiation_manual(struct lgss_nego_data *lnd,
305                                     struct lgss_cred *cred,
306                                     int req_fd[2], int reply_fd[2])
307 {
308         struct lgss_init_res gr;
309         OM_uint32 min_stat;
310         int rc;
311
312         logmsg(LL_TRACE, "starting gss negotation\n");
313         memset(&gr, 0, sizeof(gr));
314
315         lnd->lnd_rpc_err = do_nego_rpc(lnd, &cred->lc_mech_token, &gr,
316                                        req_fd, reply_fd);
317         if (lnd->lnd_rpc_err) {
318                 logmsg(LL_ERR, "negotiation rpc error %d\n", lnd->lnd_rpc_err);
319                 rc = lnd->lnd_rpc_err;
320                 goto out_error;
321         }
322
323         if (gr.gr_major == GSS_S_CONTINUE_NEEDED) {
324                 rc = -EAGAIN;
325                 goto out_error;
326
327         } else if (gr.gr_major != GSS_S_COMPLETE) {
328                 lnd->lnd_gss_err = gr.gr_major;
329                 logmsg(LL_ERR, "negotiation gss error %x\n", lnd->lnd_gss_err);
330                 rc = -ENOTCONN;
331                 goto out_error;
332         }
333
334         if (gr.gr_ctx.length == 0 || gr.gr_token.length == 0) {
335                 logmsg(LL_ERR, "zero length context or token received\n");
336                 rc = -EINVAL;
337                 goto out_error;
338         }
339
340         rc = lgss_validate_cred(cred, &gr.gr_token, &lnd->lnd_ctx_token);
341         if (rc) {
342                 logmsg(LL_ERR, "peer token failed validation\n");
343                 goto out_error;
344         }
345
346         lnd->lnd_established = 1;
347         lnd->lnd_seq_win = gr.gr_win;
348         lnd->lnd_rmt_ctx = gr.gr_ctx;
349
350         if (gr.gr_token.length != 0)
351                 gss_release_buffer(&min_stat, &gr.gr_token);
352
353         logmsg(LL_DEBUG, "successfully negotiated a context\n");
354         return 0;
355
356 out_error:
357         if (gr.gr_ctx.length != 0)
358                 gss_release_buffer(&min_stat, &gr.gr_ctx);
359         if (gr.gr_token.length != 0)
360                 gss_release_buffer(&min_stat, &gr.gr_token);
361
362         return rc;
363 }
364
365 /*
366  * if return error, the lnd_rpc_err or lnd_gss_err is set.
367  */
368 static int lgssc_negotiation(struct lgss_nego_data *lnd, int req_fd[2],
369                              int reply_fd[2])
370 {
371         struct lgss_init_res    gr;
372         gss_buffer_desc        *recv_tokenp, send_token;
373         OM_uint32               maj_stat, min_stat, ret_flags;
374
375         logmsg(LL_TRACE, "start gss negotiation\n");
376
377         /* GSS context establishment loop. */
378         memset(&gr, 0, sizeof(gr));
379         recv_tokenp = GSS_C_NO_BUFFER;
380
381         for (;;) {
382                 maj_stat = gss_init_sec_context(&min_stat,
383                                                 lnd->lnd_cred,
384                                                 &lnd->lnd_ctx,
385                                                 lnd->lnd_svc_name,
386                                                 lnd->lnd_mech,
387                                                 lnd->lnd_req_flags,
388                                                 0,            /* time req */
389                                                 NULL,         /* channel */
390                                                 recv_tokenp,
391                                                 NULL,         /* used mech */
392                                                 &send_token,
393                                                 &ret_flags,
394                                                 NULL);        /* time rec */
395
396                 logmsg_gss(LL_TRACE, lnd->lnd_mech, maj_stat, min_stat,
397                            "gss_init_sec_context");
398
399                 logmsg(LL_TRACE, "send_token:\n");
400                 log_hexl(LL_TRACE, send_token.value, send_token.length);
401
402                 if (recv_tokenp != GSS_C_NO_BUFFER) {
403                         gss_release_buffer(&min_stat, &gr.gr_token);
404                         recv_tokenp = GSS_C_NO_BUFFER;
405                 }
406
407                 if (maj_stat != GSS_S_COMPLETE &&
408                     maj_stat != GSS_S_CONTINUE_NEEDED) {
409                         lnd->lnd_gss_err = maj_stat;
410
411                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
412                                    "failed init context");
413                         break;
414                 }
415
416                 if (send_token.length != 0) {
417                         memset(&gr, 0, sizeof(gr));
418
419                         lnd->lnd_rpc_err = do_nego_rpc(lnd, &send_token, &gr,
420                                                        req_fd, reply_fd);
421                         gss_release_buffer(&min_stat, &send_token);
422
423                         if (lnd->lnd_rpc_err) {
424                                 logmsg(LL_ERR, "negotiation rpc error: %d\n",
425                                        lnd->lnd_rpc_err);
426                                 return lnd->lnd_rpc_err;
427                         }
428
429                         if (gr.gr_major != GSS_S_COMPLETE &&
430                             gr.gr_major != GSS_S_CONTINUE_NEEDED) {
431                                 lnd->lnd_gss_err = gr.gr_major;
432
433                                 logmsg(LL_ERR, "negotiation gss error %x\n",
434                                        lnd->lnd_gss_err);
435                                 return -ENOTCONN;
436                         }
437
438                         if (gr.gr_ctx.length != 0) {
439                                 if (lnd->lnd_rmt_ctx.value)
440                                         gss_release_buffer(&min_stat,
441                                                            &lnd->lnd_rmt_ctx);
442                                 lnd->lnd_rmt_ctx = gr.gr_ctx;
443                         }
444
445                         if (gr.gr_token.length != 0) {
446                                 if (maj_stat != GSS_S_CONTINUE_NEEDED)
447                                         break;
448                                 recv_tokenp = &gr.gr_token;
449                         }
450                 }
451
452                 /* GSS_S_COMPLETE => check gss header verifier,
453                  * usually checked in gss_validate
454                  */
455                 if (maj_stat == GSS_S_COMPLETE) {
456                         lnd->lnd_established = 1;
457                         lnd->lnd_seq_win = gr.gr_win;
458                         break;
459                 }
460         }
461
462         /* End context negotiation loop. */
463         if (!lnd->lnd_established) {
464                 if (gr.gr_token.length != 0)
465                         gss_release_buffer(&min_stat, &gr.gr_token);
466
467                 if (lnd->lnd_gss_err == GSS_S_COMPLETE)
468                         lnd->lnd_rpc_err = -EACCES;
469
470                 logmsg(LL_ERR, "context negotiation failed\n");
471                 return -1;
472         }
473
474         logmsg(LL_DEBUG, "successfully negotiated a context\n");
475         return 0;
476 }
477
478 /*
479  * if return error, the lnd_rpc_err or lnd_gss_err is set.
480  */
481 static int lgssc_init_nego_data(struct lgss_nego_data *lnd,
482                                 struct keyring_upcall_param *kup,
483                                 enum lgss_mech mech)
484 {
485         gss_buffer_desc         sname;
486         OM_uint32               maj_stat, min_stat;
487
488         memset(lnd, 0, sizeof(*lnd));
489
490         lnd->lnd_secid = kup->kup_secid;
491         lnd->lnd_uid = kup->kup_uid;
492         lnd->lnd_lsvc = kup->kup_svc | mech << LUSTRE_GSS_MECH_SHIFT;
493         lnd->lnd_uuid = kup->kup_tgt;
494
495         lnd->lnd_established = 0;
496         lnd->lnd_svc_name = GSS_C_NO_NAME;
497         lnd->lnd_cred = GSS_C_NO_CREDENTIAL;
498         lnd->lnd_ctx = GSS_C_NO_CONTEXT;
499         lnd->lnd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
500         lnd->lnd_seq_win = 0;
501
502         switch (mech) {
503         case LGSS_MECH_KRB5:
504                 lnd->lnd_mech = (gss_OID)&krb5oid;
505                 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
506                 break;
507         case LGSS_MECH_NULL:
508                 lnd->lnd_mech = (gss_OID)&nulloid;
509                 break;
510 #ifdef HAVE_OPENSSL_SSK
511         case LGSS_MECH_SK:
512                 lnd->lnd_mech = (gss_OID)&skoid;
513                 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
514                 break;
515 #endif
516         default:
517                 logmsg(LL_ERR, "invalid mech: %d\n", mech);
518                 lnd->lnd_rpc_err = -EACCES;
519                 return -1;
520         }
521
522         sname.value = g_service;
523         sname.length = strlen(g_service);
524
525         maj_stat = gss_import_name(&min_stat, &sname,
526                                    (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
527                                    &lnd->lnd_svc_name);
528         if (maj_stat != GSS_S_COMPLETE) {
529                 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
530                            "can't import svc name");
531                 lnd->lnd_gss_err = maj_stat;
532                 return -1;
533         }
534
535         return 0;
536 }
537
538 static void lgssc_fini_nego_data(struct lgss_nego_data *lnd)
539 {
540         OM_uint32       maj_stat, min_stat;
541
542         if (lnd->lnd_svc_name != GSS_C_NO_NAME) {
543                 maj_stat = gss_release_name(&min_stat, &lnd->lnd_svc_name);
544                 if (maj_stat != GSS_S_COMPLETE)
545                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
546                                    "can't release service name");
547         }
548
549         if (lnd->lnd_cred != GSS_C_NO_CREDENTIAL) {
550                 maj_stat = gss_release_cred(&min_stat, &lnd->lnd_cred);
551                 if (maj_stat != GSS_S_COMPLETE)
552                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
553                                    "can't release credential");
554         }
555 }
556
557 static int fork_and_switch_id(int uid, pid_t *child)
558 {
559         int status, rc = 0;
560
561         *child = fork();
562         if (*child == -1) {
563                 logmsg(LL_ERR, "cannot fork child for user %u: %s\n",
564                        uid, strerror(errno));
565                 rc = errno;
566         } else if (*child == 0) {
567                 /* switch identity */
568                 rc = switch_identity(uid);
569                 if (rc)
570                         rc = errno;
571         } else {
572                 if (wait(&status) < 0) {
573                         rc = errno;
574                         logmsg(LL_ERR, "child %d failed: %s\n",
575                                *child, strerror(rc));
576                 } else {
577                         rc = WEXITSTATUS(status);
578                         if (rc)
579                                 logmsg(LL_ERR, "child %d terminated with %d\n",
580                                        *child, rc);
581                 }
582         }
583         return rc;
584 }
585
586 static int do_keyctl_update(char *reason, key_serial_t keyid,
587                             const void *payload, size_t plen)
588 {
589         while (keyctl_update(keyid, payload, plen)) {
590                 if (errno != EAGAIN) {
591                         logmsg(LL_ERR, "%se key %08x: %s\n",
592                                reason, keyid, strerror(errno));
593                         return -1;
594                 }
595
596                 logmsg(LL_WARN, "key %08x: %sing too soon, try again\n",
597                        keyid, reason);
598                 sleep(2);
599         }
600
601         logmsg(LL_INFO, "key %08x: %sed\n", keyid, reason);
602         return 0;
603 }
604
605 static int error_kernel_key(key_serial_t keyid, int rpc_error, int gss_error,
606                             uid_t uid)
607 {
608         key_serial_t inst_keyring = KEY_SPEC_SESSION_KEYRING;
609         pid_t child = 1;
610         int seqwin = 0;
611         char *p, *end;
612         char buf[32];
613         int rc, rc2;
614
615         logmsg(LL_TRACE, "revoking kernel key %08x\n", keyid);
616
617         /* Only possessor and uid can update the key. So for a user key that is
618          * linked to the user keyring, switch uid/gid in a subprocess to not
619          * change identity in main process.
620          */
621         if (uid) {
622                 rc = fork_and_switch_id(uid, &child);
623                 if (rc || child)
624                         goto out;
625                 inst_keyring = KEY_SPEC_USER_KEYRING;
626         }
627
628         p = buf;
629         end = buf + sizeof(buf);
630
631         WRITE_BYTES(&p, end, seqwin);
632         WRITE_BYTES(&p, end, rpc_error);
633         WRITE_BYTES(&p, end, gss_error);
634
635         rc = do_keyctl_update("revok", keyid, buf, p - buf);
636         /* no matter if revoking key was successful or not, always try unlink */
637         rc2 = keyctl_unlink(keyid, inst_keyring);
638         if (rc2) {
639                 logmsg(LL_ERR, "unlink key %08x from %d: %s\n",
640                        keyid, inst_keyring, strerror(errno));
641                 if (!rc)
642                         rc = rc2;
643         } else {
644                 logmsg(LL_INFO, "key %08x: unlinked from %d\n",
645                        keyid, inst_keyring);
646         }
647
648 out:
649         if (child == 0)
650                 /* job done for child */
651                 exit(rc);
652         return rc;
653 }
654
655 static int update_kernel_key(key_serial_t keyid,
656                              struct lgss_nego_data *lnd,
657                              gss_buffer_desc *ctx_token)
658 {
659         char *buf = NULL, *p = NULL, *end = NULL;
660         unsigned int buf_size = 0;
661         pid_t child = 1;
662         int uid, rc = 0;
663
664         logmsg(LL_TRACE, "updating kernel key %08x\n", keyid);
665
666         /* Only possessor and uid can update the key. So for a user key that is
667          * linked to the user keyring, switch uid/gid in a subprocess to not
668          * change identity in main process.
669          */
670         uid = lnd->lnd_uid;
671         if (uid) {
672                 rc = fork_and_switch_id(uid, &child);
673                 if (rc || child)
674                         goto out;
675         }
676
677         buf_size = sizeof(lnd->lnd_seq_win) +
678                 sizeof(lnd->lnd_rmt_ctx.length) + lnd->lnd_rmt_ctx.length +
679                 sizeof(ctx_token->length) + ctx_token->length;
680         buf = malloc(buf_size);
681         if (buf == NULL) {
682                 logmsg(LL_ERR, "key %08x: can't alloc update buf: size %d\n",
683                        keyid, buf_size);
684                 rc = ENOMEM;
685                 goto out;
686         }
687
688         p = buf;
689         end = buf + buf_size;
690         rc = -1;
691
692         if (WRITE_BYTES(&p, end, lnd->lnd_seq_win))
693                 goto out;
694         if (write_buffer(&p, end, &lnd->lnd_rmt_ctx))
695                 goto out;
696         if (write_buffer(&p, end, ctx_token))
697                 goto out;
698
699         rc = do_keyctl_update("updat", keyid, buf, p - buf);
700
701 out:
702         free(buf);
703         if (child == 0)
704                 /* job done for child */
705                 exit(rc);
706         return rc;
707 }
708
709 static int lgssc_kr_negotiate_krb(key_serial_t keyid, struct lgss_cred *cred,
710                                   struct keyring_upcall_param *kup,
711                                   int req_fd[2], int reply_fd[2])
712 {
713         struct lgss_nego_data lnd;
714         OM_uint32 min_stat;
715         int rc = -1;
716         bool redo = true;
717
718         if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
719                 logmsg(LL_ERR, "key %08x: failed to construct service "
720                        "string\n", keyid);
721                 error_kernel_key(keyid, -EACCES, 0, cred->lc_uid);
722                 goto out_cred;
723         }
724
725         if (lgss_using_cred(cred)) {
726                 logmsg(LL_ERR, "key %08x: can't using cred\n", keyid);
727                 error_kernel_key(keyid, -EACCES, 0, cred->lc_uid);
728                 goto out_cred;
729         }
730
731 retry_nego:
732         memset(&lnd, 0, sizeof(lnd));
733         if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) {
734                 logmsg(LL_ERR, "key %08x: failed to initialize "
735                        "negotiation data\n", keyid);
736                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err,
737                                  cred->lc_uid);
738                 goto out_cred;
739         }
740
741         rc = lgssc_negotiation(&lnd, req_fd, reply_fd);
742         if (rc == -EAGAIN || (rc == -ETIMEDOUT && redo)) {
743                 logmsg(LL_ERR, "Failed negotiation must retry\n");
744                 redo = false;
745                 goto retry_nego;
746         } else if (rc) {
747                 logmsg(LL_ERR, "key %08x: failed to negotiation\n", keyid);
748                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err,
749                                  cred->lc_uid);
750                 goto out;
751         }
752
753         rc = serialize_context_for_kernel(&lnd.lnd_ctx, &lnd.lnd_ctx_token,
754                                           lnd.lnd_mech);
755         if (rc) {
756                 logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
757                 error_kernel_key(keyid, rc, lnd.lnd_gss_err, cred->lc_uid);
758                 goto out;
759         }
760
761         rc = update_kernel_key(keyid,  &lnd, &lnd.lnd_ctx_token);
762         if (rc)
763                 goto out;
764
765         rc = 0;
766         logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
767                keyid, kup->kup_uid);
768 out:
769         if (lnd.lnd_ctx_token.length != 0)
770                 (void)gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
771
772         lgssc_fini_nego_data(&lnd);
773
774 out_cred:
775         lgss_release_cred(cred);
776         return rc;
777 }
778
779 static int lgssc_kr_negotiate_manual(key_serial_t keyid, struct lgss_cred *cred,
780                                      struct keyring_upcall_param *kup,
781                                      int req_fd[2], int reply_fd[2])
782 {
783         struct lgss_nego_data lnd;
784         OM_uint32 min_stat;
785         int rc;
786         bool redo = true;
787
788         rc = lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid);
789         if (rc) {
790                 logmsg(LL_ERR, "key %08x: failed to construct service "
791                        "string\n", keyid);
792                 error_kernel_key(keyid, -EACCES, 0, 0);
793                 goto out_cred;
794         }
795
796         rc = lgss_using_cred(cred);
797         if (rc) {
798                 logmsg(LL_ERR, "key %08x: can't use cred\n", keyid);
799                 error_kernel_key(keyid, -EACCES, 0, 0);
800                 goto out_cred;
801         }
802
803 retry:
804         memset(&lnd, 0, sizeof(lnd));
805         rc = lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n);
806         if (rc) {
807                 logmsg(LL_ERR, "key %08x: failed to initialize "
808                        "negotiation data\n", keyid);
809                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err, 0);
810                 goto out_cred;
811         }
812
813         /*
814          * Handles the negotiation but then calls lgss_validate to make sure
815          * the token is valid.  It also populates the lnd_ctx_token for the
816          * update to the kernel key
817          */
818         rc = lgssc_negotiation_manual(&lnd, cred, req_fd, reply_fd);
819         if (rc == -EAGAIN || (rc == -ETIMEDOUT && redo)) {
820                 logmsg(LL_ERR, "Failed negotiation must retry\n");
821                 redo = false;
822                 goto retry;
823         } else if (rc) {
824                 logmsg(LL_ERR, "key %08x: failed to negotiate\n", keyid);
825                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err, 0);
826                 goto out;
827         }
828
829         rc = update_kernel_key(keyid,  &lnd, &lnd.lnd_ctx_token);
830         if (rc)
831                 goto out;
832
833         logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
834                keyid, kup->kup_uid);
835 out:
836         if (lnd.lnd_ctx_token.length != 0)
837                 gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
838
839         lgssc_fini_nego_data(&lnd);
840
841 out_cred:
842         lgss_release_cred(cred);
843         return rc;
844 }
845
846 /*
847  * note we inherited assumed authority from parent process
848  */
849 static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
850                               struct keyring_upcall_param *kup,
851                               int req_fd[2], int reply_fd[2])
852 {
853         int rc;
854
855         logmsg(LL_TRACE, "child start on behalf of key %08x: "
856                "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n",
857                keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
858                kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
859
860         switch (cred->lc_mech->lmt_mech_n) {
861         case LGSS_MECH_NULL:
862         case LGSS_MECH_SK:
863                 rc = lgssc_kr_negotiate_manual(keyid, cred, kup,
864                                                req_fd, reply_fd);
865                 break;
866         case LGSS_MECH_KRB5:
867         default:
868                 rc = lgssc_kr_negotiate_krb(keyid, cred, kup, req_fd, reply_fd);
869                 break;
870         }
871
872         return rc;
873 }
874
875 /*
876  * call out info format: s[:s]...
877  *  [0]: secid          (uint)
878  *  [1]: mech_name      (string)
879  *  [2]: uid            (uint)
880  *  [3]: gid            (uint)
881  *  [4]: flags          (string) FMT: r-root; m-mdt; o-ost
882  *  [5]: svc type       (char)
883  *  [6]: lustre_svc     (int)
884  *  [7]: target_nid     (uint64)
885  *  [8]: target_uuid    (string)
886  *  [9]: self_nid        (uint64)
887  *  [10]: pid            (uint)
888  */
889 static int parse_callout_info(const char *coinfo,
890                               struct keyring_upcall_param *uparam)
891 {
892         const int       nargs = 11;
893         char            buf[1024];
894         char           *string = buf;
895         int             length, i;
896         char           *data[nargs];
897         char           *pos;
898
899         length = strlen(coinfo) + 1;
900         if (length > 1024) {
901                 logmsg(LL_ERR, "coinfo too long\n");
902                 return -1;
903         }
904         memcpy(buf, coinfo, length);
905
906         for (i = 0; i < nargs - 1; i++) {
907                 pos = strchr(string, ':');
908                 if (pos == NULL) {
909                         logmsg(LL_ERR, "short of components\n");
910                         return -1;
911                 }
912
913                 *pos = '\0';
914                 data[i] = string;
915                 string = pos + 1;
916         }
917         data[i] = string;
918
919         logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s,%s\n",
920                data[0], data[1], data[2], data[3], data[4], data[5][0],
921                data[6], data[7], data[8], data[9], data[10]);
922
923         uparam->kup_secid = strtol(data[0], NULL, 0);
924         snprintf(uparam->kup_mech, sizeof(uparam->kup_mech), "%s", data[1]);
925         uparam->kup_uid = strtol(data[2], NULL, 0);
926         uparam->kup_gid = strtol(data[3], NULL, 0);
927         if (strchr(data[4], 'r'))
928                 uparam->kup_is_root = 1;
929         if (strchr(data[4], 'm'))
930                 uparam->kup_is_mdt = 1;
931         if (strchr(data[4], 'o'))
932                 uparam->kup_is_ost = 1;
933         uparam->kup_svc_type = data[5][0];
934         uparam->kup_svc = strtol(data[6], NULL, 0);
935         uparam->kup_nid = strtoll(data[7], NULL, 0);
936         snprintf(uparam->kup_tgt, sizeof(uparam->kup_tgt), "%s", data[8]);
937         uparam->kup_selfnid = strtoll(data[9], NULL, 0);
938         uparam->kup_pid = strtol(data[10], NULL, 0);
939
940         logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, "
941                "is_root %d, is_mdt %d, is_ost %d, svc type %c, svc %d, "
942                "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64", pid %d\n",
943                uparam->kup_secid, uparam->kup_mech,
944                uparam->kup_uid, uparam->kup_gid,
945                uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
946                uparam->kup_svc_type, uparam->kup_svc, uparam->kup_nid,
947                uparam->kup_tgt, uparam->kup_selfnid, uparam->kup_pid);
948         return 0;
949 }
950
951 static void set_log_level()
952 {
953         unsigned int level;
954         glob_t path;
955         FILE *file;
956
957         if (cfs_get_param_paths(&path,
958                                 "sptlrpc/gss/lgss_keyring/debug_level") != 0)
959                 return;
960         file = fopen(path.gl_pathv[0], "r");
961         if (file == NULL) {
962                 cfs_free_param_data(&path);
963                 return;
964         }
965
966         if (fscanf(file, "%u", &level) != 1)
967                 goto out;
968
969         if (level >= LL_MAX)
970                 goto out;
971
972         lgss_set_loglevel(level);
973 out:
974         cfs_free_param_data(&path);
975         fclose(file);
976 }
977
978 static int associate_with_ns(char *path)
979 {
980         int fd, rc = -1;
981
982         fd = open(path, O_RDONLY);
983         if (fd != -1) {
984                 rc = setns(fd, 0);
985                 close(fd);
986         }
987
988         return rc;
989 }
990
991 static int prepare_and_instantiate(struct lgss_cred *cred, key_serial_t keyid,
992                                    uint32_t uid)
993 {
994         key_serial_t inst_keyring;
995         bool prepared = true;
996         pid_t child = 1;
997         int rc = 0;
998
999         if (lgss_prepare_cred(cred)) {
1000                 logmsg(LL_ERR, "key %08x: failed to prepare credentials "
1001                        "for user %d\n", keyid, uid);
1002                 /* prepare failed, but still instantiate the key for regular
1003                  * user, so that it can be used to report the error later
1004                  * in the process
1005                  */
1006                 if (cred->lc_root_flags)
1007                         return 1;
1008                 prepared = false;
1009         }
1010
1011         /* Pre initialize the key. Note the keyring linked to is actually of the
1012          * original requesting process, not _this_ upcall process. If it's for
1013          * root user, don't link to any keyrings because we want fully control
1014          * on it, and share it among all root sessions.
1015          * Otherswise link to user keyring, which requires switching uid/gid.
1016          * Do this in a subprocess because other operations need privileges.
1017          */
1018         if (cred->lc_root_flags) {
1019                 inst_keyring = 0;
1020         } else {
1021                 inst_keyring = KEY_SPEC_USER_KEYRING;
1022                 /* fork to not change identity in main process */
1023                 rc = fork_and_switch_id(uid, &child);
1024                 if (rc || child)
1025                         goto out;
1026         }
1027
1028         /* if dealing with a user key, grant user write permission,
1029          * it will be required for key update
1030          */
1031         if (child == 0) {
1032                 key_perm_t perm;
1033
1034                 perm = KEY_POS_VIEW | KEY_POS_WRITE | KEY_POS_SEARCH |
1035                         KEY_POS_LINK | KEY_POS_SETATTR |
1036                         KEY_USR_VIEW | KEY_USR_WRITE;
1037                 if (keyctl_setperm(keyid, perm))
1038                         logmsg(LL_ERR, "setperm %08x on key %08x: %s\n",
1039                                perm, keyid, strerror(errno));
1040         }
1041
1042         rc = keyctl_instantiate(keyid, NULL, 0, inst_keyring);
1043         if (rc) {
1044                 rc = errno;
1045                 logmsg(LL_ERR, "instantiate key %08x in keyring id %d: %s\n",
1046                        keyid, inst_keyring, strerror(rc));
1047         } else {
1048                 logmsg(LL_TRACE,
1049                        "instantiated kernel key %08x in keyring id %d\n",
1050                        keyid, inst_keyring);
1051         }
1052
1053 out:
1054         if (child == 0)
1055                 /* job done for child */
1056                 exit(rc);
1057         return prepared ? rc : 1;
1058 }
1059
1060 /****************************************
1061  * main process                         *
1062  ****************************************/
1063
1064 int main(int argc, char *argv[])
1065 {
1066         struct keyring_upcall_param uparam;
1067         key_serial_t keyid;
1068         key_serial_t sring;
1069         pid_t child;
1070         int req_fd[2] = { -1, -1 };
1071         int reply_fd[2] = { -1, -1 };
1072         struct lgss_mech_type *mech;
1073         struct lgss_cred *cred;
1074         char path[PATH_MAX] = "";
1075         int other_ns = 0;
1076         int rc = 0, opt;
1077         struct stat parent_ns = { .st_ino = 0 };
1078         struct stat caller_ns = { .st_ino = 0 };
1079
1080         static struct option long_opts[] = {
1081                 { .name = "realm", .has_arg = required_argument, .val = 'R'},
1082                 { .name = NULL, } };
1083
1084         set_log_level();
1085
1086         logmsg(LL_TRACE, "start parsing parameters\n");
1087
1088         /* one possible option before upcall parameters: -R REALM */
1089         while ((opt = getopt_long(argc, argv, "R:", long_opts, NULL)) != EOF) {
1090                 switch (opt) {
1091                 case 'R':
1092                         lgss_client_realm = optarg;
1093                         break;
1094                 default:
1095                         logmsg(LL_ERR, "invalid parameter %s\n",
1096                                argv[optind - 1]);
1097                         return 1;
1098                 }
1099         }
1100
1101         if (lgss_client_realm) {
1102                 /* shift args to meet expected upcall parameters */
1103                 argc -= optind - 1;
1104                 argv += optind - 1;
1105         }
1106
1107         /*
1108          * parse & sanity check upcall parameters
1109          * expected to be called with:
1110          * [1]:  operation
1111          * [2]:  key ID
1112          * [3]:  key type
1113          * [4]:  key description
1114          * [5]:  call out info
1115          * [6]:  UID
1116          * [7]:  GID
1117          * [8]:  thread keyring
1118          * [9]:  process keyring
1119          * [10]: session keyring
1120          */
1121         if (argc != 10 + 1) {
1122                 logmsg(LL_ERR, "invalid parameter number %d\n", argc);
1123                 return 1;
1124         }
1125
1126         memset(&uparam, 0, sizeof(uparam));
1127
1128         if (strcmp(argv[1], "create") != 0) {
1129                 logmsg(LL_ERR,
1130                        "invalid OP %s (key %s, desc %s, ugid %s:%s, sring %s, coinfo %s)\n",
1131                        argv[1], argv[2], argv[4], argv[6], argv[7], argv[10],
1132                        argv[5]);
1133                 return 1;
1134         }
1135
1136         if (sscanf(argv[2], "%d", &keyid) != 1) {
1137                 logmsg(LL_ERR,
1138                        "can't extract KeyID: %s (key %s, desc %s, ugid %s:%s, sring %s, coinfo %s)\n",
1139                        argv[2], argv[2], argv[4], argv[6], argv[7], argv[10],
1140                        argv[5]);
1141                 return 1;
1142         }
1143
1144         logmsg(LL_INFO, "key %08x, desc %s, ugid %s:%s, sring %s, coinfo %s\n",
1145                keyid, argv[4], argv[6], argv[7], argv[10], argv[5]);
1146
1147         if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) {
1148                 logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]);
1149                 return 1;
1150         }
1151
1152         if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) {
1153                 logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]);
1154                 return 1;
1155         }
1156
1157         if (sscanf(argv[10], "%d", &sring) != 1) {
1158                 logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]);
1159                 return 1;
1160         }
1161
1162         if (parse_callout_info(argv[5], &uparam)) {
1163                 logmsg(LL_ERR, "can't extract callout info: %s\n", argv[5]);
1164                 return 1;
1165         }
1166
1167         logmsg(LL_TRACE, "parsing parameters OK\n");
1168
1169         /*
1170          * prepare a cred
1171          */
1172         mech = lgss_name2mech(uparam.kup_mech);
1173         if (mech == NULL) {
1174                 logmsg(LL_ERR, "key %08x: unsupported mech: %s\n",
1175                        keyid, uparam.kup_mech);
1176                 return 1;
1177         }
1178
1179         if (lgss_mech_initialize(mech)) {
1180                 logmsg(LL_ERR, "key %08x: can't initialize mech %s\n",
1181                        keyid, mech->lmt_name);
1182                 return 1;
1183         }
1184
1185         cred = lgss_create_cred(mech);
1186         if (cred == NULL) {
1187                 logmsg(LL_ERR, "key %08x: can't create a new %s cred\n",
1188                        keyid, mech->lmt_name);
1189                 return 1;
1190         }
1191
1192         cred->lc_uid = uparam.kup_uid;
1193         cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0;
1194         cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0;
1195         cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0;
1196         cred->lc_tgt_nid = uparam.kup_nid;
1197         cred->lc_tgt_svc = uparam.kup_svc;
1198         cred->lc_tgt_uuid = uparam.kup_tgt;
1199         cred->lc_svc_type = uparam.kup_svc_type;
1200         cred->lc_self_nid = uparam.kup_selfnid;
1201
1202         /* Is caller in different namespace? */
1203         /* If passed caller's pid is 0, it means we have to stick
1204          * with current namespace.
1205          */
1206         if (uparam.kup_pid) {
1207                 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", getpid());
1208                 if (stat(path, &parent_ns)) {
1209                         logmsg(LL_DEBUG, "cannot stat %s: %s\n",
1210                                path, strerror(errno));
1211                 } else {
1212                         snprintf(path, sizeof(path), "/proc/%d/ns/mnt",
1213                                  uparam.kup_pid);
1214                         if (stat(path, &caller_ns))
1215                                 logmsg(LL_DEBUG, "cannot stat %s: %s\n",
1216                                        path, strerror(errno));
1217                         else if (caller_ns.st_ino != parent_ns.st_ino)
1218                                 other_ns = 1;
1219                 }
1220         }
1221
1222         /*
1223          * if caller's namespace is different, fork a child and associate it
1224          * with caller's namespace to do credentials preparation
1225          */
1226         if (other_ns) {
1227                 logmsg(LL_TRACE, "caller's namespace is different\n");
1228
1229                 /* use pipes to pass info between child and parent processes */
1230                 if (pipe(req_fd) == -1) {
1231                         logmsg(LL_ERR, "key %08x: pipe failed: %s\n",
1232                                keyid, strerror(errno));
1233                         return 1;
1234                 }
1235                 if (pipe(reply_fd) == -1) {
1236                         logmsg(LL_ERR, "key %08x: pipe failed: %s\n",
1237                                keyid, strerror(errno));
1238                         return 1;
1239                 }
1240
1241                 child = fork();
1242                 if (child == -1) {
1243                         logmsg(LL_ERR, "key %08x: can't create child: %s\n",
1244                                keyid, strerror(errno));
1245                         rc = 1;
1246                         goto out_pipe;
1247                 } else if (child == 0) {
1248                         int rc2;
1249                         /* child process: carry out credentials preparation
1250                          * in caller's namespace */
1251
1252                         close(req_fd[0]); /* close unsed read end */
1253                         req_fd[0] = -1;
1254                         close(reply_fd[1]); /* close unsed write end */
1255                         reply_fd[1] = -1;
1256
1257                         if (associate_with_ns(path) != 0) {
1258                                 logmsg(LL_ERR,
1259                                        "failed to attach to pid %d namespace: "
1260                                        "%s\n", uparam.kup_pid, strerror(errno));
1261                                 rc = 1;
1262                                 goto out_pipe;
1263                         }
1264                         logmsg(LL_TRACE, "working in namespace of pid %d\n",
1265                                uparam.kup_pid);
1266
1267                         rc = prepare_and_instantiate(cred, keyid,
1268                                                      uparam.kup_uid);
1269
1270                         /* send to parent the status of credentials preparation
1271                          * and key instantiation */
1272                         rc2 = send_to(req_fd[1], &rc, sizeof(rc));
1273                         rc = (rc == 0 ? rc2 : rc);
1274                         if (rc != 0)
1275                                 goto out_pipe;
1276
1277                         /* now do real gss negotiation
1278                          * parent main process will not wait for us,
1279                          * as it has to be done in the background */
1280                         rc = lgssc_kr_negotiate(keyid, cred, &uparam,
1281                                                 req_fd, reply_fd);
1282                         goto out_pipe;
1283                 } else {
1284                         int rc2;
1285                         /* parent process: exchange info with child carrying out
1286                          * credentials preparation */
1287
1288                         close(req_fd[1]); /* close unsed write end */
1289                         req_fd[1] = -1;
1290                         close(reply_fd[0]); /* close unsed read end */
1291                         reply_fd[0] = -1;
1292
1293                         /* get status of credentials preparation
1294                          * and key instantiation */
1295                         rc2 = receive_from(req_fd[0], &rc, sizeof(rc));
1296                         if (rc2 != 0 || rc != 0) {
1297                                 logmsg(LL_ERR, "child failed preparing creds: "
1298                                        "%s\n",
1299                                        rc2 != 0 ? strerror(-rc2)
1300                                                 : strerror(rc));
1301                                 goto out_pipe;
1302                         }
1303
1304                         /*
1305                          * fork a child here to participate in gss negotiation,
1306                          * as it has to be done in the background
1307                          */
1308                         child = fork();
1309                         if (child == -1) {
1310                                 logmsg(LL_ERR,
1311                                        "key %08x: can't create child: %s\n",
1312                                        keyid, strerror(errno));
1313                                 rc = 1;
1314                                 goto out_pipe;
1315                         } else if (child == 0) {
1316                                 struct lgssd_ioctl_param param;
1317                                 char outbuf[8192] = { 0 };
1318                                 void *gss_token = NULL;
1319
1320                                 /* get ioctl buffer from child */
1321                                 rc = receive_from(req_fd[0], &param,
1322                                                   sizeof(param));
1323                                 if (rc != 0)
1324                                         goto out_pipe;
1325
1326                                 gss_token = calloc(1, param.send_token_size);
1327                                 if (gss_token == NULL)
1328                                         goto out_pipe;
1329
1330                                 /* get gss token from child */
1331                                 rc = receive_from(req_fd[0], gss_token,
1332                                                   param.send_token_size);
1333                                 if (rc != 0)
1334                                         goto out_token;
1335
1336                                 param.send_token = (char *)gss_token;
1337                                 param.reply_buf_size = sizeof(outbuf);
1338                                 param.reply_buf = outbuf;
1339
1340                                 /* do ioctl in place of child process carrying
1341                                  * out credentials negotiation: as it runs in
1342                                  * a container, it might not be able to
1343                                  * perform ioctl */
1344                                 rc = gss_do_ioctl(&param);
1345                                 if (rc != 0)
1346                                         goto out_token;
1347
1348                                 /* send ioctl status to child */
1349                                 rc = send_to(reply_fd[1], &param.status,
1350                                              sizeof(param.status));
1351                                 if (rc != 0)
1352                                         goto out_token;
1353                                 /* send reply buffer to child */
1354                                 rc = send_to(reply_fd[1], outbuf,
1355                                              sizeof(outbuf));
1356                                 if (rc != 0)
1357                                         goto out_token;
1358
1359 out_token:
1360                                 free(gss_token);
1361                                 goto out_pipe;
1362                         }
1363
1364                         logmsg(LL_TRACE, "forked child %d\n", child);
1365                 }
1366 out_pipe:
1367                 close(req_fd[0]);
1368                 close(req_fd[1]);
1369                 close(reply_fd[0]);
1370                 close(reply_fd[1]);
1371                 lgss_fini(cred);
1372                 return rc;
1373         } else {
1374                 if (uparam.kup_pid)
1375                         logmsg(LL_TRACE, "caller's namespace is the same\n");
1376                 else
1377                         logmsg(LL_TRACE, "stick with current namespace\n");
1378
1379                 /* In case of prepare error, a key will be instantiated
1380                  * all the same. But then we will have to error this key
1381                  * instead of doing normal gss negotiation.
1382                  */
1383                 rc = prepare_and_instantiate(cred, keyid, uparam.kup_uid);
1384
1385                 /*
1386                  * fork a child to do the real gss negotiation
1387                  */
1388                 child = fork();
1389                 if (child == -1) {
1390                         logmsg(LL_ERR, "key %08x: can't create child: %s\n",
1391                                keyid, strerror(errno));
1392                         rc = 1;
1393                         goto out_reg;
1394                 } else if (child == 0) {
1395                         if (rc)
1396                                 rc = error_kernel_key(keyid, -ENOKEY, 0,
1397                                                       cred->lc_uid);
1398                         else
1399                                 rc = lgssc_kr_negotiate(keyid, cred, &uparam,
1400                                                         req_fd, reply_fd);
1401                         goto out_reg;
1402                 } else {
1403                         logmsg(LL_TRACE, "forked child %d\n", child);
1404                         return 0;
1405                 }
1406
1407 out_reg:
1408                 lgss_fini(cred);
1409                 return rc;
1410         }
1411 }