X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fgss%2Fsvcgssd_proc.c;h=731f340b2c41d831686f61176572f662f15862df;hb=449186a71320e3406f6f06cc8cc89be71c016e9f;hp=4983b238d0d5f5803c4ae74417a224bae6d92d35;hpb=0d88b3296cf28c8222359f9a19e42e423e2e3b28;p=fs%2Flustre-release.git diff --git a/lustre/utils/gss/svcgssd_proc.c b/lustre/utils/gss/svcgssd_proc.c index 4983b23..731f340 100644 --- a/lustre/utils/gss/svcgssd_proc.c +++ b/lustre/utils/gss/svcgssd_proc.c @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -45,7 +46,12 @@ #include #include #include -#include +#ifdef HAVE_NETDB_H +# include +#endif + +#include +#include #include "svcgssd.h" #include "gss_util.h" @@ -53,8 +59,10 @@ #include "context.h" #include "cacheio.h" #include "lsupport.h" +#include "gss_oids.h" +#include "sk_utils.h" +#include -extern char * mech2file(gss_OID mech); #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.sptlrpc.context/channel" #define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.sptlrpc.init/channel" @@ -70,16 +78,36 @@ struct svc_cred { uid_t cr_gid; }; +struct svc_nego_data { + /* kernel data*/ + uint32_t lustre_svc; + lnet_nid_t nid; + uint64_t handle_seq; + char nm_name[LUSTRE_NODEMAP_NAME_LENGTH + 1]; + gss_buffer_desc in_tok; + gss_buffer_desc out_tok; + gss_buffer_desc in_handle; + gss_buffer_desc out_handle; + uint32_t maj_stat; + uint32_t min_stat; + + /* userspace data */ + gss_OID mech; + gss_ctx_id_t ctx; + gss_buffer_desc ctx_token; +}; + static int do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, - gss_OID mech, gss_buffer_desc *context_token) + gss_OID mechoid, gss_buffer_desc *context_token) { FILE *f; - char *fname = NULL; + const char *mechname; int err; printerr(2, "doing downcall\n"); - if ((fname = mech2file(mech)) == NULL) + mechname = gss_OID_mech_name(mechoid); + if (mechname == NULL) goto out_err; f = fopen(SVCGSSD_CONTEXT_CHANNEL, "w"); if (f == NULL) { @@ -90,7 +118,7 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, } qword_printhex(f, out_handle->value, out_handle->length); /* XXX are types OK for the rest of this? */ - qword_printint(f, 0x7fffffff); /*XXX need a better timeout */ + qword_printint(f, 3600); /* an hour should be sufficient */ qword_printint(f, cred->cr_remote); qword_printint(f, cred->cr_usr_root); qword_printint(f, cred->cr_usr_mds); @@ -98,7 +126,7 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred, qword_printint(f, cred->cr_mapped_uid); qword_printint(f, cred->cr_uid); qword_printint(f, cred->cr_gid); - qword_print(f, fname); + qword_print(f, mechname); qword_printhex(f, context_token->value, context_token->length); err = qword_eol(f); fclose(f); @@ -126,18 +154,17 @@ send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token, /* XXXARG: */ int g; - printerr(2, "sending null reply\n"); - + printerr(2, "sending reply\n"); qword_addhex(&bp, &blen, in_handle->value, in_handle->length); qword_addhex(&bp, &blen, in_token->value, in_token->length); - qword_addint(&bp, &blen, 0x7fffffff); /*XXX need a better timeout */ + qword_addint(&bp, &blen, 3600); /* an hour should be sufficient */ qword_adduint(&bp, &blen, maj_stat); qword_adduint(&bp, &blen, min_stat); qword_addhex(&bp, &blen, out_handle->value, out_handle->length); qword_addhex(&bp, &blen, out_token->value, out_token->length); qword_addeol(&bp, &blen); if (blen <= 0) { - printerr(0, "WARNING: send_respsonse: message too long\n"); + printerr(0, "WARNING: send_response: message too long\n"); return -1; } g = open(SVCGSSD_INIT_CHANNEL, O_WRONLY); @@ -166,139 +193,6 @@ send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token, #define rpcsec_gsserr_credproblem 13 #define rpcsec_gsserr_ctxproblem 14 -#if 0 -static void -add_supplementary_groups(char *secname, char *name, struct svc_cred *cred) -{ - int ret; - static gid_t *groups = NULL; - - cred->cr_ngroups = NGROUPS; - ret = nfs4_gss_princ_to_grouplist(secname, name, - cred->cr_groups, &cred->cr_ngroups); - if (ret < 0) { - groups = realloc(groups, cred->cr_ngroups*sizeof(gid_t)); - ret = nfs4_gss_princ_to_grouplist(secname, name, - groups, &cred->cr_ngroups); - if (ret < 0) - cred->cr_ngroups = 0; - else { - if (cred->cr_ngroups > NGROUPS) - cred->cr_ngroups = NGROUPS; - memcpy(cred->cr_groups, groups, - cred->cr_ngroups*sizeof(gid_t)); - } - } -} -#endif - -#if 0 -static int -get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred) -{ - u_int32_t maj_stat, min_stat; - gss_buffer_desc name; - char *sname; - int res = -1; - uid_t uid, gid; - gss_OID name_type = GSS_C_NO_OID; - char *secname; - - maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); - if (maj_stat != GSS_S_COMPLETE) { - pgsserr("get_ids: gss_display_name", - maj_stat, min_stat, mech); - goto out; - } - if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */ - !(sname = calloc(name.length + 1, 1))) { - printerr(0, "WARNING: get_ids: error allocating %d bytes " - "for sname\n", name.length + 1); - gss_release_buffer(&min_stat, &name); - goto out; - } - memcpy(sname, name.value, name.length); - printerr(1, "sname = %s\n", sname); - gss_release_buffer(&min_stat, &name); - - res = -EINVAL; - if ((secname = mech2file(mech)) == NULL) { - printerr(0, "WARNING: get_ids: error mapping mech to " - "file for name '%s'\n", sname); - goto out_free; - } - nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ - res = nfs4_gss_princ_to_ids(secname, sname, &uid, &gid); - if (res < 0) { - /* - * -ENOENT means there was no mapping, any other error - * value means there was an error trying to do the - * mapping. - * If there was no mapping, we send down the value -1 - * to indicate that the anonuid/anongid for the export - * should be used. - */ - if (res == -ENOENT) { - cred->cr_uid = -1; - cred->cr_gid = -1; - cred->cr_ngroups = 0; - res = 0; - goto out_free; - } - printerr(0, "WARNING: get_ids: failed to map name '%s' " - "to uid/gid: %s\n", sname, strerror(-res)); - goto out_free; - } - cred->cr_uid = uid; - cred->cr_gid = gid; - add_supplementary_groups(secname, sname, cred); - res = 0; -out_free: - free(sname); -out: - return res; -} -#endif - -#if 0 -void -print_hexl(int pri, unsigned char *cp, int length) -{ - int i, j, jm; - unsigned char c; - - printerr(pri, "length %d\n",length); - printerr(pri, "\n"); - - for (i = 0; i < length; i += 0x10) { - printerr(pri, " %04x: ", (u_int)i); - jm = length - i; - jm = jm > 16 ? 16 : jm; - - for (j = 0; j < jm; j++) { - if ((j % 2) == 1) - printerr(pri,"%02x ", (u_int)cp[i+j]); - else - printerr(pri,"%02x", (u_int)cp[i+j]); - } - for (; j < 16; j++) { - if ((j % 2) == 1) - printerr(pri," "); - else - printerr(pri," "); - } - printerr(pri," "); - - for (j = 0; j < jm; j++) { - c = cp[i+j]; - c = isprint(c) ? c : '.'; - printerr(pri,"%c", c); - } - printerr(pri,"\n"); - } -} -#endif - static int get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, lnet_nid_t nid, uint32_t lustre_svc) @@ -324,7 +218,7 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred, } if (name.length >= 0xffff || /* be certain name.length+1 doesn't overflow */ !(sname = calloc(name.length + 1, 1))) { - printerr(0, "WARNING: get_ids: error allocating %d bytes " + printerr(0, "WARNING: get_ids: error allocating %zu bytes " "for sname\n", name.length + 1); gss_release_buffer(&min_stat, &name); return -1; @@ -463,117 +357,262 @@ typedef struct gss_union_ctx_id_t { gss_ctx_id_t internal_ctx_id; } gss_union_ctx_id_desc, *gss_union_ctx_id_t; -/* - * return -1 only if we detect error during reading from upcall channel, - * all other cases return 0. - */ -int -handle_nullreq(FILE *f) { - uint64_t handle_seq; - char in_tok_buf[TOKEN_BUF_SIZE]; - char in_handle_buf[15]; - char out_handle_buf[15]; - gss_buffer_desc in_tok = {.value = in_tok_buf}, - out_tok = {.value = NULL}, - in_handle = {.value = in_handle_buf}, - out_handle = {.value = out_handle_buf}, - ctx_token = {.value = NULL}, - ignore_out_tok = {.value = NULL}, - /* XXX isn't there a define for this?: */ - null_token = {.value = NULL}; - uint32_t lustre_svc; - lnet_nid_t nid; - u_int32_t ret_flags; - gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; - gss_name_t client_name; - gss_OID mech = GSS_C_NO_OID; - gss_cred_id_t svc_cred; - u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; - u_int32_t ignore_min_stat; - int get_len; - struct svc_cred cred; - static char *lbuf = NULL; - static int lbuflen = 0; - static char *cp; +int handle_sk(struct svc_nego_data *snd) +{ + struct sk_cred *skc = NULL; + struct svc_cred cred; + gss_buffer_desc bufs[7]; + gss_buffer_desc remote_pub_key = GSS_C_EMPTY_BUFFER; + char *target; + uint32_t rc = GSS_S_FAILURE; + uint32_t flags; + int numbufs = 7; + int i; + + printerr(3, "Handling sk request\n"); + + /* See lgss_sk_using_cred() for client side token + * bufs returned are in this order: + * bufs[0] - iv + * bufs[1] - p + * bufs[2] - remote_pub_key + * bufs[3] - target + * bufs[4] - nodemap_hash + * bufs[5] - flags + * bufs[6] - hmac */ + i = sk_decode_netstring(bufs, numbufs, &snd->in_tok); + if (i < numbufs) { + printerr(0, "Invalid netstring token received from peer\n"); + rc = GSS_S_DEFECTIVE_TOKEN; + goto out_err; + } - printerr(2, "handling null request\n"); + /* target must be a null terminated string */ + i = bufs[3].length - 1; + target = bufs[3].value; + if (i >= 0 && target[i] != '\0') { + printerr(0, "Invalid target from netstring\n"); + for (i = 0; i < numbufs; i++) + free(bufs[i].value); + goto out_err; + } - if (readline(fileno(f), &lbuf, &lbuflen) != 1) { - printerr(0, "WARNING: handle_nullreq: " - "failed reading request\n"); - return -1; + memcpy(&flags, bufs[5].value, sizeof(flags)); + skc = sk_create_cred(target, snd->nm_name, be32_to_cpu(flags)); + if (!skc) { + printerr(0, "Failed to create sk credentials\n"); + for (i = 0; i < numbufs; i++) + free(bufs[i].value); + goto out_err; } - cp = lbuf; + /* Take control of all the allocated buffers from decoding */ + skc->sc_kctx.skc_iv = bufs[0]; + skc->sc_p = bufs[1]; + remote_pub_key = bufs[2]; + skc->sc_nodemap_hash = bufs[4]; + skc->sc_hmac = bufs[6]; + + /* Verify that the peer has used a key size greater to or equal + * the size specified by the key file */ + if (skc->sc_flags & LGSS_SVC_PRIV && + skc->sc_p.length < skc->sc_session_keylen) { + printerr(0, "Peer DH parameters do not meet the size required " + "by keyfile\n"); + goto out_err; + } - qword_get(&cp, (char *) &lustre_svc, sizeof(lustre_svc)); - qword_get(&cp, (char *) &nid, sizeof(nid)); - qword_get(&cp, (char *) &handle_seq, sizeof(handle_seq)); - printerr(2, "handling req: svc %u, nid %016llx, idx %llx\n", - lustre_svc, nid, handle_seq); + /* Verify HMAC from peer. Ideally this would happen before anything + * else but we don't have enough information to lookup key without the + * token (fsname and cluster_hash) so it's done shortly after. */ + rc = sk_verify_hmac(skc, bufs, numbufs - 1, EVP_sha256(), + &skc->sc_hmac); + free(bufs[3].value); + free(bufs[5].value); + if (rc != GSS_S_COMPLETE) { + printerr(0, "HMAC verification error: 0x%x from peer %s\n", + rc, libcfs_nid2str((lnet_nid_t) snd->nid)); + goto out_err; + } - get_len = qword_get(&cp, in_handle.value, sizeof(in_handle_buf)); - if (get_len < 0) { - printerr(0, "WARNING: handle_nullreq: " - "failed parsing request\n"); + /* Check that the cluster hash matches the hash of nodemap name */ + rc = sk_verify_hash(snd->nm_name, EVP_sha256(), &skc->sc_nodemap_hash); + if (rc != GSS_S_COMPLETE) { + printerr(0, "Cluster hash failed validation: 0x%x\n", rc); goto out_err; } - in_handle.length = (size_t)get_len; - printerr(3, "in_handle:\n"); - print_hexl(3, in_handle.value, in_handle.length); + rc = sk_gen_params(skc, false); + if (rc != GSS_S_COMPLETE) { + printerr(0, "Failed to generate DH params for responder\n"); + goto out_err; + } + if (sk_compute_key(skc, &remote_pub_key)) { + printerr(0, "Failed to compute session key from DH params\n"); + goto out_err; + } + if (sk_kdf(skc, snd->nid, &snd->in_tok)) { + printerr(0, "Failed to calulate derviced session key\n"); + goto out_err; + } + if (sk_serialize_kctx(skc, &snd->ctx_token)) { + printerr(0, "Failed to serialize context for kernel\n"); + goto out_err; + } - get_len = qword_get(&cp, in_tok.value, sizeof(in_tok_buf)); - if (get_len < 0) { - printerr(0, "WARNING: handle_nullreq: " - "failed parsing request\n"); + /* Server reply only contains the servers public key and HMAC */ + bufs[0] = skc->sc_pub_key; + if (sk_sign_bufs(&skc->sc_kctx.skc_shared_key, bufs, 1, EVP_sha256(), + &skc->sc_hmac)) { + printerr(0, "Failed to sign parameters\n"); + goto out_err; + } + bufs[1] = skc->sc_hmac; + if (sk_encode_netstring(bufs, 2, &snd->out_tok)) { + printerr(0, "Failed to encode netstring for token\n"); goto out_err; } - in_tok.length = (size_t)get_len; - printerr(3, "in_tok:\n"); - print_hexl(3, in_tok.value, in_tok.length); + printerr(2, "Created netstring of %zd bytes\n", snd->out_tok.length); - if (in_handle.length != 0) { /* CONTINUE_INIT case */ - if (in_handle.length != sizeof(ctx)) { - printerr(0, "WARNING: handle_nullreq: " - "input handle has unexpected length %d\n", - in_handle.length); - goto out_err; - } - /* in_handle is the context id stored in the out_handle - * for the GSS_S_CONTINUE_NEEDED case below. */ - memcpy(&ctx, in_handle.value, in_handle.length); + snd->out_handle.length = sizeof(snd->handle_seq); + memcpy(snd->out_handle.value, &snd->handle_seq, + sizeof(snd->handle_seq)); + snd->maj_stat = GSS_S_COMPLETE; + + /* fix credentials */ + memset(&cred, 0, sizeof(cred)); + cred.cr_mapped_uid = -1; + + if (skc->sc_flags & LGSS_ROOT_CRED_ROOT) + cred.cr_usr_root = 1; + if (skc->sc_flags & LGSS_ROOT_CRED_MDT) + cred.cr_usr_mds = 1; + if (skc->sc_flags & LGSS_ROOT_CRED_OST) + cred.cr_usr_oss = 1; + + do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token); + + /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */ + free(remote_pub_key.value); + free(snd->ctx_token.value); + snd->ctx_token.length = 0; + + printerr(3, "sk returning success\n"); + return 0; + +out_err: + snd->maj_stat = rc; + if (remote_pub_key.value) + free(remote_pub_key.value); + if (snd->ctx_token.value) + free(snd->ctx_token.value); + snd->ctx_token.length = 0; + + if (skc) + sk_free_cred(skc); + printerr(3, "sk returning failure\n"); + return -1; +} + +int handle_null(struct svc_nego_data *snd) +{ + struct svc_cred cred; + uint64_t tmp; + uint32_t flags; + + /* null just uses the same token as the return token and for + * for sending to the kernel. It is a single uint64_t. */ + if (snd->in_tok.length != sizeof(uint64_t)) { + snd->maj_stat = GSS_S_DEFECTIVE_TOKEN; + printerr(0, "Invalid token size (%zd) received\n", + snd->in_tok.length); + return -1; + } + snd->out_tok.length = snd->in_tok.length; + snd->out_tok.value = malloc(snd->out_tok.length); + if (!snd->out_tok.value) { + snd->maj_stat = GSS_S_FAILURE; + printerr(0, "Failed to allocate out_tok\n"); + return -1; } - svc_cred = gssd_select_svc_cred(lustre_svc); + snd->ctx_token.length = snd->in_tok.length; + snd->ctx_token.value = malloc(snd->ctx_token.length); + if (!snd->ctx_token.value) { + snd->maj_stat = GSS_S_FAILURE; + printerr(0, "Failed to allocate ctx_token\n"); + return -1; + } + + snd->out_handle.length = sizeof(snd->handle_seq); + memcpy(snd->out_handle.value, &snd->handle_seq, + sizeof(snd->handle_seq)); + snd->maj_stat = GSS_S_COMPLETE; + + memcpy(&tmp, snd->in_tok.value, sizeof(tmp)); + tmp = be64_to_cpu(tmp); + flags = (uint32_t)(tmp & 0x00000000ffffffff); + memset(&cred, 0, sizeof(cred)); + cred.cr_mapped_uid = -1; + + if (flags & LGSS_ROOT_CRED_ROOT) + cred.cr_usr_root = 1; + if (flags & LGSS_ROOT_CRED_MDT) + cred.cr_usr_mds = 1; + if (flags & LGSS_ROOT_CRED_OST) + cred.cr_usr_oss = 1; + + do_svc_downcall(&snd->out_handle, &cred, snd->mech, &snd->ctx_token); + + /* cleanup ctx_token, out_tok is cleaned up in handle_channel_req */ + free(snd->ctx_token.value); + snd->ctx_token.length = 0; + + return 0; +} + +static int handle_krb(struct svc_nego_data *snd) +{ + u_int32_t ret_flags; + gss_name_t client_name; + gss_buffer_desc ignore_out_tok = {.value = NULL}; + gss_OID mech = GSS_C_NO_OID; + gss_cred_id_t svc_cred; + u_int32_t ignore_min_stat; + struct svc_cred cred; + + svc_cred = gssd_select_svc_cred(snd->lustre_svc); if (!svc_cred) { - printerr(0, "no service credential for svc %u\n", lustre_svc); + printerr(0, "no service credential for svc %u\n", + snd->lustre_svc); goto out_err; } - maj_stat = gss_accept_sec_context(&min_stat, &ctx, svc_cred, - &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name, - &mech, &out_tok, &ret_flags, NULL, NULL); + snd->maj_stat = gss_accept_sec_context(&snd->min_stat, &snd->ctx, + svc_cred, &snd->in_tok, + GSS_C_NO_CHANNEL_BINDINGS, + &client_name, &mech, + &snd->out_tok, &ret_flags, NULL, + NULL); - if (maj_stat == GSS_S_CONTINUE_NEEDED) { + if (snd->maj_stat == GSS_S_CONTINUE_NEEDED) { printerr(1, "gss_accept_sec_context GSS_S_CONTINUE_NEEDED\n"); /* Save the context handle for future calls */ - out_handle.length = sizeof(ctx); - memcpy(out_handle.value, &ctx, sizeof(ctx)); - goto continue_needed; - } - else if (maj_stat != GSS_S_COMPLETE) { + snd->out_handle.length = sizeof(snd->ctx); + memcpy(snd->out_handle.value, &snd->ctx, sizeof(snd->ctx)); + return 0; + } else if (snd->maj_stat != GSS_S_COMPLETE) { printerr(0, "WARNING: gss_accept_sec_context failed\n"); - pgsserr("handle_nullreq: gss_accept_sec_context", - maj_stat, min_stat, mech); + pgsserr("handle_krb: gss_accept_sec_context", + snd->maj_stat, snd->min_stat, mech); goto out_err; } - if (get_ids(client_name, mech, &cred, nid, lustre_svc)) { + if (get_ids(client_name, mech, &cred, snd->nid, snd->lustre_svc)) { /* get_ids() prints error msg */ - maj_stat = GSS_S_BAD_NAME; /* XXX ? */ + snd->maj_stat = GSS_S_BAD_NAME; /* XXX ? */ gss_release_name(&ignore_min_stat, &client_name); goto out_err; } @@ -581,35 +620,168 @@ handle_nullreq(FILE *f) { /* Context complete. Pass handle_seq in out_handle to use * for context lookup in the kernel. */ - out_handle.length = sizeof(handle_seq); - memcpy(out_handle.value, &handle_seq, sizeof(handle_seq)); + snd->out_handle.length = sizeof(snd->handle_seq); + memcpy(snd->out_handle.value, &snd->handle_seq, + sizeof(snd->handle_seq)); /* kernel needs ctx to calculate verifier on null response, so * must give it context before doing null call: */ - if (serialize_context_for_kernel(ctx, &ctx_token, mech)) { - printerr(0, "WARNING: handle_nullreq: " - "serialize_context_for_kernel failed\n"); - maj_stat = GSS_S_FAILURE; + if (serialize_context_for_kernel(snd->ctx, &snd->ctx_token, mech)) { + printerr(0, "WARNING: handle_krb: " + "serialize_context_for_kernel failed\n"); + snd->maj_stat = GSS_S_FAILURE; goto out_err; } /* We no longer need the gss context */ - gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok); - - do_svc_downcall(&out_handle, &cred, mech, &ctx_token); -continue_needed: - send_response(f, &in_handle, &in_tok, maj_stat, min_stat, - &out_handle, &out_tok); -out: - if (ctx_token.value != NULL) - free(ctx_token.value); - if (out_tok.value != NULL) - gss_release_buffer(&ignore_min_stat, &out_tok); + gss_delete_sec_context(&ignore_min_stat, &snd->ctx, &ignore_out_tok); + do_svc_downcall(&snd->out_handle, &cred, mech, &snd->ctx_token); + return 0; out_err: - if (ctx != GSS_C_NO_CONTEXT) - gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok); - send_response(f, &in_handle, &in_tok, maj_stat, min_stat, - &null_token, &null_token); - goto out; + if (snd->ctx != GSS_C_NO_CONTEXT) + gss_delete_sec_context(&ignore_min_stat, &snd->ctx, + &ignore_out_tok); + + return 1; +} + +/* + * return -1 only if we detect error during reading from upcall channel, + * all other cases return 0. + */ +int handle_channel_request(FILE *f) +{ + char in_tok_buf[TOKEN_BUF_SIZE]; + char in_handle_buf[15]; + char out_handle_buf[15]; + gss_buffer_desc ctx_token = {.value = NULL}, + null_token = {.value = NULL}; + uint32_t lustre_mech; + static char *lbuf; + static int lbuflen; + static char *cp; + int get_len; + int rc = 1; + u_int32_t ignore_min_stat; + struct svc_nego_data snd = { + .in_tok.value = in_tok_buf, + .in_handle.value = in_handle_buf, + .out_handle.value = out_handle_buf, + .maj_stat = GSS_S_FAILURE, + .ctx = GSS_C_NO_CONTEXT, + }; + + printerr(2, "handling request\n"); + if (readline(fileno(f), &lbuf, &lbuflen) != 1) { + printerr(0, "WARNING: failed reading request\n"); + return -1; + } + + cp = lbuf; + + /* see rsi_request() for the format of data being input here */ + qword_get(&cp, (char *)&snd.lustre_svc, sizeof(snd.lustre_svc)); + + /* lustre_svc is the svc and gss subflavor */ + lustre_mech = (snd.lustre_svc & LUSTRE_GSS_MECH_MASK) >> + LUSTRE_GSS_MECH_SHIFT; + snd.lustre_svc = snd.lustre_svc & LUSTRE_GSS_SVC_MASK; + switch (lustre_mech) { + case LGSS_MECH_KRB5: + if (!krb_enabled) { + printerr(1, "WARNING: Request for kerberos but service " + "support not enabled\n"); + goto ignore; + } + snd.mech = &krb5oid; + break; + case LGSS_MECH_NULL: + if (!null_enabled) { + printerr(1, "WARNING: Request for gssnull but service " + "support not enabled\n"); + goto ignore; + } + snd.mech = &nulloid; + break; + case LGSS_MECH_SK: + if (!sk_enabled) { + printerr(1, "WARNING: Request for sk but service " + "support not enabled\n"); + goto ignore; + } + snd.mech = &skoid; + break; + default: + printerr(0, "WARNING: invalid mechanism recevied: %d\n", + lustre_mech); + goto out_err; + break; + } + + qword_get(&cp, (char *)&snd.nid, sizeof(snd.nid)); + qword_get(&cp, (char *)&snd.handle_seq, sizeof(snd.handle_seq)); + qword_get(&cp, snd.nm_name, sizeof(snd.nm_name)); + printerr(2, "handling req: svc %u, nid %016llx, idx %"PRIx64" nodemap " + "%s\n", snd.lustre_svc, snd.nid, snd.handle_seq, snd.nm_name); + + get_len = qword_get(&cp, snd.in_handle.value, sizeof(in_handle_buf)); + if (get_len < 0) { + printerr(0, "WARNING: failed parsing request\n"); + goto out_err; + } + snd.in_handle.length = (size_t)get_len; + + printerr(3, "in_handle:\n"); + print_hexl(3, snd.in_handle.value, snd.in_handle.length); + + get_len = qword_get(&cp, snd.in_tok.value, sizeof(in_tok_buf)); + if (get_len < 0) { + printerr(0, "WARNING: failed parsing request\n"); + goto out_err; + } + snd.in_tok.length = (size_t)get_len; + + printerr(3, "in_tok:\n"); + print_hexl(3, snd.in_tok.value, snd.in_tok.length); + + if (snd.in_handle.length != 0) { /* CONTINUE_INIT case */ + if (snd.in_handle.length != sizeof(snd.ctx)) { + printerr(0, "WARNING: input handle has unexpected " + "length %zu\n", snd.in_handle.length); + goto out_err; + } + /* in_handle is the context id stored in the out_handle + * for the GSS_S_CONTINUE_NEEDED case below. */ + memcpy(&snd.ctx, snd.in_handle.value, snd.in_handle.length); + } + + if (lustre_mech == LGSS_MECH_KRB5) + rc = handle_krb(&snd); + else if (lustre_mech == LGSS_MECH_SK) + rc = handle_sk(&snd); + else if (lustre_mech == LGSS_MECH_NULL) + rc = handle_null(&snd); + else + printerr(0, "WARNING: Received or request for" + "subflavor that is not enabled: %d\n", lustre_mech); + +out_err: + /* Failures send a null token */ + if (rc == 0) + send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat, + snd.min_stat, &snd.out_handle, &snd.out_tok); + else + send_response(f, &snd.in_handle, &snd.in_tok, snd.maj_stat, + snd.min_stat, &null_token, &null_token); + + /* cleanup buffers */ + if (snd.ctx_token.value != NULL) + free(ctx_token.value); + if (snd.out_tok.value != NULL) + gss_release_buffer(&ignore_min_stat, &snd.out_tok); + + /* For junk wire data just ignore */ +ignore: + return 0; }