X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fgss%2Flgss_keyring.c;h=bf936de51f89e9b8b0940edba56deca9909abcd2;hb=2ffbcc9f9ad930fee2df53238b3244b7c3e6bb91;hp=2a3fdf2dcfbfaab450dbbfaa2027145f00447d68;hpb=f6995cf04407dff15d6ca79ca44cfa97dc6eb014;p=fs%2Flustre-release.git diff --git a/lustre/utils/gss/lgss_keyring.c b/lustre/utils/gss/lgss_keyring.c index 2a3fdf2..bf936de 100644 --- a/lustre/utils/gss/lgss_keyring.c +++ b/lustre/utils/gss/lgss_keyring.c @@ -15,11 +15,7 @@ * * You should have received a copy of the GNU General Public License * version 2 along with this program; If not, see - * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf - * - * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, - * CA 95054 USA or visit www.sun.com if you need additional information or - * have any questions. + * http://www.gnu.org/licenses/gpl-2.0.html * * GPL HEADER END */ @@ -40,16 +36,21 @@ * Author: Eric Mei */ +#include +#include +#include #include #include #include #include +#include #include #include #include #include #include +#include #include #include "lsupport.h" #include "lgss_utils.h" @@ -65,67 +66,71 @@ static char *g_service = NULL; * all data about negotiation */ struct lgss_nego_data { - uint32_t lnd_established:1; - - int lnd_secid; - uint32_t lnd_uid; - uint32_t lnd_lsvc; - char *lnd_uuid; - - gss_OID lnd_mech; /* mech OID */ - gss_name_t lnd_svc_name; /* service name */ - u_int lnd_req_flags; /* request flags */ - gss_cred_id_t lnd_cred; /* credential */ - gss_ctx_id_t lnd_ctx; /* session context */ - gss_buffer_desc lnd_rmt_ctx; /* remote handle of context */ - uint32_t lnd_seq_win; /* sequence window */ - - int lnd_rpc_err; - int lnd_gss_err; + uint32_t lnd_established:1; + + int lnd_secid; + uint32_t lnd_uid; + uint32_t lnd_lsvc; + char *lnd_uuid; + + gss_OID lnd_mech; /* mech OID */ + gss_name_t lnd_svc_name; /* service name */ + unsigned int lnd_req_flags; /* request flags */ + gss_cred_id_t lnd_cred; /* credential */ + gss_ctx_id_t lnd_ctx; /* session context */ + gss_buffer_desc lnd_rmt_ctx; /* remote handle of context */ + gss_buffer_desc lnd_ctx_token; /* context token for kernel */ + uint32_t lnd_seq_win; /* sequence window */ + + int lnd_rpc_err; + int lnd_gss_err; }; /* * context creation response */ struct lgss_init_res { - gss_buffer_desc gr_ctx; /* context handle */ - u_int gr_major; /* major status */ - u_int gr_minor; /* minor status */ - u_int gr_win; /* sequence window */ - gss_buffer_desc gr_token; /* token */ + gss_buffer_desc gr_ctx; /* context handle */ + unsigned int gr_major; /* major status */ + unsigned int gr_minor; /* minor status */ + unsigned int gr_win; /* sequence window */ + gss_buffer_desc gr_token; /* token */ }; struct keyring_upcall_param { - uint32_t kup_ver; - uint32_t kup_secid; - uint32_t kup_uid; - uint32_t kup_fsuid; - uint32_t kup_gid; - uint32_t kup_fsgid; - uint32_t kup_svc; - uint64_t kup_nid; - char kup_tgt[64]; - char kup_mech[16]; - unsigned int kup_is_root:1, - kup_is_mdt:1, - kup_is_ost:1; + uint32_t kup_ver; + uint32_t kup_secid; + uint32_t kup_uid; + uint32_t kup_fsuid; + uint32_t kup_gid; + uint32_t kup_fsgid; + uint32_t kup_svc; + uint64_t kup_nid; + uint64_t kup_selfnid; + char kup_svc_type; + char kup_tgt[64]; + char kup_mech[16]; + unsigned int kup_is_root:1, + kup_is_mdt:1, + kup_is_ost:1; + uint32_t kup_pid; }; /**************************************** * child process: gss negotiation * ****************************************/ -#define INIT_CHANNEL "/proc/fs/lustre/sptlrpc/gss/init_channel" - int do_nego_rpc(struct lgss_nego_data *lnd, gss_buffer_desc *gss_token, struct lgss_init_res *gr) { - struct lgssd_ioctl_param param; - struct passwd *pw; - int fd, ret, res; - char outbuf[8192]; - unsigned int *p; + struct lgssd_ioctl_param param; + struct passwd *pw; + int fd, ret, res; + char outbuf[8192]; + unsigned int *p; + glob_t path; + int rc; logmsg(LL_TRACE, "start negotiation rpc\n"); @@ -147,38 +152,44 @@ int do_nego_rpc(struct lgss_nego_data *lnd, param.reply_buf_size = sizeof(outbuf); param.reply_buf = outbuf; - logmsg(LL_TRACE, "to open " INIT_CHANNEL "\n"); + rc = cfs_get_param_paths(&path, "sptlrpc/gss/init_channel"); + if (rc != 0) + return rc; - fd = open(INIT_CHANNEL, O_WRONLY); + logmsg(LL_TRACE, "to open %s\n", path.gl_pathv[0]); + + fd = open(path.gl_pathv[0], O_WRONLY); if (fd < 0) { - logmsg(LL_ERR, "can't open " INIT_CHANNEL "\n"); - return -EACCES; + logmsg(LL_ERR, "can't open %s\n", path.gl_pathv[0]); + rc = -EACCES; + goto out_params; } - logmsg(LL_TRACE, "to down-write\n"); + logmsg(LL_TRACE, "to down-write\n"); - ret = write(fd, ¶m, sizeof(param)); - if (ret != sizeof(param)) { - logmsg(LL_ERR, "lustre ioctl err: %d\n", strerror(errno)); - close(fd); - return -EACCES; - } - close(fd); + ret = write(fd, ¶m, sizeof(param)); + close(fd); + if (ret != sizeof(param)) { + logmsg(LL_ERR, "lustre ioctl err: %s\n", strerror(errno)); + rc = -EACCES; + goto out_params; + } logmsg(LL_TRACE, "do_nego_rpc: to parse reply\n"); if (param.status) { - logmsg(LL_ERR, "status: %d (%s)\n", - param.status, strerror((int)param.status)); + logmsg(LL_ERR, "status: %ld (%s)\n", + param.status, strerror((int)(-param.status))); /* kernel return -ETIMEDOUT means the rpc timedout, we should * notify the caller to reinitiate the gss negotiation, by * returning -ERESTART */ if (param.status == -ETIMEDOUT) - return -ERESTART; - else - return param.status; - } + rc = -ERESTART; + else + rc = param.status; + goto out_params; + } p = (unsigned int *)outbuf; res = *p++; @@ -186,19 +197,92 @@ int do_nego_rpc(struct lgss_nego_data *lnd, gr->gr_minor = *p++; gr->gr_win = *p++; - gr->gr_ctx.length = *p++; - gr->gr_ctx.value = malloc(gr->gr_ctx.length); - memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length); - p += (((gr->gr_ctx.length + 3) & ~3) / 4); - - gr->gr_token.length = *p++; - gr->gr_token.value = malloc(gr->gr_token.length); - memcpy(gr->gr_token.value, p, gr->gr_token.length); - p += (((gr->gr_token.length + 3) & ~3) / 4); - - logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %d, token len %d, " \ + gr->gr_ctx.length = *p++; + gr->gr_ctx.value = malloc(gr->gr_ctx.length); + if (gr->gr_ctx.value == NULL) + return -ENOMEM; + memcpy(gr->gr_ctx.value, p, gr->gr_ctx.length); + p += (((gr->gr_ctx.length + 3) & ~3) / 4); + + gr->gr_token.length = *p++; + gr->gr_token.value = malloc(gr->gr_token.length); + if (gr->gr_token.value == NULL) { + free(gr->gr_ctx.value); + return -ENOMEM; + } + memcpy(gr->gr_token.value, p, gr->gr_token.length); + p += (((gr->gr_token.length + 3) & ~3) / 4); + + logmsg(LL_DEBUG, "do_nego_rpc: receive handle len %zu, token len %zu, " "res %d\n", gr->gr_ctx.length, gr->gr_token.length, res); +out_params: + cfs_free_param_data(&path); + return rc; +} + +/* This is used by incomplete GSSAPI implementations that can't use + * gss_init_sec_context and will parse the token themselves (gssnull and sk). + * Callers should have cred->lc_mech_token pointing to a gss_buffer_desc + * token to send to the peer as part of the SEC_CTX_INIT operation. The return + * RPC's token with be in gr.gr_token which is validated using + * lgss_validate_cred. */ +static int lgssc_negotiation_manual(struct lgss_nego_data *lnd, + struct lgss_cred *cred) +{ + struct lgss_init_res gr; + OM_uint32 min_stat; + int rc; + + logmsg(LL_TRACE, "starting gss negotation\n"); + memset(&gr, 0, sizeof(gr)); + + lnd->lnd_rpc_err = do_nego_rpc(lnd, &cred->lc_mech_token, &gr); + if (lnd->lnd_rpc_err) { + logmsg(LL_ERR, "negotiation rpc error %d\n", lnd->lnd_rpc_err); + rc = lnd->lnd_rpc_err; + goto out_error; + } + + if (gr.gr_major == GSS_S_CONTINUE_NEEDED) { + rc = -EAGAIN; + goto out_error; + + } else if (gr.gr_major != GSS_S_COMPLETE) { + lnd->lnd_gss_err = gr.gr_major; + logmsg(LL_ERR, "negotiation gss error %x\n", lnd->lnd_gss_err); + rc = -ENOTCONN; + goto out_error; + } + + if (gr.gr_ctx.length == 0 || gr.gr_token.length == 0) { + logmsg(LL_ERR, "zero length context or token received\n"); + rc = -EINVAL; + goto out_error; + } + + rc = lgss_validate_cred(cred, &gr.gr_token, &lnd->lnd_ctx_token); + if (rc) { + logmsg(LL_ERR, "peer token failed validation\n"); + goto out_error; + } + + lnd->lnd_established = 1; + lnd->lnd_seq_win = gr.gr_win; + lnd->lnd_rmt_ctx = gr.gr_ctx; + + if (gr.gr_token.length != 0) + gss_release_buffer(&min_stat, &gr.gr_token); + + logmsg(LL_DEBUG, "successfully negotiated a context\n"); return 0; + +out_error: + if (gr.gr_ctx.length != 0) + gss_release_buffer(&min_stat, &gr.gr_ctx); + if (gr.gr_token.length != 0) + gss_release_buffer(&min_stat, &gr.gr_token); + + return rc; } /* @@ -310,18 +394,18 @@ static int lgssc_negotiation(struct lgss_nego_data *lnd) * if return error, the lnd_rpc_err or lnd_gss_err is set. */ static int lgssc_init_nego_data(struct lgss_nego_data *lnd, - struct keyring_upcall_param *kup, - lgss_mech_t mech) + struct keyring_upcall_param *kup, + enum lgss_mech mech) { gss_buffer_desc sname; OM_uint32 maj_stat, min_stat; memset(lnd, 0, sizeof(*lnd)); - lnd->lnd_secid = kup->kup_secid; - lnd->lnd_uid = kup->kup_uid; - lnd->lnd_lsvc = kup->kup_svc; - lnd->lnd_uuid = kup->kup_tgt; + lnd->lnd_secid = kup->kup_secid; + lnd->lnd_uid = kup->kup_uid; + lnd->lnd_lsvc = kup->kup_svc | mech << LUSTRE_GSS_MECH_SHIFT; + lnd->lnd_uuid = kup->kup_tgt; lnd->lnd_established = 0; lnd->lnd_svc_name = GSS_C_NO_NAME; @@ -331,14 +415,23 @@ static int lgssc_init_nego_data(struct lgss_nego_data *lnd, lnd->lnd_seq_win = 0; switch (mech) { - case LGSS_MECH_KRB5: - lnd->lnd_mech = (gss_OID) &krb5oid; - lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG; - break; - default: - logmsg(LL_ERR, "invalid mech: %d\n", mech); - lnd->lnd_rpc_err = -EACCES; - return -1; + case LGSS_MECH_KRB5: + lnd->lnd_mech = (gss_OID)&krb5oid; + lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG; + break; + case LGSS_MECH_NULL: + lnd->lnd_mech = (gss_OID)&nulloid; + break; +#ifdef HAVE_OPENSSL_SSK + case LGSS_MECH_SK: + lnd->lnd_mech = (gss_OID)&skoid; + lnd->lnd_req_flags = GSS_C_MUTUAL_FLAG; + break; +#endif + default: + logmsg(LL_ERR, "invalid mech: %d\n", mech); + lnd->lnd_rpc_err = -EACCES; + return -1; } sname.value = g_service; @@ -463,21 +556,14 @@ out: return rc; } -/* - * note we inherited assumed authority from parent process - */ -static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred, - struct keyring_upcall_param *kup) +static int lgssc_kr_negotiate_krb(key_serial_t keyid, struct lgss_cred *cred, + struct keyring_upcall_param *kup) { - struct lgss_nego_data lnd; - gss_buffer_desc token = GSS_C_EMPTY_BUFFER; - OM_uint32 min_stat; - int rc = -1; + struct lgss_nego_data lnd; + OM_uint32 min_stat; + int rc = -1; - logmsg(LL_TRACE, "child start on behalf of key %08x: " - "cred %p, uid %u, svc %u, nid %llx, uids: %u:%u/%u:%u\n", - keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid, - kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid); + memset(&lnd, 0, sizeof(lnd)); if (lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid)) { logmsg(LL_ERR, "key %08x: failed to construct service " @@ -506,29 +592,123 @@ static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred, goto out; } - rc = serialize_context_for_kernel(lnd.lnd_ctx, &token, lnd.lnd_mech); - if (rc) { - logmsg(LL_ERR, "key %08x: failed to export context\n", keyid); - error_kernel_key(keyid, rc, lnd.lnd_gss_err); - goto out; - } + rc = serialize_context_for_kernel(lnd.lnd_ctx, &lnd.lnd_ctx_token, + lnd.lnd_mech); + if (rc) { + logmsg(LL_ERR, "key %08x: failed to export context\n", keyid); + error_kernel_key(keyid, rc, lnd.lnd_gss_err); + goto out; + } - rc = update_kernel_key(keyid, &lnd, &token); - if (rc) - goto out; + rc = update_kernel_key(keyid, &lnd, &lnd.lnd_ctx_token); + if (rc) + goto out; - rc = 0; - logmsg(LL_INFO, "key %08x for user %u is updated OK!\n", - keyid, kup->kup_uid); + rc = 0; + logmsg(LL_INFO, "key %08x for user %u is updated OK!\n", + keyid, kup->kup_uid); out: - if (token.length != 0) - gss_release_buffer(&min_stat, &token); + if (lnd.lnd_ctx_token.length != 0) + gss_release_buffer(&min_stat, &lnd.lnd_ctx_token); - lgssc_fini_nego_data(&lnd); + lgssc_fini_nego_data(&lnd); out_cred: - lgss_release_cred(cred); - return rc; + lgss_release_cred(cred); + return rc; +} + +static int lgssc_kr_negotiate_manual(key_serial_t keyid, struct lgss_cred *cred, + struct keyring_upcall_param *kup) +{ + struct lgss_nego_data lnd; + OM_uint32 min_stat; + int rc; + +retry: + memset(&lnd, 0, sizeof(lnd)); + + rc = lgss_get_service_str(&g_service, kup->kup_svc, kup->kup_nid); + if (rc) { + logmsg(LL_ERR, "key %08x: failed to construct service " + "string\n", keyid); + error_kernel_key(keyid, -EACCES, 0); + goto out_cred; + } + + rc = lgss_using_cred(cred); + if (rc) { + logmsg(LL_ERR, "key %08x: can't use cred\n", keyid); + error_kernel_key(keyid, -EACCES, 0); + goto out_cred; + } + + rc = lgssc_init_nego_data(&lnd, kup, cred->lc_mech->lmt_mech_n); + if (rc) { + logmsg(LL_ERR, "key %08x: failed to initialize " + "negotiation data\n", keyid); + error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err); + goto out_cred; + } + + /* + * Handles the negotiation but then calls lgss_validate to make sure + * the token is valid. It also populates the lnd_ctx_token for the + * update to the kernel key + */ + rc = lgssc_negotiation_manual(&lnd, cred); + if (rc == -EAGAIN) { + logmsg(LL_ERR, "Failed negotiation must retry\n"); + goto retry; + + } else if (rc) { + logmsg(LL_ERR, "key %08x: failed to negotiate\n", keyid); + error_kernel_key(keyid, lnd.lnd_rpc_err, lnd.lnd_gss_err); + goto out; + } + + rc = update_kernel_key(keyid, &lnd, &lnd.lnd_ctx_token); + if (rc) + goto out; + + logmsg(LL_INFO, "key %08x for user %u is updated OK!\n", + keyid, kup->kup_uid); +out: + if (lnd.lnd_ctx_token.length != 0) + gss_release_buffer(&min_stat, &lnd.lnd_ctx_token); + + lgssc_fini_nego_data(&lnd); + +out_cred: + lgss_release_cred(cred); + return rc; +} + +/* + * note we inherited assumed authority from parent process + */ +static int lgssc_kr_negotiate(key_serial_t keyid, struct lgss_cred *cred, + struct keyring_upcall_param *kup) +{ + int rc; + + logmsg(LL_TRACE, "child start on behalf of key %08x: " + "cred %p, uid %u, svc %u, nid %"PRIx64", uids: %u:%u/%u:%u\n", + keyid, cred, cred->lc_uid, cred->lc_tgt_svc, cred->lc_tgt_nid, + kup->kup_uid, kup->kup_gid, kup->kup_fsuid, kup->kup_fsgid); + + switch (cred->lc_mech->lmt_mech_n) { + case LGSS_MECH_NULL: + case LGSS_MECH_SK: + rc = lgssc_kr_negotiate_manual(keyid, cred, kup); + break; + case LGSS_MECH_KRB5: + default: + rc = lgssc_kr_negotiate_krb(keyid, cred, kup); + break; + } + + return rc; } /* @@ -538,19 +718,22 @@ out_cred: * [2]: uid (uint) * [3]: gid (uint) * [4]: flags (string) FMT: r-root; m-mdt; o-ost - * [5]: lustre_svc (uint) - * [6]: target_nid (uint64) - * [7]: target_uuid (string) + * [5]: svc type (char) + * [6]: lustre_svc (int) + * [7]: target_nid (uint64) + * [8]: target_uuid (string) + * [9]: self_nid (uint64) + * [10]: pid (uint) */ static int parse_callout_info(const char *coinfo, struct keyring_upcall_param *uparam) { - const int nargs = 8; - char buf[1024]; - char *string = buf; - int length, i; - char *data[nargs]; - char *pos; + const int nargs = 11; + char buf[1024]; + char *string = buf; + int length, i; + char *data[nargs]; + char *pos; length = strlen(coinfo) + 1; if (length > 1024) { @@ -572,54 +755,79 @@ static int parse_callout_info(const char *coinfo, } data[i] = string; - logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%s,%s,%s\n", - data[0], data[1], data[2], data[3], data[4], data[5], - data[6], data[7]); + logmsg(LL_TRACE, "components: %s,%s,%s,%s,%s,%c,%s,%s,%s,%s,%s\n", + data[0], data[1], data[2], data[3], data[4], data[5][0], + data[6], data[7], data[8], data[9], data[10]); - uparam->kup_secid = strtol(data[0], NULL, 0); + uparam->kup_secid = strtol(data[0], NULL, 0); strlcpy(uparam->kup_mech, data[1], sizeof(uparam->kup_mech)); - uparam->kup_uid = strtol(data[2], NULL, 0); - uparam->kup_gid = strtol(data[3], NULL, 0); - if (strchr(data[4], 'r')) - uparam->kup_is_root = 1; - if (strchr(data[4], 'm')) - uparam->kup_is_mdt = 1; - if (strchr(data[4], 'o')) - uparam->kup_is_ost = 1; - uparam->kup_svc = strtol(data[5], NULL, 0); - uparam->kup_nid = strtoll(data[6], NULL, 0); - strlcpy(uparam->kup_tgt, data[7], sizeof(uparam->kup_tgt)); - - logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u " - "is_root %d, is_mdt %d, is_ost %d, svc %d, nid 0x%llx, tgt %s\n", - uparam->kup_secid, uparam->kup_mech, - uparam->kup_uid, uparam->kup_gid, - uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost, - uparam->kup_svc, uparam->kup_nid, uparam->kup_tgt); - return 0; + uparam->kup_uid = strtol(data[2], NULL, 0); + uparam->kup_gid = strtol(data[3], NULL, 0); + if (strchr(data[4], 'r')) + uparam->kup_is_root = 1; + if (strchr(data[4], 'm')) + uparam->kup_is_mdt = 1; + if (strchr(data[4], 'o')) + uparam->kup_is_ost = 1; + uparam->kup_svc_type = data[5][0]; + uparam->kup_svc = strtol(data[6], NULL, 0); + uparam->kup_nid = strtoll(data[7], NULL, 0); + strlcpy(uparam->kup_tgt, data[8], sizeof(uparam->kup_tgt)); + uparam->kup_selfnid = strtoll(data[9], NULL, 0); + uparam->kup_pid = strtol(data[10], NULL, 0); + + logmsg(LL_DEBUG, "parse call out info: secid %d, mech %s, ugid %u:%u, " + "is_root %d, is_mdt %d, is_ost %d, svc type %c, svc %d, " + "nid 0x%"PRIx64", tgt %s, self nid 0x%"PRIx64", pid %d\n", + uparam->kup_secid, uparam->kup_mech, + uparam->kup_uid, uparam->kup_gid, + uparam->kup_is_root, uparam->kup_is_mdt, uparam->kup_is_ost, + uparam->kup_svc_type, uparam->kup_svc, uparam->kup_nid, + uparam->kup_tgt, uparam->kup_selfnid, uparam->kup_pid); + return 0; } -#define LOG_LEVEL_PATH "/proc/fs/lustre/sptlrpc/gss/lgss_keyring/debug_level" - static void set_log_level() { - FILE *file; - unsigned int level; - - file = fopen(LOG_LEVEL_PATH, "r"); - if (file == NULL) - return; + unsigned int level; + glob_t path; + FILE *file; + + if (cfs_get_param_paths(&path, + "sptlrpc/gss/lgss_keyring/debug_level") != 0) + return; + file = fopen(path.gl_pathv[0], "r"); + if (file == NULL) { + cfs_free_param_data(&path); + return; + } + + if (fscanf(file, "%u", &level) != 1) + goto out; + + if (level >= LL_MAX) + goto out; + + lgss_set_loglevel(level); +out: + cfs_free_param_data(&path); + fclose(file); +} - if (fscanf(file, "%u", &level) != 1) - goto out; +#ifdef HAVE_SETNS +static int associate_with_ns(char *path) +{ + int fd, rc = -1; - if (level >= LL_MAX) - goto out; + fd = open(path, O_RDONLY); + if (fd != -1) { + rc = setns(fd, 0); + close(fd); + } - lgss_set_loglevel(level); -out: - fclose(file); + return rc; } +#endif /**************************************** * main process * @@ -634,6 +842,10 @@ int main(int argc, char *argv[]) pid_t child; struct lgss_mech_type *mech; struct lgss_cred *cred; +#ifdef HAVE_SETNS + char path[PATH_MAX]; + struct stat parent_ns = { .st_ino = 0 }, caller_ns = { .st_ino = 0 }; +#endif set_log_level(); @@ -717,18 +929,45 @@ int main(int argc, char *argv[]) return 1; } - cred->lc_uid = uparam.kup_uid; - cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0; - cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0; - cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0; - cred->lc_tgt_nid = uparam.kup_nid; - cred->lc_tgt_svc = uparam.kup_svc; - - if (lgss_prepare_cred(cred)) { - logmsg(LL_ERR, "key %08x: failed to prepare credentials " - "for user %d\n", keyid, uparam.kup_uid); - return 1; - } + cred->lc_uid = uparam.kup_uid; + cred->lc_root_flags |= uparam.kup_is_root ? LGSS_ROOT_CRED_ROOT : 0; + cred->lc_root_flags |= uparam.kup_is_mdt ? LGSS_ROOT_CRED_MDT : 0; + cred->lc_root_flags |= uparam.kup_is_ost ? LGSS_ROOT_CRED_OST : 0; + cred->lc_tgt_nid = uparam.kup_nid; + cred->lc_tgt_svc = uparam.kup_svc; + cred->lc_tgt_uuid = uparam.kup_tgt; + cred->lc_svc_type = uparam.kup_svc_type; + cred->lc_self_nid = uparam.kup_selfnid; + +#ifdef HAVE_SETNS + /* Is caller in different namespace? */ + snprintf(path, sizeof(path), "/proc/%d/ns/mnt", getpid()); + if (stat(path, &parent_ns)) + logmsg(LL_ERR, "cannot stat %s: %s\n", path, strerror(errno)); + snprintf(path, sizeof(path), "/proc/%d/ns/mnt", uparam.kup_pid); + if (stat(path, &caller_ns)) + logmsg(LL_ERR, "cannot stat %s: %s\n", path, strerror(errno)); + if (caller_ns.st_ino != parent_ns.st_ino) { + /* + * do credentials preparation in caller's namespace + */ + if (associate_with_ns(path) != 0) { + logmsg(LL_ERR, "failed to attach to pid %d namespace: " + "%s\n", uparam.kup_pid, strerror(errno)); + return 1; + } + logmsg(LL_TRACE, "working in namespace of pid %d\n", + uparam.kup_pid); + } else { + logmsg(LL_TRACE, "caller's namespace is the same\n"); + } +#endif /* HAVE_SETNS */ + + if (lgss_prepare_cred(cred)) { + logmsg(LL_ERR, "key %08x: failed to prepare credentials " + "for user %d\n", keyid, uparam.kup_uid); + return 1; + } /* pre initialize the key. note the keyring linked to is actually of the * original requesting process, not _this_ upcall process. if it's for