Whamcloud - gitweb
LU-3289 gss: Add userspace support for GSS null and sk
[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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2014, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/gss/lgss_keyring.c
37  *
38  * user-space upcall to create GSS context, using keyring interface to kernel
39  *
40  * Author: Eric Mei <ericm@clusterfs.com>
41  */
42
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <fcntl.h>
47 #include <inttypes.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <pwd.h>
51 #include <keyutils.h>
52 #include <gssapi/gssapi.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 };
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         case LGSS_MECH_SK:
426                 lnd->lnd_mech = (gss_OID)&skoid;
427                 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
428                 break;
429         default:
430                 logmsg(LL_ERR, "invalid mech: %d\n", mech);
431                 lnd->lnd_rpc_err = -EACCES;
432                 return -1;
433         }
434
435         sname.value = g_service;
436         sname.length = strlen(g_service);
437
438         maj_stat = gss_import_name(&min_stat, &sname,
439                                    (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
440                                    &lnd->lnd_svc_name);
441         if (maj_stat != GSS_S_COMPLETE) {
442                 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
443                            "can't import svc name");
444                 lnd->lnd_gss_err = maj_stat;
445                 return -1;
446         }
447
448         return 0;
449 }
450
451 void lgssc_fini_nego_data(struct lgss_nego_data *lnd)
452 {
453         OM_uint32       maj_stat, min_stat;
454
455         if (lnd->lnd_svc_name != GSS_C_NO_NAME) {
456                 maj_stat = gss_release_name(&min_stat, &lnd->lnd_svc_name);
457                 if (maj_stat != GSS_S_COMPLETE)
458                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
459                                    "can't release service name");
460         }
461
462         if (lnd->lnd_cred != GSS_C_NO_CREDENTIAL) {
463                 maj_stat = gss_release_cred(&min_stat, &lnd->lnd_cred);
464                 if (maj_stat != GSS_S_COMPLETE)
465                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
466                                    "can't release credential");
467         }
468 }
469
470 static
471 int error_kernel_key(key_serial_t keyid, int rpc_error, int gss_error)
472 {
473         int      seqwin = 0;
474         char     buf[32];
475         char    *p, *end;
476
477         logmsg(LL_TRACE, "revoking kernel key %08x\n", keyid);
478
479         p = buf;
480         end = buf + sizeof(buf);
481
482         WRITE_BYTES(&p, end, seqwin);
483         WRITE_BYTES(&p, end, rpc_error);
484         WRITE_BYTES(&p, end, gss_error);
485
486 again:
487         if (keyctl_update(keyid, buf, p - buf)) {
488                 if (errno != EAGAIN) {
489                         logmsg(LL_ERR, "revoke key %08x: %s\n",
490                                keyid, strerror(errno));
491                         return -1;
492                 }
493
494                 logmsg(LL_WARN, "key %08x: revoking too soon, try again\n",
495                        keyid);
496                 sleep(2);
497                 goto again;
498         }
499
500         logmsg(LL_INFO, "key %08x: revoked\n", keyid);
501         return 0;
502 }
503
504 static
505 int update_kernel_key(key_serial_t keyid,
506                       struct lgss_nego_data *lnd,
507                       gss_buffer_desc *ctx_token)
508 {
509         char        *buf = NULL, *p = NULL, *end = NULL;
510         unsigned int buf_size = 0;
511         int          rc;
512
513         logmsg(LL_TRACE, "updating kernel key %08x\n", keyid);
514
515         buf_size = sizeof(lnd->lnd_seq_win) +
516                    sizeof(lnd->lnd_rmt_ctx.length) + lnd->lnd_rmt_ctx.length +
517                    sizeof(ctx_token->length) + ctx_token->length;
518         buf = malloc(buf_size);
519         if (buf == NULL) {
520                 logmsg(LL_ERR, "key %08x: can't alloc update buf: size %d\n",
521                        keyid, buf_size);
522                 return 1;
523         }
524
525         p = buf;
526         end = buf + buf_size;
527         rc = -1;
528
529         if (WRITE_BYTES(&p, end, lnd->lnd_seq_win))
530                 goto out;
531         if (write_buffer(&p, end, &lnd->lnd_rmt_ctx))
532                 goto out;
533         if (write_buffer(&p, end, ctx_token))
534                 goto out;
535
536 again:
537         if (keyctl_update(keyid, buf, p - buf)) {
538                 if (errno != EAGAIN) {
539                         logmsg(LL_ERR, "update key %08x: %s\n",
540                                keyid, strerror(errno));
541                         goto out;
542                 }
543
544                 logmsg(LL_DEBUG, "key %08x: updating too soon, try again\n",
545                        keyid);
546                 sleep(2);
547                 goto again;
548         }
549
550         rc = 0;
551         logmsg(LL_DEBUG, "key %08x: updated\n", keyid);
552 out:
553         free(buf);
554         return rc;
555 }
556
557 static int lgssc_kr_negotiate_krb(key_serial_t keyid, struct lgss_cred *cred,
558                                   struct keyring_upcall_param *kup)
559 {
560         struct lgss_nego_data lnd;
561         OM_uint32 min_stat;
562         int rc = -1;
563
564         memset(&lnd, 0, sizeof(lnd));
565
566         if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
567                 logmsg(LL_ERR, "key %08x: failed to construct service "
568                        "string\n", keyid);
569                 error_kernel_key(keyid, -EACCES, 0);
570                 goto out_cred;
571         }
572
573         if (lgss_using_cred(cred)) {
574                 logmsg(LL_ERR, "key %08x: can't using cred\n", keyid);
575                 error_kernel_key(keyid, -EACCES, 0);
576                 goto out_cred;
577         }
578
579         if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) {
580                 logmsg(LL_ERR, "key %08x: failed to initialize "
581                        "negotiation data\n", keyid);
582                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
583                 goto out_cred;
584         }
585
586         rc = lgssc_negotiation(&lnd);
587         if (rc) {
588                 logmsg(LL_ERR, "key %08x: failed to negotiation\n", keyid);
589                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
590                 goto out;
591         }
592
593         rc = serialize_context_for_kernel(lnd.lnd_ctx, &lnd.lnd_ctx_token,
594                                           lnd.lnd_mech);
595         if (rc) {
596                 logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
597                 error_kernel_key(keyid, rc, lnd.lnd_gss_err);
598                 goto out;
599         }
600
601         rc = update_kernel_key(keyid,  &lnd, &lnd.lnd_ctx_token);
602         if (rc)
603                 goto out;
604
605         rc = 0;
606         logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
607                keyid, kup->kup_uid);
608 out:
609         if (lnd.lnd_ctx_token.length != 0)
610                 gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
611
612         lgssc_fini_nego_data(&lnd);
613
614 out_cred:
615         lgss_release_cred(cred);
616         return rc;
617 }
618
619 static int lgssc_kr_negotiate_manual(key_serial_t keyid, struct lgss_cred *cred,
620                                      struct keyring_upcall_param *kup)
621 {
622         struct lgss_nego_data   lnd;
623         OM_uint32               min_stat;
624         int                     rc;
625
626 retry:
627         memset(&lnd, 0, sizeof(lnd));
628
629         rc = lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid);
630         if (rc) {
631                 logmsg(LL_ERR, "key %08x: failed to construct service "
632                        "string\n", keyid);
633                 error_kernel_key(keyid, -EACCES, 0);
634                 goto out_cred;
635         }
636
637         rc = lgss_using_cred(cred);
638         if (rc) {
639                 logmsg(LL_ERR, "key %08x: can't use cred\n", keyid);
640                 error_kernel_key(keyid, -EACCES, 0);
641                 goto out_cred;
642         }
643
644         rc = lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n);
645         if (rc) {
646                 logmsg(LL_ERR, "key %08x: failed to initialize "
647                        "negotiation data\n", keyid);
648                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
649                 goto out_cred;
650         }
651
652         /*
653          * Handles the negotiation but then calls lgss_validate to make sure
654          * the token is valid.  It also populates the lnd_ctx_token for the
655          * update to the kernel key
656          */
657         rc = lgssc_negotiation_manual(&lnd, cred);
658         if (rc == -EAGAIN) {
659                 logmsg(LL_ERR, "Failed negotiation must retry\n");
660                 goto retry;
661
662         } else if (rc) {
663                 logmsg(LL_ERR, "key %08x: failed to negotiate\n", keyid);
664                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
665                 goto out;
666         }
667
668         rc = update_kernel_key(keyid,  &lnd, &lnd.lnd_ctx_token);
669         if (rc)
670                 goto out;
671
672         logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
673                keyid, kup->kup_uid);
674 out:
675         if (lnd.lnd_ctx_token.length != 0)
676                 gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
677
678         lgssc_fini_nego_data(&lnd);
679
680 out_cred:
681         lgss_release_cred(cred);
682         return rc;
683 }
684
685 /*
686  * note we inherited assumed authority from parent process
687  */
688 static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
689                               struct keyring_upcall_param *kup)
690 {
691         int rc;
692
693         logmsg(LL_TRACE, "child start on behalf of key %08x: "
694                "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n",
695                keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
696                kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
697
698         switch (cred->lc_mech->lmt_mech_n) {
699         case LGSS_MECH_NULL:
700         case LGSS_MECH_SK:
701                 rc = lgssc_kr_negotiate_manual(keyid, cred, kup);
702                 break;
703         case LGSS_MECH_KRB5:
704         default:
705                 rc = lgssc_kr_negotiate_krb(keyid, cred, kup);
706                 break;
707         }
708
709         return rc;
710 }
711
712 /*
713  * call out info format: s[:s]...
714  *  [0]: secid          (uint)
715  *  [1]: mech_name      (string)
716  *  [2]: uid            (uint)
717  *  [3]: gid            (uint)
718  *  [4]: flags          (string) FMT: r-root; m-mdt; o-ost
719  *  [5]: svc type       (char)
720  *  [6]: lustre_svc     (int)
721  *  [7]: target_nid     (uint64)
722  *  [8]: target_uuid    (string)
723  *  [9]: self_nid        (uint64)
724  */
725 static int parse_callout_info(const char *coinfo,
726                               struct keyring_upcall_param *uparam)
727 {
728         const int       nargs = 10;
729         char            buf[1024];
730         char           *string = buf;
731         int             length, i;
732         char           *data[nargs];
733         char           *pos;
734
735         length = strlen(coinfo) + 1;
736         if (length > 1024) {
737                 logmsg(LL_ERR, "coinfo too long\n");
738                 return -1;
739         }
740         memcpy(buf, coinfo, length);
741
742         for (i = 0; i < nargs - 1; i++) {
743                 pos = strchr(string, ':');
744                 if (pos == NULL) {
745                         logmsg(LL_ERR, "short of components\n");
746                         return -1;
747                 }
748
749                 *pos = '\0';
750                 data[i] = string;
751                 string = pos + 1;
752         }
753         data[i] = string;
754
755         logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s\n",
756                data[0], data[1], data[2], data[3], data[4], data[5][0],
757                data[6], data[7], data[8], data[9]);
758
759         uparam->kup_secid = strtol(data[0], NULL, 0);
760         strlcpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech));
761         uparam->kup_uid = strtol(data[2], NULL, 0);
762         uparam->kup_gid = strtol(data[3], NULL, 0);
763         if (strchr(data[4], 'r'))
764                 uparam->kup_is_root = 1;
765         if (strchr(data[4], 'm'))
766                 uparam->kup_is_mdt = 1;
767         if (strchr(data[4], 'o'))
768                 uparam->kup_is_ost = 1;
769         uparam->kup_svc_type = data[5][0];
770         uparam->kup_svc = strtol(data[6], NULL, 0);
771         uparam->kup_nid = strtoll(data[7], NULL, 0);
772         strlcpy(uparam->kup_tgt, data[8], sizeof(uparam->kup_tgt));
773         uparam->kup_selfnid = strtoll(data[9], NULL, 0);
774
775         logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, "
776                "is_root %d, is_mdt %d, is_ost %d, svc type %c, svc %d, "
777                "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64"\n",
778                uparam->kup_secid, uparam->kup_mech,
779                uparam->kup_uid, uparam->kup_gid,
780                uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
781                uparam->kup_svc_type, uparam->kup_svc, uparam->kup_nid,
782                uparam->kup_tgt, uparam->kup_selfnid);
783         return 0;
784 }
785
786 static void set_log_level()
787 {
788         unsigned int level;
789         glob_t path;
790         FILE *file;
791
792         if (cfs_get_param_paths(&path,
793                                 "sptlrpc/gss/lgss_keyring/debug_level") != 0)
794                 return;
795         file = fopen(path.gl_pathv[0], "r");
796         if (file == NULL) {
797                 cfs_free_param_data(&path);
798                 return;
799         }
800
801         if (fscanf(file, "%u", &level) != 1)
802                 goto out;
803
804         if (level >= LL_MAX)
805                 goto out;
806
807         lgss_set_loglevel(level);
808 out:
809         cfs_free_param_data(&path);
810         fclose(file);
811 }
812
813 /****************************************
814  * main process                         *
815  ****************************************/
816
817 int main(int argc, char *argv[])
818 {
819         struct keyring_upcall_param     uparam;
820         key_serial_t                    keyid;
821         key_serial_t                    sring;
822         key_serial_t                    inst_keyring;
823         pid_t                           child;
824         struct lgss_mech_type          *mech;
825         struct lgss_cred               *cred;
826
827         set_log_level();
828
829         logmsg(LL_TRACE, "start parsing parameters\n");
830         /*
831          * parse & sanity check upcall parameters
832          * expected to be called with:
833          * [1]:  operation
834          * [2]:  key ID
835          * [3]:  key type
836          * [4]:  key description
837          * [5]:  call out info
838          * [6]:  UID
839          * [7]:  GID
840          * [8]:  thread keyring
841          * [9]:  process keyring
842          * [10]: session keyring
843          */
844         if (argc != 10 + 1) {
845                 logmsg(LL_ERR, "invalid parameter number %d\n", argc);
846                 return 1;
847         }
848
849         logmsg(LL_INFO, "key %s, desc %s, ugid %s:%s, sring %s, coinfo %s\n",
850                argv[2], argv[4], argv[6], argv[7], argv[10], argv[5]);
851
852         memset(&uparam, 0, sizeof(uparam));
853
854         if (strcmp(argv[1], "create") != 0) {
855                 logmsg(LL_ERR, "invalid OP %s\n", argv[1]);
856                 return 1;
857         }
858
859         if (sscanf(argv[2], "%d", &keyid) != 1) {
860                 logmsg(LL_ERR, "can't extract KeyID: %s\n", argv[2]);
861                 return 1;
862         }
863
864         if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) {
865                 logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]);
866                 return 1;
867         }
868
869         if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) {
870                 logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]);
871                 return 1;
872         }
873
874         if (sscanf(argv[10], "%d", &sring) != 1) {
875                 logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]);
876                 return 1;
877         }
878
879         if (parse_callout_info(argv[5], &uparam)) {
880                 logmsg(LL_ERR, "can't extract callout info: %s\n", argv[5]);
881                 return 1;
882         }
883
884         logmsg(LL_TRACE, "parsing parameters OK\n");
885
886         /*
887          * prepare a cred
888          */
889         mech = lgss_name2mech(uparam.kup_mech);
890         if (mech == NULL) {
891                 logmsg(LL_ERR, "key %08x: unsupported mech: %s\n",
892                        keyid, uparam.kup_mech);
893                 return 1;
894         }
895
896         if (lgss_mech_initialize(mech)) {
897                 logmsg(LL_ERR, "key %08x: can't initialize mech %s\n",
898                        keyid, mech->lmt_name);
899                 return 1;
900         }
901
902         cred = lgss_create_cred(mech);
903         if (cred == NULL) {
904                 logmsg(LL_ERR, "key %08x: can't create a new %s cred\n",
905                        keyid, mech->lmt_name);
906                 return 1;
907         }
908
909         cred->lc_uid = uparam.kup_uid;
910         cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0;
911         cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0;
912         cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0;
913         cred->lc_tgt_nid = uparam.kup_nid;
914         cred->lc_tgt_svc = uparam.kup_svc;
915         cred->lc_tgt_uuid = uparam.kup_tgt;
916         cred->lc_svc_type = uparam.kup_svc_type;
917         cred->lc_self_nid = uparam.kup_selfnid;
918
919         if (lgss_prepare_cred(cred)) {
920                 logmsg(LL_ERR, "key %08x: failed to prepare credentials "
921                        "for user %d\n", keyid, uparam.kup_uid);
922                 return 1;
923         }
924
925         /* pre initialize the key. note the keyring linked to is actually of the
926          * original requesting process, not _this_ upcall process. if it's for
927          * root user, don't link to any keyrings because we want fully control
928          * on it, and share it among all root sessions; otherswise link to
929          * session keyring.
930          */
931         if (cred->lc_root_flags != 0)
932                 inst_keyring = 0;
933         else
934                 inst_keyring = KEY_SPEC_SESSION_KEYRING;
935
936         if (keyctl_instantiate(keyid, NULL, 0, inst_keyring)) {
937                 logmsg(LL_ERR, "instantiate key %08x: %s\n",
938                        keyid, strerror(errno));
939                 return 1;
940         }
941
942         logmsg(LL_TRACE, "instantiated kernel key %08x\n", keyid);
943
944         /*
945          * fork a child to do the real gss negotiation
946          */
947         child = fork();
948         if (child == -1) {
949                 logmsg(LL_ERR, "key %08x: can't create child: %s\n",
950                        keyid, strerror(errno));
951                 return 1;
952         } else if (child == 0) {
953                 return lgssc_kr_negotiate(keyid, cred, &uparam);
954         }
955
956         logmsg(LL_TRACE, "forked child %d\n", child);
957         return 0;
958 }