4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2011, Intel Corporation.
29 * This file is part of Lustre, http://www.lustre.org/
30 * Lustre is a trademark of Sun Microsystems, Inc.
32 * lustre/utils/gss/lgss_keyring.c
34 * user-space upcall to create GSS context, using keyring interface to kernel
36 * Author: Eric Mei <ericm@clusterfs.com>
40 #include <sys/types.h>
51 #include <gssapi/gssapi.h>
54 #include <libcfs/util/param.h>
55 #include <libcfs/util/string.h>
57 #include "lgss_utils.h"
58 #include "write_bytes.h"
62 * gss target string of lustre service we are negotiating for
64 static char *g_service = NULL;
67 * all data about negotiation
69 struct lgss_nego_data {
70 uint32_t lnd_established:1;
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 */
91 * context creation response
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 */
101 struct keyring_upcall_param {
110 uint64_t kup_selfnid;
114 unsigned int kup_is_root:1,
120 /****************************************
121 * child process: gss negotiation *
122 ****************************************/
124 static int send_to(int fd, const void *buf, size_t size)
128 sz = write(fd, buf, size);
130 logmsg(LL_ERR, "cannot send to GSS process: %s\n",
135 logmsg(LL_ERR, "short write sending to GSS process: %d/%d\n",
143 static int receive_from(int fd, void *buf, size_t size)
147 sz = read(fd, buf, size);
149 logmsg(LL_ERR, "cannot receive from GSS process: %s\n",
154 logmsg(LL_ERR, "short read receiving from GSS process: %d/%d\n",
162 static int gss_do_ioctl(struct lgssd_ioctl_param *param)
168 rc = cfs_get_param_paths(&path, "sptlrpc/gss/init_channel");
172 logmsg(LL_TRACE, "to open %s\n", path.gl_pathv[0]);
174 fd = open(path.gl_pathv[0], O_WRONLY);
176 logmsg(LL_ERR, "can't open %s\n", path.gl_pathv[0]);
181 logmsg(LL_TRACE, "to down-write\n");
183 ret = write(fd, param, sizeof(*param));
185 if (ret != sizeof(*param)) {
186 logmsg(LL_ERR, "lustre ioctl err: %s\n", strerror(errno));
191 cfs_free_param_data(&path);
195 int do_nego_rpc(struct lgss_nego_data *lnd,
196 gss_buffer_desc *gss_token,
197 struct lgss_init_res *gr,
198 int req_fd[2], int reply_fd[2])
200 struct lgssd_ioctl_param param;
203 char outbuf[8192] = { 0 };
207 logmsg(LL_TRACE, "start negotiation rpc\n");
209 pw = getpwuid(lnd->lnd_uid);
211 logmsg(LL_ERR, "no uid %u in local user database\n",
216 param.version = GSSD_INTERFACE_VERSION;
217 param.secid = lnd->lnd_secid;
218 param.uuid = lnd->lnd_uuid;
219 param.lustre_svc = lnd->lnd_lsvc;
220 param.uid = lnd->lnd_uid;
221 param.gid = pw->pw_gid;
222 param.send_token_size = gss_token->length;
223 param.send_token = (char *) gss_token->value;
225 if (req_fd[0] == -1 && reply_fd[0] == -1) {
226 /* we can do the ioctl directly */
227 param.reply_buf_size = sizeof(outbuf);
228 param.reply_buf = outbuf;
230 rc = gss_do_ioctl(¶m);
234 /* looks like we are running in a container,
235 * so we cannot do the ioctl ourselves: delegate to
236 * parent process running directly on host */
238 /* send ioctl buffer to parent */
239 rc = send_to(req_fd[1], ¶m, sizeof(param));
242 /* send gss token to parent */
243 rc = send_to(req_fd[1], gss_token->value, gss_token->length);
247 /* read ioctl status from parent */
248 rc = receive_from(reply_fd[0], ¶m.status,
249 sizeof(param.status));
253 if (param.status == 0) {
254 /* read reply buffer from parent */
255 rc = receive_from(reply_fd[0], outbuf, sizeof(outbuf));
261 logmsg(LL_TRACE, "do_nego_rpc: to parse reply\n");
263 logmsg(LL_ERR, "status: %ld (%s)\n",
264 param.status, strerror((int)(-param.status)));
268 p = (unsigned int *)outbuf;
274 gr->gr_ctx.length = *p++;
275 gr->gr_ctx.value = malloc(gr->gr_ctx.length);
276 if (gr->gr_ctx.value == NULL)
278 memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
279 p += (((gr->gr_ctx.length + 3) & ~3) / 4);
281 gr->gr_token.length = *p++;
282 gr->gr_token.value = malloc(gr->gr_token.length);
283 if (gr->gr_token.value == NULL) {
284 free(gr->gr_ctx.value);
287 memcpy(gr->gr_token.value, p, gr->gr_token.length);
288 p += (((gr->gr_token.length + 3) & ~3) / 4);
290 logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %zu, token len %zu, "
291 "res %d\n", gr->gr_ctx.length, gr->gr_token.length, res);
296 /* This is used by incomplete GSSAPI implementations that can't use
297 * gss_init_sec_context and will parse the token themselves (gssnull and sk).
298 * Callers should have cred->lc_mech_token pointing to a gss_buffer_desc
299 * token to send to the peer as part of the SEC_CTX_INIT operation. The return
300 * RPC's token with be in gr.gr_token which is validated using
301 * lgss_validate_cred. */
302 static int lgssc_negotiation_manual(struct lgss_nego_data *lnd,
303 struct lgss_cred *cred,
304 int req_fd[2], int reply_fd[2])
306 struct lgss_init_res gr;
310 logmsg(LL_TRACE, "starting gss negotation\n");
311 memset(&gr, 0, sizeof(gr));
313 lnd->lnd_rpc_err = do_nego_rpc(lnd, &cred->lc_mech_token, &gr,
315 if (lnd->lnd_rpc_err) {
316 logmsg(LL_ERR, "negotiation rpc error %d\n", lnd->lnd_rpc_err);
317 rc = lnd->lnd_rpc_err;
321 if (gr.gr_major == GSS_S_CONTINUE_NEEDED) {
325 } else if (gr.gr_major != GSS_S_COMPLETE) {
326 lnd->lnd_gss_err = gr.gr_major;
327 logmsg(LL_ERR, "negotiation gss error %x\n", lnd->lnd_gss_err);
332 if (gr.gr_ctx.length == 0 || gr.gr_token.length == 0) {
333 logmsg(LL_ERR, "zero length context or token received\n");
338 rc = lgss_validate_cred(cred, &gr.gr_token, &lnd->lnd_ctx_token);
340 logmsg(LL_ERR, "peer token failed validation\n");
344 lnd->lnd_established = 1;
345 lnd->lnd_seq_win = gr.gr_win;
346 lnd->lnd_rmt_ctx = gr.gr_ctx;
348 if (gr.gr_token.length != 0)
349 gss_release_buffer(&min_stat, &gr.gr_token);
351 logmsg(LL_DEBUG, "successfully negotiated a context\n");
355 if (gr.gr_ctx.length != 0)
356 gss_release_buffer(&min_stat, &gr.gr_ctx);
357 if (gr.gr_token.length != 0)
358 gss_release_buffer(&min_stat, &gr.gr_token);
364 * if return error, the lnd_rpc_err or lnd_gss_err is set.
366 static int lgssc_negotiation(struct lgss_nego_data *lnd, int req_fd[2],
369 struct lgss_init_res gr;
370 gss_buffer_desc *recv_tokenp, send_token;
371 OM_uint32 maj_stat, min_stat, ret_flags;
373 logmsg(LL_TRACE, "start gss negotiation\n");
375 /* GSS context establishment loop. */
376 memset(&gr, 0, sizeof(gr));
377 recv_tokenp = GSS_C_NO_BUFFER;
380 maj_stat = gss_init_sec_context(&min_stat,
389 NULL, /* used mech */
392 NULL); /* time rec */
394 if (recv_tokenp != GSS_C_NO_BUFFER) {
395 gss_release_buffer(&min_stat, &gr.gr_token);
396 recv_tokenp = GSS_C_NO_BUFFER;
399 if (maj_stat != GSS_S_COMPLETE &&
400 maj_stat != GSS_S_CONTINUE_NEEDED) {
401 lnd->lnd_gss_err = maj_stat;
403 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
404 "failed init context");
408 if (send_token.length != 0) {
409 memset(&gr, 0, sizeof(gr));
411 lnd->lnd_rpc_err = do_nego_rpc(lnd, &send_token, &gr,
413 gss_release_buffer(&min_stat, &send_token);
415 if (lnd->lnd_rpc_err) {
416 logmsg(LL_ERR, "negotiation rpc error: %d\n",
418 return lnd->lnd_rpc_err;
421 if (gr.gr_major != GSS_S_COMPLETE &&
422 gr.gr_major != GSS_S_CONTINUE_NEEDED) {
423 lnd->lnd_gss_err = gr.gr_major;
425 logmsg(LL_ERR, "negotiation gss error %x\n",
430 if (gr.gr_ctx.length != 0) {
431 if (lnd->lnd_rmt_ctx.value)
432 gss_release_buffer(&min_stat,
434 lnd->lnd_rmt_ctx = gr.gr_ctx;
437 if (gr.gr_token.length != 0) {
438 if (maj_stat != GSS_S_CONTINUE_NEEDED)
440 recv_tokenp = &gr.gr_token;
444 /* GSS_S_COMPLETE => check gss header verifier,
445 * usually checked in gss_validate
447 if (maj_stat == GSS_S_COMPLETE) {
448 lnd->lnd_established = 1;
449 lnd->lnd_seq_win = gr.gr_win;
454 /* End context negotiation loop. */
455 if (!lnd->lnd_established) {
456 if (gr.gr_token.length != 0)
457 gss_release_buffer(&min_stat, &gr.gr_token);
459 if (lnd->lnd_gss_err == GSS_S_COMPLETE)
460 lnd->lnd_rpc_err = -EACCES;
462 logmsg(LL_ERR, "context negotiation failed\n");
466 logmsg(LL_DEBUG, "successfully negotiated a context\n");
471 * if return error, the lnd_rpc_err or lnd_gss_err is set.
473 static int lgssc_init_nego_data(struct lgss_nego_data *lnd,
474 struct keyring_upcall_param *kup,
477 gss_buffer_desc sname;
478 OM_uint32 maj_stat, min_stat;
480 memset(lnd, 0, sizeof(*lnd));
482 lnd->lnd_secid = kup->kup_secid;
483 lnd->lnd_uid = kup->kup_uid;
484 lnd->lnd_lsvc = kup->kup_svc | mech << LUSTRE_GSS_MECH_SHIFT;
485 lnd->lnd_uuid = kup->kup_tgt;
487 lnd->lnd_established = 0;
488 lnd->lnd_svc_name = GSS_C_NO_NAME;
489 lnd->lnd_cred = GSS_C_NO_CREDENTIAL;
490 lnd->lnd_ctx = GSS_C_NO_CONTEXT;
491 lnd->lnd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
492 lnd->lnd_seq_win = 0;
496 lnd->lnd_mech = (gss_OID)&krb5oid;
497 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
500 lnd->lnd_mech = (gss_OID)&nulloid;
502 #ifdef HAVE_OPENSSL_SSK
504 lnd->lnd_mech = (gss_OID)&skoid;
505 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
509 logmsg(LL_ERR, "invalid mech: %d\n", mech);
510 lnd->lnd_rpc_err = -EACCES;
514 sname.value = g_service;
515 sname.length = strlen(g_service);
517 maj_stat = gss_import_name(&min_stat, &sname,
518 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
520 if (maj_stat != GSS_S_COMPLETE) {
521 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
522 "can't import svc name");
523 lnd->lnd_gss_err = maj_stat;
530 void lgssc_fini_nego_data(struct lgss_nego_data *lnd)
532 OM_uint32 maj_stat, min_stat;
534 if (lnd->lnd_svc_name != GSS_C_NO_NAME) {
535 maj_stat = gss_release_name(&min_stat, &lnd->lnd_svc_name);
536 if (maj_stat != GSS_S_COMPLETE)
537 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
538 "can't release service name");
541 if (lnd->lnd_cred != GSS_C_NO_CREDENTIAL) {
542 maj_stat = gss_release_cred(&min_stat, &lnd->lnd_cred);
543 if (maj_stat != GSS_S_COMPLETE)
544 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
545 "can't release credential");
550 int error_kernel_key(key_serial_t keyid, int rpc_error, int gss_error)
556 logmsg(LL_TRACE, "revoking kernel key %08x\n", keyid);
559 end = buf + sizeof(buf);
561 WRITE_BYTES(&p, end, seqwin);
562 WRITE_BYTES(&p, end, rpc_error);
563 WRITE_BYTES(&p, end, gss_error);
566 if (keyctl_update(keyid, buf, p - buf)) {
567 if (errno != EAGAIN) {
568 logmsg(LL_ERR, "revoke key %08x: %s\n",
569 keyid, strerror(errno));
573 logmsg(LL_WARN, "key %08x: revoking too soon, try again\n",
579 logmsg(LL_INFO, "key %08x: revoked\n", keyid);
584 int update_kernel_key(key_serial_t keyid,
585 struct lgss_nego_data *lnd,
586 gss_buffer_desc *ctx_token)
588 char *buf = NULL, *p = NULL, *end = NULL;
589 unsigned int buf_size = 0;
592 logmsg(LL_TRACE, "updating kernel key %08x\n", keyid);
594 buf_size = sizeof(lnd->lnd_seq_win) +
595 sizeof(lnd->lnd_rmt_ctx.length) + lnd->lnd_rmt_ctx.length +
596 sizeof(ctx_token->length) + ctx_token->length;
597 buf = malloc(buf_size);
599 logmsg(LL_ERR, "key %08x: can't alloc update buf: size %d\n",
605 end = buf + buf_size;
608 if (WRITE_BYTES(&p, end, lnd->lnd_seq_win))
610 if (write_buffer(&p, end, &lnd->lnd_rmt_ctx))
612 if (write_buffer(&p, end, ctx_token))
616 if (keyctl_update(keyid, buf, p - buf)) {
617 if (errno != EAGAIN) {
618 logmsg(LL_ERR, "update key %08x: %s\n",
619 keyid, strerror(errno));
623 logmsg(LL_DEBUG, "key %08x: updating too soon, try again\n",
630 logmsg(LL_DEBUG, "key %08x: updated\n", keyid);
636 static int lgssc_kr_negotiate_krb(key_serial_t keyid, struct lgss_cred *cred,
637 struct keyring_upcall_param *kup,
638 int req_fd[2], int reply_fd[2])
640 struct lgss_nego_data lnd;
645 if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
646 logmsg(LL_ERR, "key %08x: failed to construct service "
648 error_kernel_key(keyid, -EACCES, 0);
652 if (lgss_using_cred(cred)) {
653 logmsg(LL_ERR, "key %08x: can't using cred\n", keyid);
654 error_kernel_key(keyid, -EACCES, 0);
659 memset(&lnd, 0, sizeof(lnd));
660 if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) {
661 logmsg(LL_ERR, "key %08x: failed to initialize "
662 "negotiation data\n", keyid);
663 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
667 rc = lgssc_negotiation(&lnd, req_fd, reply_fd);
668 if (rc == -EAGAIN || (rc == -ETIMEDOUT && redo)) {
669 logmsg(LL_ERR, "Failed negotiation must retry\n");
673 logmsg(LL_ERR, "key %08x: failed to negotiation\n", keyid);
674 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
678 rc = serialize_context_for_kernel(lnd.lnd_ctx, &lnd.lnd_ctx_token,
681 logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
682 error_kernel_key(keyid, rc, lnd.lnd_gss_err);
686 rc = update_kernel_key(keyid, &lnd, &lnd.lnd_ctx_token);
691 logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
692 keyid, kup->kup_uid);
694 if (lnd.lnd_ctx_token.length != 0)
695 gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
697 lgssc_fini_nego_data(&lnd);
700 lgss_release_cred(cred);
704 static int lgssc_kr_negotiate_manual(key_serial_t keyid, struct lgss_cred *cred,
705 struct keyring_upcall_param *kup,
706 int req_fd[2], int reply_fd[2])
708 struct lgss_nego_data lnd;
713 rc = lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid);
715 logmsg(LL_ERR, "key %08x: failed to construct service "
717 error_kernel_key(keyid, -EACCES, 0);
721 rc = lgss_using_cred(cred);
723 logmsg(LL_ERR, "key %08x: can't use cred\n", keyid);
724 error_kernel_key(keyid, -EACCES, 0);
729 memset(&lnd, 0, sizeof(lnd));
730 rc = lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n);
732 logmsg(LL_ERR, "key %08x: failed to initialize "
733 "negotiation data\n", keyid);
734 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
739 * Handles the negotiation but then calls lgss_validate to make sure
740 * the token is valid. It also populates the lnd_ctx_token for the
741 * update to the kernel key
743 rc = lgssc_negotiation_manual(&lnd, cred, req_fd, reply_fd);
744 if (rc == -EAGAIN || (rc == -ETIMEDOUT && redo)) {
745 logmsg(LL_ERR, "Failed negotiation must retry\n");
749 logmsg(LL_ERR, "key %08x: failed to negotiate\n", keyid);
750 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err);
754 rc = update_kernel_key(keyid, &lnd, &lnd.lnd_ctx_token);
758 logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
759 keyid, kup->kup_uid);
761 if (lnd.lnd_ctx_token.length != 0)
762 gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
764 lgssc_fini_nego_data(&lnd);
767 lgss_release_cred(cred);
772 * note we inherited assumed authority from parent process
774 static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
775 struct keyring_upcall_param *kup,
776 int req_fd[2], int reply_fd[2])
780 logmsg(LL_TRACE, "child start on behalf of key %08x: "
781 "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n",
782 keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
783 kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
785 switch (cred->lc_mech->lmt_mech_n) {
788 rc = lgssc_kr_negotiate_manual(keyid, cred, kup,
793 rc = lgssc_kr_negotiate_krb(keyid, cred, kup, req_fd, reply_fd);
801 * call out info format: s[:s]...
803 * [1]: mech_name (string)
806 * [4]: flags (string) FMT: r-root; m-mdt; o-ost
807 * [5]: svc type (char)
808 * [6]: lustre_svc (int)
809 * [7]: target_nid (uint64)
810 * [8]: target_uuid (string)
811 * [9]: self_nid (uint64)
814 static int parse_callout_info(const char *coinfo,
815 struct keyring_upcall_param *uparam)
817 const int nargs = 11;
824 length = strlen(coinfo) + 1;
826 logmsg(LL_ERR, "coinfo too long\n");
829 memcpy(buf, coinfo, length);
831 for (i = 0; i < nargs - 1; i++) {
832 pos = strchr(string, ':');
834 logmsg(LL_ERR, "short of components\n");
844 logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s,%s\n",
845 data[0], data[1], data[2], data[3], data[4], data[5][0],
846 data[6], data[7], data[8], data[9], data[10]);
848 uparam->kup_secid = strtol(data[0], NULL, 0);
849 snprintf(uparam->kup_mech, sizeof(uparam->kup_mech), "%s", data[1]);
850 uparam->kup_uid = strtol(data[2], NULL, 0);
851 uparam->kup_gid = strtol(data[3], NULL, 0);
852 if (strchr(data[4], 'r'))
853 uparam->kup_is_root = 1;
854 if (strchr(data[4], 'm'))
855 uparam->kup_is_mdt = 1;
856 if (strchr(data[4], 'o'))
857 uparam->kup_is_ost = 1;
858 uparam->kup_svc_type = data[5][0];
859 uparam->kup_svc = strtol(data[6], NULL, 0);
860 uparam->kup_nid = strtoll(data[7], NULL, 0);
861 snprintf(uparam->kup_tgt, sizeof(uparam->kup_tgt), "%s", data[8]);
862 uparam->kup_selfnid = strtoll(data[9], NULL, 0);
863 uparam->kup_pid = strtol(data[10], NULL, 0);
865 logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, "
866 "is_root %d, is_mdt %d, is_ost %d, svc type %c, svc %d, "
867 "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64", pid %d\n",
868 uparam->kup_secid, uparam->kup_mech,
869 uparam->kup_uid, uparam->kup_gid,
870 uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
871 uparam->kup_svc_type, uparam->kup_svc, uparam->kup_nid,
872 uparam->kup_tgt, uparam->kup_selfnid, uparam->kup_pid);
876 static void set_log_level()
882 if (cfs_get_param_paths(&path,
883 "sptlrpc/gss/lgss_keyring/debug_level") != 0)
885 file = fopen(path.gl_pathv[0], "r");
887 cfs_free_param_data(&path);
891 if (fscanf(file, "%u", &level) != 1)
897 lgss_set_loglevel(level);
899 cfs_free_param_data(&path);
903 static int associate_with_ns(char *path)
908 fd = open(path, O_RDONLY);
917 #endif /* HAVE_SETNS */
920 static int prepare_and_instantiate(struct lgss_cred *cred, key_serial_t keyid,
923 key_serial_t inst_keyring;
925 if (lgss_prepare_cred(cred)) {
926 logmsg(LL_ERR, "key %08x: failed to prepare credentials "
927 "for user %d\n", keyid, uid);
931 /* pre initialize the key. note the keyring linked to is actually of the
932 * original requesting process, not _this_ upcall process. if it's for
933 * root user, don't link to any keyrings because we want fully control
934 * on it, and share it among all root sessions; otherswise link to
937 if (cred->lc_root_flags != 0)
940 inst_keyring = KEY_SPEC_SESSION_KEYRING;
942 if (keyctl_instantiate(keyid, NULL, 0, inst_keyring)) {
943 logmsg(LL_ERR, "instantiate key %08x: %s\n",
944 keyid, strerror(errno));
948 logmsg(LL_TRACE, "instantiated kernel key %08x\n", keyid);
953 /****************************************
955 ****************************************/
957 int main(int argc, char *argv[])
959 struct keyring_upcall_param uparam;
963 int req_fd[2] = { -1, -1 };
964 int reply_fd[2] = { -1, -1 };
965 struct lgss_mech_type *mech;
966 struct lgss_cred *cred;
967 char path[PATH_MAX] = "";
971 struct stat parent_ns = { .st_ino = 0 };
972 struct stat caller_ns = { .st_ino = 0 };
977 logmsg(LL_TRACE, "start parsing parameters\n");
979 * parse & sanity check upcall parameters
980 * expected to be called with:
984 * [4]: key description
988 * [8]: thread keyring
989 * [9]: process keyring
990 * [10]: session keyring
992 if (argc != 10 + 1) {
993 logmsg(LL_ERR, "invalid parameter number %d\n", argc);
997 logmsg(LL_INFO, "key %s, desc %s, ugid %s:%s, sring %s, coinfo %s\n",
998 argv[2], argv[4], argv[6], argv[7], argv[10], argv[5]);
1000 memset(&uparam, 0, sizeof(uparam));
1002 if (strcmp(argv[1], "create") != 0) {
1003 logmsg(LL_ERR, "invalid OP %s\n", argv[1]);
1007 if (sscanf(argv[2], "%d", &keyid) != 1) {
1008 logmsg(LL_ERR, "can't extract KeyID: %s\n", argv[2]);
1012 if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) {
1013 logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]);
1017 if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) {
1018 logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]);
1022 if (sscanf(argv[10], "%d", &sring) != 1) {
1023 logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]);
1027 if (parse_callout_info(argv[5], &uparam)) {
1028 logmsg(LL_ERR, "can't extract callout info: %s\n", argv[5]);
1032 logmsg(LL_TRACE, "parsing parameters OK\n");
1037 mech = lgss_name2mech(uparam.kup_mech);
1039 logmsg(LL_ERR, "key %08x: unsupported mech: %s\n",
1040 keyid, uparam.kup_mech);
1044 if (lgss_mech_initialize(mech)) {
1045 logmsg(LL_ERR, "key %08x: can't initialize mech %s\n",
1046 keyid, mech->lmt_name);
1050 cred = lgss_create_cred(mech);
1052 logmsg(LL_ERR, "key %08x: can't create a new %s cred\n",
1053 keyid, mech->lmt_name);
1057 cred->lc_uid = uparam.kup_uid;
1058 cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0;
1059 cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0;
1060 cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0;
1061 cred->lc_tgt_nid = uparam.kup_nid;
1062 cred->lc_tgt_svc = uparam.kup_svc;
1063 cred->lc_tgt_uuid = uparam.kup_tgt;
1064 cred->lc_svc_type = uparam.kup_svc_type;
1065 cred->lc_self_nid = uparam.kup_selfnid;
1068 /* Is caller in different namespace? */
1069 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", getpid());
1070 if (stat(path, &parent_ns))
1071 logmsg(LL_ERR, "cannot stat %s: %s\n", path, strerror(errno));
1072 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", uparam.kup_pid);
1073 if (stat(path, &caller_ns))
1074 logmsg(LL_ERR, "cannot stat %s: %s\n", path, strerror(errno));
1075 if (caller_ns.st_ino != parent_ns.st_ino) {
1078 #endif /* HAVE_SETNS */
1081 * if caller's namespace is different, fork a child and associate it
1082 * with caller's namespace to do credentials preparation
1085 logmsg(LL_TRACE, "caller's namespace is diffent\n");
1087 /* use pipes to pass info between child and parent processes */
1088 if (pipe(req_fd) == -1) {
1089 logmsg(LL_ERR, "key %08x: pipe failed: %s\n",
1090 keyid, strerror(errno));
1093 if (pipe(reply_fd) == -1) {
1094 logmsg(LL_ERR, "key %08x: pipe failed: %s\n",
1095 keyid, strerror(errno));
1101 logmsg(LL_ERR, "key %08x: can't create child: %s\n",
1102 keyid, strerror(errno));
1105 } else if (child == 0) {
1107 /* child process: carry out credentials preparation
1108 * in caller's namespace */
1110 close(req_fd[0]); /* close unsed read end */
1112 close(reply_fd[1]); /* close unsed write end */
1115 if (associate_with_ns(path) != 0) {
1117 "failed to attach to pid %d namespace: "
1118 "%s\n", uparam.kup_pid, strerror(errno));
1122 logmsg(LL_TRACE, "working in namespace of pid %d\n",
1125 rc = prepare_and_instantiate(cred, keyid,
1128 /* send to parent the status of credentials preparation
1129 * and key instantiation */
1130 rc2 = send_to(req_fd[1], &rc, sizeof(rc));
1131 rc = (rc == 0 ? rc2 : rc);
1135 /* now do real gss negotiation
1136 * parent main process will not wait for us,
1137 * as it has to be done in the background */
1138 rc = lgssc_kr_negotiate(keyid, cred, &uparam,
1143 /* parent process: exchange info with child carrying out
1144 * credentials preparation */
1146 close(req_fd[1]); /* close unsed write end */
1148 close(reply_fd[0]); /* close unsed read end */
1151 /* get status of credentials preparation
1152 * and key instantiation */
1153 rc2 = receive_from(req_fd[0], &rc, sizeof(rc));
1154 if (rc2 != 0 || rc != 0) {
1155 logmsg(LL_ERR, "child failed preparing creds: "
1157 rc2 != 0 ? strerror(-rc2)
1163 * fork a child here to participate in gss negotiation,
1164 * as it has to be done in the background
1169 "key %08x: can't create child: %s\n",
1170 keyid, strerror(errno));
1173 } else if (child == 0) {
1174 struct lgssd_ioctl_param param;
1175 char outbuf[8192] = { 0 };
1176 void *gss_token = NULL;
1178 /* get ioctl buffer from child */
1179 rc = receive_from(req_fd[0], ¶m,
1184 gss_token = calloc(1, param.send_token_size);
1185 if (gss_token == NULL)
1188 /* get gss token from child */
1189 rc = receive_from(req_fd[0], gss_token,
1190 param.send_token_size);
1194 param.send_token = (char *)gss_token;
1195 param.reply_buf_size = sizeof(outbuf);
1196 param.reply_buf = outbuf;
1198 /* do ioctl in place of child process carrying
1199 * out credentials negotiation: as it runs in
1200 * a container, it might not be able to
1202 rc = gss_do_ioctl(¶m);
1206 /* send ioctl status to child */
1207 rc = send_to(reply_fd[1], ¶m.status,
1208 sizeof(param.status));
1211 /* send reply buffer to child */
1212 rc = send_to(reply_fd[1], outbuf,
1222 logmsg(LL_TRACE, "forked child %d\n", child);
1231 logmsg(LL_TRACE, "caller's namespace is the same\n");
1233 rc = prepare_and_instantiate(cred, keyid, uparam.kup_uid);
1238 * fork a child to do the real gss negotiation
1242 logmsg(LL_ERR, "key %08x: can't create child: %s\n",
1243 keyid, strerror(errno));
1245 } else if (child == 0) {
1246 return lgssc_kr_negotiate(keyid, cred, &uparam,
1250 logmsg(LL_TRACE, "forked child %d\n", child);