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