Whamcloud - gitweb
LU-5030 utils: migrate most lustre utils to use cfs_get_paths()
[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         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_tgt[64];
111         char            kup_mech[16];
112         unsigned int    kup_is_root:1,
113                         kup_is_mdt:1,
114                         kup_is_ost:1;
115 };
116
117 /****************************************
118  * child process: gss negotiation       *
119  ****************************************/
120
121 int do_nego_rpc(struct lgss_nego_data *lnd,
122                 gss_buffer_desc *gss_token,
123                 struct lgss_init_res *gr)
124 {
125         struct lgssd_ioctl_param param;
126         struct passwd *pw;
127         int fd, ret, res;
128         char outbuf[8192];
129         unsigned int *p;
130         glob_t path;
131         int rc;
132
133         logmsg(LL_TRACE, "start negotiation rpc\n");
134
135         pw = getpwuid(lnd->lnd_uid);
136         if (!pw) {
137                 logmsg(LL_ERR, "no uid %u in local user database\n",
138                        lnd->lnd_uid);
139                 return -EACCES;
140         }
141
142         param.version = GSSD_INTERFACE_VERSION;
143         param.secid = lnd->lnd_secid;
144         param.uuid = lnd->lnd_uuid;
145         param.lustre_svc = lnd->lnd_lsvc;
146         param.uid = lnd->lnd_uid;
147         param.gid = pw->pw_gid;
148         param.send_token_size = gss_token->length;
149         param.send_token = (char *) gss_token->value;
150         param.reply_buf_size = sizeof(outbuf);
151         param.reply_buf = outbuf;
152
153         rc = cfs_get_param_paths(&path, "sptlrpc/gss/init_channel");
154         if (rc != 0)
155                 return rc;
156
157         logmsg(LL_TRACE, "to open %s\n", path.gl_pathv[0]);
158
159         fd = open(path.gl_pathv[0], O_WRONLY);
160         if (fd < 0) {
161                 logmsg(LL_ERR, "can't open %s\n", path.gl_pathv[0]);
162                 rc = -EACCES;
163                 goto out_params;
164         }
165
166         logmsg(LL_TRACE, "to down-write\n");
167
168         ret = write(fd, &param, sizeof(param));
169         close(fd);
170         if (ret != sizeof(param)) {
171                 logmsg(LL_ERR, "lustre ioctl err: %s\n", strerror(errno));
172                 rc = -EACCES;
173                 goto out_params;
174         }
175
176         logmsg(LL_TRACE, "do_nego_rpc: to parse reply\n");
177         if (param.status) {
178                 logmsg(LL_ERR, "status: %ld (%s)\n",
179                        param.status, strerror((int)param.status));
180
181                 /* kernel return -ETIMEDOUT means the rpc timedout, we should
182                  * notify the caller to reinitiate the gss negotiation, by
183                  * returning -ERESTART
184                  */
185                 if (param.status == -ETIMEDOUT)
186                         rc = -ERESTART;
187                 else
188                         rc = param.status;
189                 goto out_params;
190         }
191
192         p = (unsigned int *)outbuf;
193         res = *p++;
194         gr->gr_major = *p++;
195         gr->gr_minor = *p++;
196         gr->gr_win = *p++;
197
198         gr->gr_ctx.length = *p++;
199         gr->gr_ctx.value = malloc(gr->gr_ctx.length);
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         memcpy(gr->gr_token.value, p, gr->gr_token.length);
206         p += (((gr->gr_token.length + 3) & ~3) / 4);
207
208         logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %zu, token len %zu, "
209                "res %d\n", gr->gr_ctx.length, gr->gr_token.length, res);
210 out_params:
211         cfs_free_param_data(&path);
212         return rc;
213 }
214
215 /*
216  * if return error, the lnd_rpc_err or lnd_gss_err is set.
217  */
218 static int lgssc_negotiation(struct lgss_nego_data *lnd)
219 {
220         struct lgss_init_res    gr;
221         gss_buffer_desc        *recv_tokenp, send_token;
222         OM_uint32               maj_stat, min_stat, ret_flags;
223
224         logmsg(LL_TRACE, "start gss negotiation\n");
225
226         /* GSS context establishment loop. */
227         memset(&gr, 0, sizeof(gr));
228         recv_tokenp = GSS_C_NO_BUFFER;
229
230         for (;;) {
231                 maj_stat = gss_init_sec_context(&min_stat,
232                                                 lnd->lnd_cred,
233                                                 &lnd->lnd_ctx,
234                                                 lnd->lnd_svc_name,
235                                                 lnd->lnd_mech,
236                                                 lnd->lnd_req_flags,
237                                                 0,            /* time req */
238                                                 NULL,         /* channel */
239                                                 recv_tokenp,
240                                                 NULL,         /* used mech */
241                                                 &send_token,
242                                                 &ret_flags,
243                                                 NULL);        /* time rec */
244
245                 if (recv_tokenp != GSS_C_NO_BUFFER) {
246                         gss_release_buffer(&min_stat, &gr.gr_token);
247                         recv_tokenp = GSS_C_NO_BUFFER;
248                 }
249
250                 if (maj_stat != GSS_S_COMPLETE &&
251                     maj_stat != GSS_S_CONTINUE_NEEDED) {
252                         lnd->lnd_gss_err = maj_stat;
253
254                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
255                                    "failed init context");
256                         break;
257                 }
258
259                 if (send_token.length != 0) {
260                         memset(&gr, 0, sizeof(gr));
261
262                         lnd->lnd_rpc_err = do_nego_rpc(lnd, &send_token, &gr);
263                         gss_release_buffer(&min_stat, &send_token);
264
265                         if (lnd->lnd_rpc_err) {
266                                 logmsg(LL_ERR, "negotiation rpc error: %d\n",
267                                        lnd->lnd_rpc_err);
268                                 return -1;
269                         }
270
271                         if (gr.gr_major != GSS_S_COMPLETE &&
272                             gr.gr_major != GSS_S_CONTINUE_NEEDED) {
273                                 lnd->lnd_gss_err = gr.gr_major;
274
275                                 logmsg(LL_ERR, "negotiation gss error %x\n",
276                                        lnd->lnd_gss_err);
277                                 return -1;
278                         }
279
280                         if (gr.gr_ctx.length != 0) {
281                                 if (lnd->lnd_rmt_ctx.value)
282                                         gss_release_buffer(&min_stat,
283                                                            &lnd->lnd_rmt_ctx);
284                                 lnd->lnd_rmt_ctx = gr.gr_ctx;
285                         }
286
287                         if (gr.gr_token.length != 0) {
288                                 if (maj_stat != GSS_S_CONTINUE_NEEDED)
289                                         break;
290                                 recv_tokenp = &gr.gr_token;
291                         }
292                 }
293
294                 /* GSS_S_COMPLETE => check gss header verifier,
295                  * usually checked in gss_validate
296                  */
297                 if (maj_stat == GSS_S_COMPLETE) {
298                         lnd->lnd_established = 1;
299                         lnd->lnd_seq_win = gr.gr_win;
300                         break;
301                 }
302         }
303
304         /* End context negotiation loop. */
305         if (!lnd->lnd_established) {
306                 if (gr.gr_token.length != 0)
307                         gss_release_buffer(&min_stat, &gr.gr_token);
308
309                 if (lnd->lnd_gss_err == GSS_S_COMPLETE)
310                         lnd->lnd_rpc_err = -EACCES;
311
312                 logmsg(LL_ERR, "context negotiation failed\n");
313                 return -1;
314         }
315
316         logmsg(LL_DEBUG, "successfully negotiated a context\n");
317         return 0;
318 }
319
320 /*
321  * if return error, the lnd_rpc_err or lnd_gss_err is set.
322  */
323 static int lgssc_init_nego_data(struct lgss_nego_data *lnd,
324                                 struct keyring_upcall_param *kup,
325                                 lgss_mech_t mech)
326 {
327         gss_buffer_desc         sname;
328         OM_uint32               maj_stat, min_stat;
329
330         memset(lnd, 0, sizeof(*lnd));
331
332         lnd->lnd_secid = kup->kup_secid;
333         lnd->lnd_uid = kup->kup_uid;
334         lnd->lnd_lsvc = kup->kup_svc;
335         lnd->lnd_uuid = kup->kup_tgt;
336
337         lnd->lnd_established = 0;
338         lnd->lnd_svc_name = GSS_C_NO_NAME;
339         lnd->lnd_cred = GSS_C_NO_CREDENTIAL;
340         lnd->lnd_ctx = GSS_C_NO_CONTEXT;
341         lnd->lnd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
342         lnd->lnd_seq_win = 0;
343
344         switch (mech) {
345         case LGSS_MECH_KRB5:
346                 lnd->lnd_mech = (gss_OID) &krb5oid;
347                 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
348                 break;
349         default:
350                 logmsg(LL_ERR, "invalid mech: %d\n", mech);
351                 lnd->lnd_rpc_err = -EACCES;
352                 return -1;
353         }
354
355         sname.value = g_service;
356         sname.length = strlen(g_service);
357
358         maj_stat = gss_import_name(&min_stat, &sname,
359                                    (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
360                                    &lnd->lnd_svc_name);
361         if (maj_stat != GSS_S_COMPLETE) {
362                 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
363                            "can't import svc name");
364                 lnd->lnd_gss_err = maj_stat;
365                 return -1;
366         }
367
368         return 0;
369 }
370
371 void lgssc_fini_nego_data(struct lgss_nego_data *lnd)
372 {
373         OM_uint32       maj_stat, min_stat;
374
375         if (lnd->lnd_svc_name != GSS_C_NO_NAME) {
376                 maj_stat = gss_release_name(&min_stat, &lnd->lnd_svc_name);
377                 if (maj_stat != GSS_S_COMPLETE)
378                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
379                                    "can't release service name");
380         }
381
382         if (lnd->lnd_cred != GSS_C_NO_CREDENTIAL) {
383                 maj_stat = gss_release_cred(&min_stat, &lnd->lnd_cred);
384                 if (maj_stat != GSS_S_COMPLETE)
385                         logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
386                                    "can't release credential");
387         }
388 }
389
390 static
391 int error_kernel_key(key_serial_t keyid, int rpc_error, int gss_error)
392 {
393         int      seqwin = 0;
394         char     buf[32];
395         char    *p, *end;
396
397         logmsg(LL_TRACE, "revoking kernel key %08x\n", keyid);
398
399         p = buf;
400         end = buf + sizeof(buf);
401
402         WRITE_BYTES(&p, end, seqwin);
403         WRITE_BYTES(&p, end, rpc_error);
404         WRITE_BYTES(&p, end, gss_error);
405
406 again:
407         if (keyctl_update(keyid, buf, p - buf)) {
408                 if (errno != EAGAIN) {
409                         logmsg(LL_ERR, "revoke key %08x: %s\n",
410                                keyid, strerror(errno));
411                         return -1;
412                 }
413
414                 logmsg(LL_WARN, "key %08x: revoking too soon, try again\n",
415                        keyid);
416                 sleep(2);
417                 goto again;
418         }
419
420         logmsg(LL_INFO, "key %08x: revoked\n", keyid);
421         return 0;
422 }
423
424 static
425 int update_kernel_key(key_serial_t keyid,
426                       struct lgss_nego_data *lnd,
427                       gss_buffer_desc *ctx_token)
428 {
429         char        *buf = NULL, *p = NULL, *end = NULL;
430         unsigned int buf_size = 0;
431         int          rc;
432
433         logmsg(LL_TRACE, "updating kernel key %08x\n", keyid);
434
435         buf_size = sizeof(lnd->lnd_seq_win) +
436                    sizeof(lnd->lnd_rmt_ctx.length) + lnd->lnd_rmt_ctx.length +
437                    sizeof(ctx_token->length) + ctx_token->length;
438         buf = malloc(buf_size);
439         if (buf == NULL) {
440                 logmsg(LL_ERR, "key %08x: can't alloc update buf: size %d\n",
441                        keyid, buf_size);
442                 return 1;
443         }
444
445         p = buf;
446         end = buf + buf_size;
447         rc = -1;
448
449         if (WRITE_BYTES(&p, end, lnd->lnd_seq_win))
450                 goto out;
451         if (write_buffer(&p, end, &lnd->lnd_rmt_ctx))
452                 goto out;
453         if (write_buffer(&p, end, ctx_token))
454                 goto out;
455
456 again:
457         if (keyctl_update(keyid, buf, p - buf)) {
458                 if (errno != EAGAIN) {
459                         logmsg(LL_ERR, "update key %08x: %s\n",
460                                keyid, strerror(errno));
461                         goto out;
462                 }
463
464                 logmsg(LL_DEBUG, "key %08x: updating too soon, try again\n",
465                        keyid);
466                 sleep(2);
467                 goto again;
468         }
469
470         rc = 0;
471         logmsg(LL_DEBUG, "key %08x: updated\n", keyid);
472 out:
473         free(buf);
474         return rc;
475 }
476
477 /*
478  * note we inherited assumed authority from parent process
479  */
480 static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
481                               struct keyring_upcall_param *kup)
482 {
483         struct lgss_nego_data   lnd;
484         gss_buffer_desc         token = GSS_C_EMPTY_BUFFER;
485         OM_uint32               min_stat;
486         int                     rc = -1;
487
488         logmsg(LL_TRACE, "child start on behalf of key %08x: "
489                "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n",
490                keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
491                kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
492
493         if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
494                 logmsg(LL_ERR, "key %08x: failed to construct service "
495                        "string\n", keyid);
496                 error_kernel_key(keyid, -EACCES, 0);
497                 goto out_cred;
498         }
499
500         if (lgss_using_cred(cred)) {
501                 logmsg(LL_ERR, "key %08x: can't using cred\n", keyid);
502                 error_kernel_key(keyid, -EACCES, 0);
503                 goto out_cred;
504         }
505
506         if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) {
507                 logmsg(LL_ERR, "key %08x: failed to initialize "
508                        "negotiation data\n", keyid);
509                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
510                 goto out_cred;
511         }
512
513         rc = lgssc_negotiation(&lnd);
514         if (rc) {
515                 logmsg(LL_ERR, "key %08x: failed to negotiation\n", keyid);
516                 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
517                 goto out;
518         }
519
520         rc = serialize_context_for_kernel(lnd.lnd_ctx, &token, lnd.lnd_mech);
521         if (rc) {
522                 logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
523                 error_kernel_key(keyid, rc, lnd.lnd_gss_err);
524                 goto out;
525         }
526
527         rc = update_kernel_key(keyid,  &lnd, &token);
528         if (rc)
529                 goto out;
530
531         rc = 0;
532         logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
533                keyid, kup->kup_uid);
534 out:
535         if (token.length != 0)
536                 gss_release_buffer(&min_stat, &token);
537
538         lgssc_fini_nego_data(&lnd);
539
540 out_cred:
541         lgss_release_cred(cred);
542         return rc;
543 }
544
545 /*
546  * call out info format: s[:s]...
547  *  [0]: secid          (uint)
548  *  [1]: mech_name      (string)
549  *  [2]: uid            (uint)
550  *  [3]: gid            (uint)
551  *  [4]: flags          (string) FMT: r-root; m-mdt; o-ost
552  *  [5]: lustre_svc     (uint)
553  *  [6]: target_nid     (uint64)
554  *  [7]: target_uuid    (string)
555  *  [8]: self_nid        (uint64)
556  */
557 static int parse_callout_info(const char *coinfo,
558                               struct keyring_upcall_param *uparam)
559 {
560         const int       nargs = 9;
561         char            buf[1024];
562         char           *string = buf;
563         int             length, i;
564         char           *data[nargs];
565         char           *pos;
566
567         length = strlen(coinfo) + 1;
568         if (length > 1024) {
569                 logmsg(LL_ERR, "coinfo too long\n");
570                 return -1;
571         }
572         memcpy(buf, coinfo, length);
573
574         for (i = 0; i < nargs - 1; i++) {
575                 pos = strchr(string, ':');
576                 if (pos == NULL) {
577                         logmsg(LL_ERR, "short of components\n");
578                         return -1;
579                 }
580
581                 *pos = '\0';
582                 data[i] = string;
583                 string = pos + 1;
584         }
585         data[i] = string;
586
587         logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%s,%s,%s,%s\n",
588                data[0], data[1], data[2], data[3], data[4], data[5],
589                data[6], data[7], data[8]);
590
591         uparam->kup_secid = strtol(data[0], NULL, 0);
592         strlcpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech));
593         uparam->kup_uid = strtol(data[2], NULL, 0);
594         uparam->kup_gid = strtol(data[3], NULL, 0);
595         if (strchr(data[4], 'r'))
596                 uparam->kup_is_root = 1;
597         if (strchr(data[4], 'm'))
598                 uparam->kup_is_mdt = 1;
599         if (strchr(data[4], 'o'))
600                 uparam->kup_is_ost = 1;
601         uparam->kup_svc = strtol(data[5], NULL, 0);
602         uparam->kup_nid = strtoll(data[6], NULL, 0);
603         strlcpy(uparam->kup_tgt, data[7], sizeof(uparam->kup_tgt));
604         uparam->kup_selfnid = strtoll(data[8], NULL, 0);
605
606         logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, "
607                "is_root %d, is_mdt %d, is_ost %d, svc %d, nid 0x%"PRIx64", "
608                "tgt %s, self nid 0x%"PRIx64"\n",
609                uparam->kup_secid, uparam->kup_mech,
610                uparam->kup_uid, uparam->kup_gid,
611                uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
612                uparam->kup_svc, uparam->kup_nid, uparam->kup_tgt,
613                uparam->kup_selfnid);
614         return 0;
615 }
616
617 static void set_log_level()
618 {
619         unsigned int level;
620         glob_t path;
621         FILE *file;
622
623         if (cfs_get_param_paths(&path,
624                                 "sptlrpc/gss/lgss_keyring/debug_level") != 0)
625                 return;
626         file = fopen(path.gl_pathv[0], "r");
627         if (file == NULL) {
628                 cfs_free_param_data(&path);
629                 return;
630         }
631
632         if (fscanf(file, "%u", &level) != 1)
633                 goto out;
634
635         if (level >= LL_MAX)
636                 goto out;
637
638         lgss_set_loglevel(level);
639 out:
640         cfs_free_param_data(&path);
641         fclose(file);
642 }
643
644 /****************************************
645  * main process                         *
646  ****************************************/
647
648 int main(int argc, char *argv[])
649 {
650         struct keyring_upcall_param     uparam;
651         key_serial_t                    keyid;
652         key_serial_t                    sring;
653         key_serial_t                    inst_keyring;
654         pid_t                           child;
655         struct lgss_mech_type          *mech;
656         struct lgss_cred               *cred;
657
658         set_log_level();
659
660         logmsg(LL_TRACE, "start parsing parameters\n");
661         /*
662          * parse & sanity check upcall parameters
663          * expected to be called with:
664          * [1]:  operation
665          * [2]:  key ID
666          * [3]:  key type
667          * [4]:  key description
668          * [5]:  call out info
669          * [6]:  UID
670          * [7]:  GID
671          * [8]:  thread keyring
672          * [9]:  process keyring
673          * [10]: session keyring
674          */
675         if (argc != 10 + 1) {
676                 logmsg(LL_ERR, "invalid parameter number %d\n", argc);
677                 return 1;
678         }
679
680         logmsg(LL_INFO, "key %s, desc %s, ugid %s:%s, sring %s, coinfo %s\n",
681                argv[2], argv[4], argv[6], argv[7], argv[10], argv[5]);
682
683         memset(&uparam, 0, sizeof(uparam));
684
685         if (strcmp(argv[1], "create") != 0) {
686                 logmsg(LL_ERR, "invalid OP %s\n", argv[1]);
687                 return 1;
688         }
689
690         if (sscanf(argv[2], "%d", &keyid) != 1) {
691                 logmsg(LL_ERR, "can't extract KeyID: %s\n", argv[2]);
692                 return 1;
693         }
694
695         if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) {
696                 logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]);
697                 return 1;
698         }
699
700         if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) {
701                 logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]);
702                 return 1;
703         }
704
705         if (sscanf(argv[10], "%d", &sring) != 1) {
706                 logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]);
707                 return 1;
708         }
709
710         if (parse_callout_info(argv[5], &uparam)) {
711                 logmsg(LL_ERR, "can't extract callout info: %s\n", argv[5]);
712                 return 1;
713         }
714
715         logmsg(LL_TRACE, "parsing parameters OK\n");
716
717         /*
718          * prepare a cred
719          */
720         mech = lgss_name2mech(uparam.kup_mech);
721         if (mech == NULL) {
722                 logmsg(LL_ERR, "key %08x: unsupported mech: %s\n",
723                        keyid, uparam.kup_mech);
724                 return 1;
725         }
726
727         if (lgss_mech_initialize(mech)) {
728                 logmsg(LL_ERR, "key %08x: can't initialize mech %s\n",
729                        keyid, mech->lmt_name);
730                 return 1;
731         }
732
733         cred = lgss_create_cred(mech);
734         if (cred == NULL) {
735                 logmsg(LL_ERR, "key %08x: can't create a new %s cred\n",
736                        keyid, mech->lmt_name);
737                 return 1;
738         }
739
740         cred->lc_uid = uparam.kup_uid;
741         cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0;
742         cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0;
743         cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0;
744         cred->lc_tgt_nid = uparam.kup_nid;
745         cred->lc_tgt_svc = uparam.kup_svc;
746         cred->lc_self_nid = uparam.kup_selfnid;
747
748         if (lgss_prepare_cred(cred)) {
749                 logmsg(LL_ERR, "key %08x: failed to prepare credentials "
750                        "for user %d\n", keyid, uparam.kup_uid);
751                 return 1;
752         }
753
754         /* pre initialize the key. note the keyring linked to is actually of the
755          * original requesting process, not _this_ upcall process. if it's for
756          * root user, don't link to any keyrings because we want fully control
757          * on it, and share it among all root sessions; otherswise link to
758          * session keyring.
759          */
760         if (cred->lc_root_flags != 0)
761                 inst_keyring = 0;
762         else
763                 inst_keyring = KEY_SPEC_SESSION_KEYRING;
764
765         if (keyctl_instantiate(keyid, NULL, 0, inst_keyring)) {
766                 logmsg(LL_ERR, "instantiate key %08x: %s\n",
767                        keyid, strerror(errno));
768                 return 1;
769         }
770
771         logmsg(LL_TRACE, "instantiated kernel key %08x\n", keyid);
772
773         /*
774          * fork a child to do the real gss negotiation
775          */
776         child = fork();
777         if (child == -1) {
778                 logmsg(LL_ERR, "key %08x: can't create child: %s\n",
779                        keyid, strerror(errno));
780                 return 1;
781         } else if (child == 0) {
782                 return lgssc_kr_negotiate(keyid, cred, &uparam);
783         }
784
785         logmsg(LL_TRACE, "forked child %d\n", child);
786         return 0;
787 }