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/
31 * lustre/utils/gss/lgss_keyring.c
33 * user-space upcall to create GSS context, using keyring interface to kernel
35 * Author: Eric Mei <ericm@clusterfs.com>
39 #include <sys/types.h>
50 #include <gssapi/gssapi.h>
54 #include <libcfs/util/param.h>
55 #include <libcfs/util/string.h>
56 #include <uapi/linux/lustre/lgss.h>
58 #include "lgss_utils.h"
59 #include "lgss_krb5_utils.h"
60 #include "write_bytes.h"
64 * gss target string of lustre service we are negotiating for
66 static char *g_service = NULL;
69 * all data about negotiation
71 struct lgss_nego_data {
72 uint32_t lnd_established:1;
79 gss_OID lnd_mech; /* mech OID */
80 gss_name_t lnd_svc_name; /* service name */
81 unsigned int lnd_req_flags; /* request flags */
82 gss_cred_id_t lnd_cred; /* credential */
83 gss_ctx_id_t lnd_ctx; /* session context */
84 gss_buffer_desc lnd_rmt_ctx; /* remote handle of context */
85 gss_buffer_desc lnd_ctx_token; /* context token for kernel */
86 uint32_t lnd_seq_win; /* sequence window */
93 * context creation response
95 struct lgss_init_res {
96 gss_buffer_desc gr_ctx; /* context handle */
97 unsigned int gr_major; /* major status */
98 unsigned int gr_minor; /* minor status */
99 unsigned int gr_win; /* sequence window */
100 gss_buffer_desc gr_token; /* token */
103 struct keyring_upcall_param {
112 uint64_t kup_selfnid;
116 unsigned int kup_is_root:1,
122 /****************************************
123 * child process: gss negotiation *
124 ****************************************/
126 static int send_to(int fd, const void *buf, size_t size)
130 sz = write(fd, buf, size);
132 logmsg(LL_ERR, "cannot send to GSS process: %s\n",
137 logmsg(LL_ERR, "short write sending to GSS process: %d/%d\n",
145 static int receive_from(int fd, void *buf, size_t size)
149 sz = read(fd, buf, size);
151 logmsg(LL_ERR, "cannot receive from GSS process: %s\n",
156 logmsg(LL_ERR, "short read receiving from GSS process: %d/%d\n",
164 static int gss_do_ioctl(struct lgssd_ioctl_param *param)
170 rc = cfs_get_param_paths(&path, "sptlrpc/gss/init_channel");
174 logmsg(LL_TRACE, "to open %s\n", path.gl_pathv[0]);
176 fd = open(path.gl_pathv[0], O_WRONLY);
178 logmsg(LL_ERR, "can't open %s\n", path.gl_pathv[0]);
183 logmsg(LL_TRACE, "to down-write\n");
185 ret = write(fd, param, sizeof(*param));
187 if (ret != sizeof(*param)) {
188 logmsg(LL_ERR, "lustre ioctl err: %s\n", strerror(errno));
193 cfs_free_param_data(&path);
197 static int do_nego_rpc(struct lgss_nego_data *lnd,
198 gss_buffer_desc *gss_token,
199 struct lgss_init_res *gr,
200 int req_fd[2], int reply_fd[2])
202 struct lgssd_ioctl_param param;
205 char outbuf[8192] = { 0 };
209 logmsg(LL_TRACE, "start negotiation rpc\n");
211 pw = getpwuid(lnd->lnd_uid);
213 logmsg(LL_ERR, "no uid %u in local user database\n",
218 param.version = GSSD_INTERFACE_VERSION;
219 param.secid = lnd->lnd_secid;
220 param.uuid = lnd->lnd_uuid;
221 param.lustre_svc = lnd->lnd_lsvc;
222 param.uid = lnd->lnd_uid;
223 param.gid = pw->pw_gid;
224 param.send_token_size = gss_token->length;
225 param.send_token = (char *) gss_token->value;
227 if (req_fd[0] == -1 && reply_fd[0] == -1) {
228 /* we can do the ioctl directly */
229 param.reply_buf_size = sizeof(outbuf);
230 param.reply_buf = outbuf;
232 rc = gss_do_ioctl(¶m);
236 /* looks like we are running in a container,
237 * so we cannot do the ioctl ourselves: delegate to
238 * parent process running directly on host */
240 /* send ioctl buffer to parent */
241 rc = send_to(req_fd[1], ¶m, sizeof(param));
244 /* send gss token to parent */
245 rc = send_to(req_fd[1], gss_token->value, gss_token->length);
249 /* read ioctl status from parent */
250 rc = receive_from(reply_fd[0], ¶m.status,
251 sizeof(param.status));
255 if (param.status == 0) {
256 /* read reply buffer from parent */
257 rc = receive_from(reply_fd[0], outbuf, sizeof(outbuf));
263 logmsg(LL_TRACE, "do_nego_rpc: to parse reply\n");
265 logmsg(LL_ERR, "status: %ld (%s)\n",
266 (long int)param.status, strerror((int)(-param.status)));
270 p = (unsigned int *)outbuf;
276 gr->gr_ctx.length = *p++;
277 gr->gr_ctx.value = malloc(gr->gr_ctx.length);
278 if (gr->gr_ctx.value == NULL)
280 memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length);
281 p += (((gr->gr_ctx.length + 3) & ~3) / 4);
283 gr->gr_token.length = *p++;
284 gr->gr_token.value = malloc(gr->gr_token.length);
285 if (gr->gr_token.value == NULL) {
286 free(gr->gr_ctx.value);
289 memcpy(gr->gr_token.value, p, gr->gr_token.length);
290 p += (((gr->gr_token.length + 3) & ~3) / 4);
292 logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %zu, token len %zu, "
293 "res %d\n", gr->gr_ctx.length, gr->gr_token.length, res);
298 /* This is used by incomplete GSSAPI implementations that can't use
299 * gss_init_sec_context and will parse the token themselves (gssnull and sk).
300 * Callers should have cred->lc_mech_token pointing to a gss_buffer_desc
301 * token to send to the peer as part of the SEC_CTX_INIT operation. The return
302 * RPC's token with be in gr.gr_token which is validated using
303 * lgss_validate_cred. */
304 static int lgssc_negotiation_manual(struct lgss_nego_data *lnd,
305 struct lgss_cred *cred,
306 int req_fd[2], int reply_fd[2])
308 struct lgss_init_res gr;
312 logmsg(LL_TRACE, "starting gss negotation\n");
313 memset(&gr, 0, sizeof(gr));
315 lnd->lnd_rpc_err = do_nego_rpc(lnd, &cred->lc_mech_token, &gr,
317 if (lnd->lnd_rpc_err) {
318 logmsg(LL_ERR, "negotiation rpc error %d\n", lnd->lnd_rpc_err);
319 rc = lnd->lnd_rpc_err;
323 if (gr.gr_major == GSS_S_CONTINUE_NEEDED) {
327 } else if (gr.gr_major != GSS_S_COMPLETE) {
328 lnd->lnd_gss_err = gr.gr_major;
329 logmsg(LL_ERR, "negotiation gss error %x\n", lnd->lnd_gss_err);
334 if (gr.gr_ctx.length == 0 || gr.gr_token.length == 0) {
335 logmsg(LL_ERR, "zero length context or token received\n");
340 rc = lgss_validate_cred(cred, &gr.gr_token, &lnd->lnd_ctx_token);
342 logmsg(LL_ERR, "peer token failed validation\n");
346 lnd->lnd_established = 1;
347 lnd->lnd_seq_win = gr.gr_win;
348 lnd->lnd_rmt_ctx = gr.gr_ctx;
350 if (gr.gr_token.length != 0)
351 gss_release_buffer(&min_stat, &gr.gr_token);
353 logmsg(LL_DEBUG, "successfully negotiated a context\n");
357 if (gr.gr_ctx.length != 0)
358 gss_release_buffer(&min_stat, &gr.gr_ctx);
359 if (gr.gr_token.length != 0)
360 gss_release_buffer(&min_stat, &gr.gr_token);
366 * if return error, the lnd_rpc_err or lnd_gss_err is set.
368 static int lgssc_negotiation(struct lgss_nego_data *lnd, int req_fd[2],
371 struct lgss_init_res gr;
372 gss_buffer_desc *recv_tokenp, send_token;
373 OM_uint32 maj_stat, min_stat, ret_flags;
375 logmsg(LL_TRACE, "start gss negotiation\n");
377 /* GSS context establishment loop. */
378 memset(&gr, 0, sizeof(gr));
379 recv_tokenp = GSS_C_NO_BUFFER;
382 maj_stat = gss_init_sec_context(&min_stat,
391 NULL, /* used mech */
394 NULL); /* time rec */
396 logmsg_gss(LL_TRACE, lnd->lnd_mech, maj_stat, min_stat,
397 "gss_init_sec_context");
399 logmsg(LL_TRACE, "send_token:\n");
400 log_hexl(LL_TRACE, send_token.value, send_token.length);
402 if (recv_tokenp != GSS_C_NO_BUFFER) {
403 gss_release_buffer(&min_stat, &gr.gr_token);
404 recv_tokenp = GSS_C_NO_BUFFER;
407 if (maj_stat != GSS_S_COMPLETE &&
408 maj_stat != GSS_S_CONTINUE_NEEDED) {
409 lnd->lnd_gss_err = maj_stat;
411 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
412 "failed init context");
416 if (send_token.length != 0) {
417 memset(&gr, 0, sizeof(gr));
419 lnd->lnd_rpc_err = do_nego_rpc(lnd, &send_token, &gr,
421 gss_release_buffer(&min_stat, &send_token);
423 if (lnd->lnd_rpc_err) {
424 logmsg(LL_ERR, "negotiation rpc error: %d\n",
426 return lnd->lnd_rpc_err;
429 if (gr.gr_major != GSS_S_COMPLETE &&
430 gr.gr_major != GSS_S_CONTINUE_NEEDED) {
431 lnd->lnd_gss_err = gr.gr_major;
433 logmsg(LL_ERR, "negotiation gss error %x\n",
438 if (gr.gr_ctx.length != 0) {
439 if (lnd->lnd_rmt_ctx.value)
440 gss_release_buffer(&min_stat,
442 lnd->lnd_rmt_ctx = gr.gr_ctx;
445 if (gr.gr_token.length != 0) {
446 if (maj_stat != GSS_S_CONTINUE_NEEDED)
448 recv_tokenp = &gr.gr_token;
452 /* GSS_S_COMPLETE => check gss header verifier,
453 * usually checked in gss_validate
455 if (maj_stat == GSS_S_COMPLETE) {
456 lnd->lnd_established = 1;
457 lnd->lnd_seq_win = gr.gr_win;
462 /* End context negotiation loop. */
463 if (!lnd->lnd_established) {
464 if (gr.gr_token.length != 0)
465 gss_release_buffer(&min_stat, &gr.gr_token);
467 if (lnd->lnd_gss_err == GSS_S_COMPLETE)
468 lnd->lnd_rpc_err = -EACCES;
470 logmsg(LL_ERR, "context negotiation failed\n");
474 logmsg(LL_DEBUG, "successfully negotiated a context\n");
479 * if return error, the lnd_rpc_err or lnd_gss_err is set.
481 static int lgssc_init_nego_data(struct lgss_nego_data *lnd,
482 struct keyring_upcall_param *kup,
485 gss_buffer_desc sname;
486 OM_uint32 maj_stat, min_stat;
488 memset(lnd, 0, sizeof(*lnd));
490 lnd->lnd_secid = kup->kup_secid;
491 lnd->lnd_uid = kup->kup_uid;
492 lnd->lnd_lsvc = kup->kup_svc | mech << LUSTRE_GSS_MECH_SHIFT;
493 lnd->lnd_uuid = kup->kup_tgt;
495 lnd->lnd_established = 0;
496 lnd->lnd_svc_name = GSS_C_NO_NAME;
497 lnd->lnd_cred = GSS_C_NO_CREDENTIAL;
498 lnd->lnd_ctx = GSS_C_NO_CONTEXT;
499 lnd->lnd_rmt_ctx = (gss_buffer_desc) GSS_C_EMPTY_BUFFER;
500 lnd->lnd_seq_win = 0;
504 lnd->lnd_mech = (gss_OID)&krb5oid;
505 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
508 lnd->lnd_mech = (gss_OID)&nulloid;
510 #ifdef HAVE_OPENSSL_SSK
512 lnd->lnd_mech = (gss_OID)&skoid;
513 lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG;
517 logmsg(LL_ERR, "invalid mech: %d\n", mech);
518 lnd->lnd_rpc_err = -EACCES;
522 sname.value = g_service;
523 sname.length = strlen(g_service);
525 maj_stat = gss_import_name(&min_stat, &sname,
526 (gss_OID) GSS_C_NT_HOSTBASED_SERVICE,
528 if (maj_stat != GSS_S_COMPLETE) {
529 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
530 "can't import svc name");
531 lnd->lnd_gss_err = maj_stat;
538 static void lgssc_fini_nego_data(struct lgss_nego_data *lnd)
540 OM_uint32 maj_stat, min_stat;
542 if (lnd->lnd_svc_name != GSS_C_NO_NAME) {
543 maj_stat = gss_release_name(&min_stat, &lnd->lnd_svc_name);
544 if (maj_stat != GSS_S_COMPLETE)
545 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
546 "can't release service name");
549 if (lnd->lnd_cred != GSS_C_NO_CREDENTIAL) {
550 maj_stat = gss_release_cred(&min_stat, &lnd->lnd_cred);
551 if (maj_stat != GSS_S_COMPLETE)
552 logmsg_gss(LL_ERR, lnd->lnd_mech, maj_stat, min_stat,
553 "can't release credential");
557 static int fork_and_switch_id(int uid, pid_t *child)
563 logmsg(LL_ERR, "cannot fork child for user %u: %s\n",
564 uid, strerror(errno));
566 } else if (*child == 0) {
567 /* switch identity */
568 rc = switch_identity(uid);
572 if (wait(&status) < 0) {
574 logmsg(LL_ERR, "child %d failed: %s\n",
575 *child, strerror(rc));
577 rc = WEXITSTATUS(status);
579 logmsg(LL_ERR, "child %d terminated with %d\n",
586 static int do_keyctl_update(char *reason, key_serial_t keyid,
587 const void *payload, size_t plen)
589 while (keyctl_update(keyid, payload, plen)) {
590 if (errno != EAGAIN) {
591 logmsg(LL_ERR, "%se key %08x: %s\n",
592 reason, keyid, strerror(errno));
596 logmsg(LL_WARN, "key %08x: %sing too soon, try again\n",
601 logmsg(LL_INFO, "key %08x: %sed\n", keyid, reason);
605 static int error_kernel_key(key_serial_t keyid, int rpc_error, int gss_error,
608 key_serial_t inst_keyring = KEY_SPEC_SESSION_KEYRING;
615 logmsg(LL_TRACE, "revoking kernel key %08x\n", keyid);
617 /* Only possessor and uid can update the key. So for a user key that is
618 * linked to the user keyring, switch uid/gid in a subprocess to not
619 * change identity in main process.
622 rc = fork_and_switch_id(uid, &child);
625 inst_keyring = KEY_SPEC_USER_KEYRING;
629 end = buf + sizeof(buf);
631 WRITE_BYTES(&p, end, seqwin);
632 WRITE_BYTES(&p, end, rpc_error);
633 WRITE_BYTES(&p, end, gss_error);
635 rc = do_keyctl_update("revok", keyid, buf, p - buf);
636 /* no matter if revoking key was successful or not, always try unlink */
637 rc2 = keyctl_unlink(keyid, inst_keyring);
639 logmsg(LL_ERR, "unlink key %08x from %d: %s\n",
640 keyid, inst_keyring, strerror(errno));
644 logmsg(LL_INFO, "key %08x: unlinked from %d\n",
645 keyid, inst_keyring);
650 /* job done for child */
655 static int update_kernel_key(key_serial_t keyid,
656 struct lgss_nego_data *lnd,
657 gss_buffer_desc *ctx_token)
659 char *buf = NULL, *p = NULL, *end = NULL;
660 unsigned int buf_size = 0;
664 logmsg(LL_TRACE, "updating kernel key %08x\n", keyid);
666 /* Only possessor and uid can update the key. So for a user key that is
667 * linked to the user keyring, switch uid/gid in a subprocess to not
668 * change identity in main process.
672 rc = fork_and_switch_id(uid, &child);
677 buf_size = sizeof(lnd->lnd_seq_win) +
678 sizeof(lnd->lnd_rmt_ctx.length) + lnd->lnd_rmt_ctx.length +
679 sizeof(ctx_token->length) + ctx_token->length;
680 buf = malloc(buf_size);
682 logmsg(LL_ERR, "key %08x: can't alloc update buf: size %d\n",
689 end = buf + buf_size;
692 if (WRITE_BYTES(&p, end, lnd->lnd_seq_win))
694 if (write_buffer(&p, end, &lnd->lnd_rmt_ctx))
696 if (write_buffer(&p, end, ctx_token))
699 rc = do_keyctl_update("updat", keyid, buf, p - buf);
704 /* job done for child */
709 static int lgssc_kr_negotiate_krb(key_serial_t keyid, struct lgss_cred *cred,
710 struct keyring_upcall_param *kup,
711 int req_fd[2], int reply_fd[2])
713 struct lgss_nego_data lnd;
718 if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) {
719 logmsg(LL_ERR, "key %08x: failed to construct service "
721 error_kernel_key(keyid, -EACCES, 0, cred->lc_uid);
725 if (lgss_using_cred(cred)) {
726 logmsg(LL_ERR, "key %08x: can't using cred\n", keyid);
727 error_kernel_key(keyid, -EACCES, 0, cred->lc_uid);
732 memset(&lnd, 0, sizeof(lnd));
733 if (lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n)) {
734 logmsg(LL_ERR, "key %08x: failed to initialize "
735 "negotiation data\n", keyid);
736 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err,
741 rc = lgssc_negotiation(&lnd, req_fd, reply_fd);
742 if (rc == -EAGAIN || (rc == -ETIMEDOUT && redo)) {
743 logmsg(LL_ERR, "Failed negotiation must retry\n");
747 logmsg(LL_ERR, "key %08x: failed to negotiation\n", keyid);
748 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err,
753 rc = serialize_context_for_kernel(&lnd.lnd_ctx, &lnd.lnd_ctx_token,
756 logmsg(LL_ERR, "key %08x: failed to export context\n", keyid);
757 error_kernel_key(keyid, rc, lnd.lnd_gss_err, cred->lc_uid);
761 rc = update_kernel_key(keyid, &lnd, &lnd.lnd_ctx_token);
766 logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
767 keyid, kup->kup_uid);
769 if (lnd.lnd_ctx_token.length != 0)
770 (void)gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
772 lgssc_fini_nego_data(&lnd);
775 lgss_release_cred(cred);
779 static int lgssc_kr_negotiate_manual(key_serial_t keyid, struct lgss_cred *cred,
780 struct keyring_upcall_param *kup,
781 int req_fd[2], int reply_fd[2])
783 struct lgss_nego_data lnd;
788 rc = lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid);
790 logmsg(LL_ERR, "key %08x: failed to construct service "
792 error_kernel_key(keyid, -EACCES, 0, 0);
796 rc = lgss_using_cred(cred);
798 logmsg(LL_ERR, "key %08x: can't use cred\n", keyid);
799 error_kernel_key(keyid, -EACCES, 0, 0);
804 memset(&lnd, 0, sizeof(lnd));
805 rc = lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n);
807 logmsg(LL_ERR, "key %08x: failed to initialize "
808 "negotiation data\n", keyid);
809 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err, 0);
814 * Handles the negotiation but then calls lgss_validate to make sure
815 * the token is valid. It also populates the lnd_ctx_token for the
816 * update to the kernel key
818 rc = lgssc_negotiation_manual(&lnd, cred, req_fd, reply_fd);
819 if (rc == -EAGAIN || (rc == -ETIMEDOUT && redo)) {
820 logmsg(LL_ERR, "Failed negotiation must retry\n");
824 logmsg(LL_ERR, "key %08x: failed to negotiate\n", keyid);
825 error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err, 0);
829 rc = update_kernel_key(keyid, &lnd, &lnd.lnd_ctx_token);
833 logmsg(LL_INFO, "key %08x for user %u is updated OK!\n",
834 keyid, kup->kup_uid);
836 if (lnd.lnd_ctx_token.length != 0)
837 gss_release_buffer(&min_stat, &lnd.lnd_ctx_token);
839 lgssc_fini_nego_data(&lnd);
842 lgss_release_cred(cred);
847 * note we inherited assumed authority from parent process
849 static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred,
850 struct keyring_upcall_param *kup,
851 int req_fd[2], int reply_fd[2])
855 logmsg(LL_TRACE, "child start on behalf of key %08x: "
856 "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n",
857 keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid,
858 kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid);
860 switch (cred->lc_mech->lmt_mech_n) {
863 rc = lgssc_kr_negotiate_manual(keyid, cred, kup,
868 rc = lgssc_kr_negotiate_krb(keyid, cred, kup, req_fd, reply_fd);
876 * call out info format: s[:s]...
878 * [1]: mech_name (string)
881 * [4]: flags (string) FMT: r-root; m-mdt; o-ost
882 * [5]: svc type (char)
883 * [6]: lustre_svc (int)
884 * [7]: target_nid (uint64)
885 * [8]: target_uuid (string)
886 * [9]: self_nid (uint64)
889 static int parse_callout_info(const char *coinfo,
890 struct keyring_upcall_param *uparam)
892 const int nargs = 11;
899 length = strlen(coinfo) + 1;
901 logmsg(LL_ERR, "coinfo too long\n");
904 memcpy(buf, coinfo, length);
906 for (i = 0; i < nargs - 1; i++) {
907 pos = strchr(string, ':');
909 logmsg(LL_ERR, "short of components\n");
919 logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s,%s\n",
920 data[0], data[1], data[2], data[3], data[4], data[5][0],
921 data[6], data[7], data[8], data[9], data[10]);
923 uparam->kup_secid = strtol(data[0], NULL, 0);
924 snprintf(uparam->kup_mech, sizeof(uparam->kup_mech), "%s", data[1]);
925 uparam->kup_uid = strtol(data[2], NULL, 0);
926 uparam->kup_gid = strtol(data[3], NULL, 0);
927 if (strchr(data[4], 'r'))
928 uparam->kup_is_root = 1;
929 if (strchr(data[4], 'm'))
930 uparam->kup_is_mdt = 1;
931 if (strchr(data[4], 'o'))
932 uparam->kup_is_ost = 1;
933 uparam->kup_svc_type = data[5][0];
934 uparam->kup_svc = strtol(data[6], NULL, 0);
935 uparam->kup_nid = strtoll(data[7], NULL, 0);
936 snprintf(uparam->kup_tgt, sizeof(uparam->kup_tgt), "%s", data[8]);
937 uparam->kup_selfnid = strtoll(data[9], NULL, 0);
938 uparam->kup_pid = strtol(data[10], NULL, 0);
940 logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, "
941 "is_root %d, is_mdt %d, is_ost %d, svc type %c, svc %d, "
942 "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64", pid %d\n",
943 uparam->kup_secid, uparam->kup_mech,
944 uparam->kup_uid, uparam->kup_gid,
945 uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost,
946 uparam->kup_svc_type, uparam->kup_svc, uparam->kup_nid,
947 uparam->kup_tgt, uparam->kup_selfnid, uparam->kup_pid);
951 static void set_log_level()
957 if (cfs_get_param_paths(&path,
958 "sptlrpc/gss/lgss_keyring/debug_level") != 0)
960 file = fopen(path.gl_pathv[0], "r");
962 cfs_free_param_data(&path);
966 if (fscanf(file, "%u", &level) != 1)
972 lgss_set_loglevel(level);
974 cfs_free_param_data(&path);
978 static int associate_with_ns(char *path)
982 fd = open(path, O_RDONLY);
991 static int prepare_and_instantiate(struct lgss_cred *cred, key_serial_t keyid,
994 key_serial_t inst_keyring;
995 bool prepared = true;
999 if (lgss_prepare_cred(cred)) {
1000 logmsg(LL_ERR, "key %08x: failed to prepare credentials "
1001 "for user %d\n", keyid, uid);
1002 /* prepare failed, but still instantiate the key for regular
1003 * user, so that it can be used to report the error later
1006 if (cred->lc_root_flags)
1011 /* Pre initialize the key. Note the keyring linked to is actually of the
1012 * original requesting process, not _this_ upcall process. If it's for
1013 * root user, don't link to any keyrings because we want fully control
1014 * on it, and share it among all root sessions.
1015 * Otherswise link to user keyring, which requires switching uid/gid.
1016 * Do this in a subprocess because other operations need privileges.
1018 if (cred->lc_root_flags) {
1021 inst_keyring = KEY_SPEC_USER_KEYRING;
1022 /* fork to not change identity in main process */
1023 rc = fork_and_switch_id(uid, &child);
1028 /* if dealing with a user key, grant user write permission,
1029 * it will be required for key update
1034 perm = KEY_POS_VIEW | KEY_POS_WRITE | KEY_POS_SEARCH |
1035 KEY_POS_LINK | KEY_POS_SETATTR |
1036 KEY_USR_VIEW | KEY_USR_WRITE;
1037 if (keyctl_setperm(keyid, perm))
1038 logmsg(LL_ERR, "setperm %08x on key %08x: %s\n",
1039 perm, keyid, strerror(errno));
1042 rc = keyctl_instantiate(keyid, NULL, 0, inst_keyring);
1045 logmsg(LL_ERR, "instantiate key %08x in keyring id %d: %s\n",
1046 keyid, inst_keyring, strerror(rc));
1049 "instantiated kernel key %08x in keyring id %d\n",
1050 keyid, inst_keyring);
1055 /* job done for child */
1057 return prepared ? rc : 1;
1060 /****************************************
1062 ****************************************/
1064 int main(int argc, char *argv[])
1066 struct keyring_upcall_param uparam;
1070 int req_fd[2] = { -1, -1 };
1071 int reply_fd[2] = { -1, -1 };
1072 struct lgss_mech_type *mech;
1073 struct lgss_cred *cred;
1074 char path[PATH_MAX] = "";
1077 struct stat parent_ns = { .st_ino = 0 };
1078 struct stat caller_ns = { .st_ino = 0 };
1080 static struct option long_opts[] = {
1081 { .name = "realm", .has_arg = required_argument, .val = 'R'},
1082 { .name = NULL, } };
1086 logmsg(LL_TRACE, "start parsing parameters\n");
1088 /* one possible option before upcall parameters: -R REALM */
1089 while ((opt = getopt_long(argc, argv, "R:", long_opts, NULL)) != EOF) {
1092 lgss_client_realm = optarg;
1095 logmsg(LL_ERR, "invalid parameter %s\n",
1101 if (lgss_client_realm) {
1102 /* shift args to meet expected upcall parameters */
1108 * parse & sanity check upcall parameters
1109 * expected to be called with:
1113 * [4]: key description
1114 * [5]: call out info
1117 * [8]: thread keyring
1118 * [9]: process keyring
1119 * [10]: session keyring
1121 if (argc != 10 + 1) {
1122 logmsg(LL_ERR, "invalid parameter number %d\n", argc);
1126 memset(&uparam, 0, sizeof(uparam));
1128 if (strcmp(argv[1], "create") != 0) {
1130 "invalid OP %s (key %s, desc %s, ugid %s:%s, sring %s, coinfo %s)\n",
1131 argv[1], argv[2], argv[4], argv[6], argv[7], argv[10],
1136 if (sscanf(argv[2], "%d", &keyid) != 1) {
1138 "can't extract KeyID: %s (key %s, desc %s, ugid %s:%s, sring %s, coinfo %s)\n",
1139 argv[2], argv[2], argv[4], argv[6], argv[7], argv[10],
1144 logmsg(LL_INFO, "key %08x, desc %s, ugid %s:%s, sring %s, coinfo %s\n",
1145 keyid, argv[4], argv[6], argv[7], argv[10], argv[5]);
1147 if (sscanf(argv[6], "%d", &uparam.kup_fsuid) != 1) {
1148 logmsg(LL_ERR, "can't extract UID: %s\n", argv[6]);
1152 if (sscanf(argv[7], "%d", &uparam.kup_fsgid) != 1) {
1153 logmsg(LL_ERR, "can't extract GID: %s\n", argv[7]);
1157 if (sscanf(argv[10], "%d", &sring) != 1) {
1158 logmsg(LL_ERR, "can't extract session keyring: %s\n", argv[10]);
1162 if (parse_callout_info(argv[5], &uparam)) {
1163 logmsg(LL_ERR, "can't extract callout info: %s\n", argv[5]);
1167 logmsg(LL_TRACE, "parsing parameters OK\n");
1172 mech = lgss_name2mech(uparam.kup_mech);
1174 logmsg(LL_ERR, "key %08x: unsupported mech: %s\n",
1175 keyid, uparam.kup_mech);
1179 if (lgss_mech_initialize(mech)) {
1180 logmsg(LL_ERR, "key %08x: can't initialize mech %s\n",
1181 keyid, mech->lmt_name);
1185 cred = lgss_create_cred(mech);
1187 logmsg(LL_ERR, "key %08x: can't create a new %s cred\n",
1188 keyid, mech->lmt_name);
1192 cred->lc_uid = uparam.kup_uid;
1193 cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0;
1194 cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0;
1195 cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0;
1196 cred->lc_tgt_nid = uparam.kup_nid;
1197 cred->lc_tgt_svc = uparam.kup_svc;
1198 cred->lc_tgt_uuid = uparam.kup_tgt;
1199 cred->lc_svc_type = uparam.kup_svc_type;
1200 cred->lc_self_nid = uparam.kup_selfnid;
1202 /* Is caller in different namespace? */
1203 /* If passed caller's pid is 0, it means we have to stick
1204 * with current namespace.
1206 if (uparam.kup_pid) {
1207 snprintf(path, sizeof(path), "/proc/%d/ns/mnt", getpid());
1208 if (stat(path, &parent_ns)) {
1209 logmsg(LL_DEBUG, "cannot stat %s: %s\n",
1210 path, strerror(errno));
1212 snprintf(path, sizeof(path), "/proc/%d/ns/mnt",
1214 if (stat(path, &caller_ns))
1215 logmsg(LL_DEBUG, "cannot stat %s: %s\n",
1216 path, strerror(errno));
1217 else if (caller_ns.st_ino != parent_ns.st_ino)
1223 * if caller's namespace is different, fork a child and associate it
1224 * with caller's namespace to do credentials preparation
1227 logmsg(LL_TRACE, "caller's namespace is different\n");
1229 /* use pipes to pass info between child and parent processes */
1230 if (pipe(req_fd) == -1) {
1231 logmsg(LL_ERR, "key %08x: pipe failed: %s\n",
1232 keyid, strerror(errno));
1235 if (pipe(reply_fd) == -1) {
1236 logmsg(LL_ERR, "key %08x: pipe failed: %s\n",
1237 keyid, strerror(errno));
1243 logmsg(LL_ERR, "key %08x: can't create child: %s\n",
1244 keyid, strerror(errno));
1247 } else if (child == 0) {
1249 /* child process: carry out credentials preparation
1250 * in caller's namespace */
1252 close(req_fd[0]); /* close unsed read end */
1254 close(reply_fd[1]); /* close unsed write end */
1257 if (associate_with_ns(path) != 0) {
1259 "failed to attach to pid %d namespace: "
1260 "%s\n", uparam.kup_pid, strerror(errno));
1264 logmsg(LL_TRACE, "working in namespace of pid %d\n",
1267 rc = prepare_and_instantiate(cred, keyid,
1270 /* send to parent the status of credentials preparation
1271 * and key instantiation */
1272 rc2 = send_to(req_fd[1], &rc, sizeof(rc));
1273 rc = (rc == 0 ? rc2 : rc);
1277 /* now do real gss negotiation
1278 * parent main process will not wait for us,
1279 * as it has to be done in the background */
1280 rc = lgssc_kr_negotiate(keyid, cred, &uparam,
1285 /* parent process: exchange info with child carrying out
1286 * credentials preparation */
1288 close(req_fd[1]); /* close unsed write end */
1290 close(reply_fd[0]); /* close unsed read end */
1293 /* get status of credentials preparation
1294 * and key instantiation */
1295 rc2 = receive_from(req_fd[0], &rc, sizeof(rc));
1296 if (rc2 != 0 || rc != 0) {
1297 logmsg(LL_ERR, "child failed preparing creds: "
1299 rc2 != 0 ? strerror(-rc2)
1305 * fork a child here to participate in gss negotiation,
1306 * as it has to be done in the background
1311 "key %08x: can't create child: %s\n",
1312 keyid, strerror(errno));
1315 } else if (child == 0) {
1316 struct lgssd_ioctl_param param;
1317 char outbuf[8192] = { 0 };
1318 void *gss_token = NULL;
1320 /* get ioctl buffer from child */
1321 rc = receive_from(req_fd[0], ¶m,
1326 gss_token = calloc(1, param.send_token_size);
1327 if (gss_token == NULL)
1330 /* get gss token from child */
1331 rc = receive_from(req_fd[0], gss_token,
1332 param.send_token_size);
1336 param.send_token = (char *)gss_token;
1337 param.reply_buf_size = sizeof(outbuf);
1338 param.reply_buf = outbuf;
1340 /* do ioctl in place of child process carrying
1341 * out credentials negotiation: as it runs in
1342 * a container, it might not be able to
1344 rc = gss_do_ioctl(¶m);
1348 /* send ioctl status to child */
1349 rc = send_to(reply_fd[1], ¶m.status,
1350 sizeof(param.status));
1353 /* send reply buffer to child */
1354 rc = send_to(reply_fd[1], outbuf,
1364 logmsg(LL_TRACE, "forked child %d\n", child);
1375 logmsg(LL_TRACE, "caller's namespace is the same\n");
1377 logmsg(LL_TRACE, "stick with current namespace\n");
1379 /* In case of prepare error, a key will be instantiated
1380 * all the same. But then we will have to error this key
1381 * instead of doing normal gss negotiation.
1383 rc = prepare_and_instantiate(cred, keyid, uparam.kup_uid);
1386 * fork a child to do the real gss negotiation
1390 logmsg(LL_ERR, "key %08x: can't create child: %s\n",
1391 keyid, strerror(errno));
1394 } else if (child == 0) {
1396 rc = error_kernel_key(keyid, -ENOKEY, 0,
1399 rc = lgssc_kr_negotiate(keyid, cred, &uparam,
1403 logmsg(LL_TRACE, "forked child %d\n", child);