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