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