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