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