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