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