diff options
Diffstat (limited to 'utils/gssd')
-rw-r--r-- | utils/gssd/context.c | 203 | ||||
-rw-r--r-- | utils/gssd/gssd_proc.c | 96 | ||||
-rw-r--r-- | utils/gssd/krb5_util.c | 10 |
3 files changed, 213 insertions, 96 deletions
diff --git a/utils/gssd/context.c b/utils/gssd/context.c index 08979f3..8f2f359 100644 --- a/utils/gssd/context.c +++ b/utils/gssd/context.c @@ -42,6 +42,10 @@ #include "err_util.h" #include "context.h" +#ifdef HAVE_SPKM3_H +#include <spkm3.h> +#endif + /* spkm3 seems to actually want it this big, yipes. */ #define MAX_CTX_LEN 4096 @@ -133,49 +137,6 @@ typedef struct _krb5_gss_ctx_id_rec { #endif /* KRB5_VERSION */ #endif /* HAVE_KRB5 */ -/* XXX We have the same issue as above. We can require SPKM-3 source - * at the time we compile gssd, or copy the context structure definitions - * here. - */ - -/* structure typedefs */ - -typedef struct spkm3_ctx_id_t { - int length; - unsigned char *data; -} spkm3_ctx_id, - *spkm3_ctx_id_t; - -/* first pass at spkm3 context. will add a bunch of stuff .... */ - -typedef struct spkm3_gss_ctx_id_desc_t { - spkm3_ctx_id ctx_id; /* per spkm token contextid */ - int established; - int qop; /* negotiated qop */ - gss_OID mech_used; - OM_uint32 ret_flags; - OM_uint32 req_flags; - /* DH should be abstracted to an EVP_ struct able to hold - * various kalg results */ - /* XXX The following is defined as "DH *dh" in the original - * header we're gonna cheat and use "void *dh" here. */ - void *dh; - gss_buffer_desc share_key; - /* derived keys are result from applying the owf_alg to the - * shared key - see spkm3_derive_supkey */ - gss_buffer_desc derived_conf_key; - gss_buffer_desc derived_integ_key; - /* openssl NID's of the negotiated algorithms */ - int keyestb_alg; /* key establishment */ - int owf_alg; /* one way function */ - int intg_alg; /* integrity */ - int conf_alg; /* privacy */ - /* der encoded REQ_TOKEN reqcontets and length */ - unsigned char *der_reqcontents; - int der_req_len; -} spkm3_gss_ctx_id_desc; - - /* adapted from mit kerberos 5 ../lib/gssapi/mechglue/mglueP.h * this is what gets passed around when the mechglue code is enabled : */ typedef struct gss_union_ctx_id_t { @@ -292,6 +253,7 @@ prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx, return -1; } + static int serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) { @@ -303,7 +265,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n"); maj_stat = gss_krb5_export_lucid_sec_context(&min_stat, &ctx, - 1, &return_ctx); + 1, &return_ctx); if (maj_stat != GSS_S_COMPLETE) goto out_err; @@ -392,63 +354,140 @@ out_err: #endif /* HAVE_KRB5 */ -/* ANDROS: need to determine which fields of the spkm3_gss_ctx_id_desc_t - * are needed in the kernel for get_mic, validate, wrap, unwrap, and destroy - * and only export those fields to the kernel. - */ +#ifdef HAVE_SPKM3_H +/* + * Function: prepare_spkm3_ctx_buffer() + * + * Prepare spkm3 lucid context for the kernel + * + * buf->length should be: + * + * ctx_id 4 + 12 + * qop 4 + * mech_used 4 + 7 + * ret_fl 4 + * req_fl 4 + * share 4 + key_len + * conf_alg 4 + oid_len + * d_conf_key 4 + key_len + * intg_alg 4 + oid_len + * d_intg_key 4 + key_len + * kyestb 4 + oid_len + * owl alg 4 + oid_len +*/ static int -serialize_spkm3_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) +prepare_spkm3_ctx_buffer(gss_spkm3_lucid_ctx_t *lctx, gss_buffer_desc *buf) { - spkm3_gss_ctx_id_desc *sctx = (spkm3_gss_ctx_id_desc *)ctx; char *p, *end; + unsigned int buf_size = 0; + + buf_size = lctx->ctx_id.length + + sizeof(lctx->ctx_id.length) + sizeof(lctx->qop) + + sizeof(lctx->mech_used.length) + lctx->mech_used.length + + sizeof(lctx->ret_flags) + sizeof(lctx->req_flags) + + sizeof(lctx->share_key.length) + lctx->share_key.length + + sizeof(lctx->conf_alg.length) + lctx->conf_alg.length + + sizeof(lctx->derived_conf_key.length) + + lctx->derived_conf_key.length + + sizeof(lctx->intg_alg.length) + lctx->intg_alg.length + + sizeof(lctx->derived_integ_key.length) + + lctx->derived_integ_key.length + + sizeof(lctx->keyestb_alg.length) + lctx->keyestb_alg.length + + sizeof(lctx->owf_alg.length) + lctx->owf_alg.length; + + if (!(buf->value = calloc(1, buf_size))) + goto out_err; + p = buf->value; + end = buf->value + buf_size; - printerr(1, "serialize_spkm3_ctx called\n"); + if (write_buffer(&p, end, &lctx->ctx_id)) + goto out_err; - if (!(buf->value = calloc(1, MAX_CTX_LEN))) + if (WRITE_BYTES(&p, end, lctx->qop)) goto out_err; - p = buf->value; - end = buf->value + MAX_CTX_LEN; -/* buf->length -ctx_id 4 + 12 -qop 4 -mech_used 4 + 7 -ret_fl 4 -req_fl 4 -share 4 + 16 -conf_alg 4 -d_conf_key 4 + 0 -intg_alg 4 -d_intg_key 4 + 0 -kyestb 4 -owl alg 4 -*/ - if (write_buffer(&p, end, (gss_buffer_desc *)&sctx->ctx_id)) + + if (write_buffer(&p, end, &lctx->mech_used)) + goto out_err; + + if (WRITE_BYTES(&p, end, lctx->ret_flags)) + goto out_err; + + if (WRITE_BYTES(&p, end, lctx->req_flags)) + goto out_err; + + if (write_buffer(&p, end, &lctx->share_key)) + goto out_err; + + if (write_buffer(&p, end, &lctx->conf_alg)) goto out_err; - if (WRITE_BYTES(&p, end, sctx->qop)) goto out_err; - if (write_buffer(&p, end, (gss_buffer_desc *)sctx->mech_used)) goto out_err; - if (WRITE_BYTES(&p, end, sctx->ret_flags)) goto out_err; - if (WRITE_BYTES(&p, end, sctx->req_flags)) goto out_err; - if (write_buffer(&p, end, &sctx->share_key)) + + if (write_buffer(&p, end, &lctx->derived_conf_key)) goto out_err; - if (WRITE_BYTES(&p, end, sctx->conf_alg)) goto out_err; - if (write_buffer(&p, end, &sctx->derived_conf_key)) + if (write_buffer(&p, end, &lctx->intg_alg)) goto out_err; - if (WRITE_BYTES(&p, end, sctx->intg_alg)) goto out_err; - if (write_buffer(&p, end, &sctx->derived_integ_key)) + if (write_buffer(&p, end, &lctx->derived_integ_key)) goto out_err; - if (WRITE_BYTES(&p, end, sctx->keyestb_alg)) goto out_err; - if (WRITE_BYTES(&p, end, sctx->owf_alg)) goto out_err; + if (write_buffer(&p, end, &lctx->keyestb_alg)) + goto out_err; + + if (write_buffer(&p, end, &lctx->owf_alg)) + goto out_err; buf->length = p - (char *)buf->value; return 0; out_err: + printerr(0, "ERROR: failed serializing spkm3 context for kernel\n"); if (buf->value) free(buf->value); buf->length = 0; + + return -1; +} + +/* ANDROS: need to determine which fields of the spkm3_gss_ctx_id_desc_t + * are needed in the kernel for get_mic, validate, wrap, unwrap, and destroy + * and only export those fields to the kernel. + */ +static int +serialize_spkm3_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf) +{ + OM_uint32 vers, ret, maj_stat, min_stat; + void *ret_ctx = 0; + gss_spkm3_lucid_ctx_t *lctx; + + printerr(1, "serialize_spkm3_ctx called\n"); + + printerr(2, "DEBUG: serialize_spkm3_ctx: lucid version!\n"); + maj_stat = gss_export_lucid_sec_context(&min_stat, ctx, 1, &ret_ctx); + if (maj_stat != GSS_S_COMPLETE) + goto out_err; + + lctx = (gss_spkm3_lucid_ctx_t *)ret_ctx; + + vers = lctx->version; + if (vers != 1) { + printerr(0, "ERROR: unsupported spkm3 context version %d\n", + vers); + goto out_err; + } + ret = prepare_spkm3_ctx_buffer(lctx, buf); + + maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, ret_ctx); + + if (maj_stat != GSS_S_COMPLETE) + printerr(0, "WARN: failed to free lucid sec context\n"); + if (ret) + goto out_err; + printerr(2, "DEBUG: serialize_spkm3_ctx: success\n"); + return 0; + +out_err: + printerr(2, "DEBUG: serialize_spkm3_ctx: failed\n"); return -1; } +#endif /* HAVE_SPKM3_H */ int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf) @@ -457,8 +496,10 @@ serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf) if (g_OID_equal(&krb5oid, uctx->mech_type)) return serialize_krb5_ctx(uctx->internal_ctx_id, buf); +#ifdef HAVE_SPKM3_H else if (g_OID_equal(&spkm3oid, uctx->mech_type)) - return serialize_spkm3_ctx(uctx->internal_ctx_id, buf); + return serialize_spkm3_ctx(uctx, buf); +#endif else { printerr(0, "ERROR: attempting to serialize context with " "unknown mechanism oid\n"); diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c index 788ecf1..78919b8 100644 --- a/utils/gssd/gssd_proc.c +++ b/utils/gssd/gssd_proc.c @@ -366,11 +366,16 @@ static int do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, gss_buffer_desc *context_token) { - char buf[2048]; - char *p = buf, *end = buf + 2048; + char *buf = NULL, *p = NULL, *end = NULL; unsigned int timeout = 0; /* XXX decide on a reasonable value */ + unsigned int buf_size = 0; printerr(1, "doing downcall\n"); + buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) + + sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length + + sizeof(context_token->length) + context_token->length; + p = buf = malloc(buf_size); + end = buf + buf_size; if (WRITE_BYTES(&p, end, uid)) goto out_err; /* Not setting any timeout for now: */ @@ -380,8 +385,10 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd, if (write_buffer(&p, end, context_token)) goto out_err; if (write(k5_fd, buf, p - buf) < p - buf) goto out_err; + if (buf) free(buf); return 0; out_err: + if (buf) free(buf); printerr(0, "Failed to write downcall!\n"); return -1; } @@ -423,7 +430,12 @@ int create_auth_rpc_client(struct clnt_info *clp, AUTH *auth = NULL; uid_t save_uid = -1; int retval = -1; + int errcode; OM_uint32 min_stat; + char rpc_errmsg[1024]; + int sockp = RPC_ANYSOCK; + int sendsz = 32768, recvsz = 32768; + struct addrinfo ai_hints, *a = NULL; sec.qop = GSS_C_QOP_DEFAULT; sec.svc = RPCSEC_GSS_SVC_NONE; @@ -435,7 +447,10 @@ int create_auth_rpc_client(struct clnt_info *clp, } else if (authtype == AUTHTYPE_SPKM3) { sec.mech = (gss_OID)&spkm3oid; - sec.req_flags = GSS_C_ANON_FLAG; + /* XXX sec.req_flags = GSS_C_ANON_FLAG; + * Need a way to switch.... + */ + sec.req_flags = GSS_C_MUTUAL_FLAG; } else { printerr(0, "ERROR: Invalid authentication type (%d) " @@ -473,20 +488,82 @@ int create_auth_rpc_client(struct clnt_info *clp, printerr(2, "creating %s client for server %s\n", clp->protocol, clp->servername); - if ((rpc_clnt = clnt_create(clp->servername, clp->prog, clp->vers, - clp->protocol)) == NULL) { - printerr(0, "WARNING: can't create rpc_clnt for server " - "%s for user with uid %d\n", - clp->servername, uid); + + memset(&ai_hints, '\0', sizeof(ai_hints)); + ai_hints.ai_family = PF_INET; + ai_hints.ai_flags |= AI_CANONNAME; + if ((strcmp(clp->protocol, "tcp")) == 0) { + ai_hints.ai_socktype = SOCK_STREAM; + ai_hints.ai_protocol = IPPROTO_TCP; + } else if ((strcmp(clp->protocol, "udp")) == 0) { + ai_hints.ai_socktype = SOCK_DGRAM; + ai_hints.ai_protocol = IPPROTO_UDP; + } else { + printerr(0, "WARNING: unrecognized protocol, '%s', requested " + "for connection to server %s for user with uid %d", + clp->protocol, clp->servername, uid); + goto out_fail; + } + + errcode = getaddrinfo(clp->servername, "nfs", + &ai_hints, &a); + if (errcode) { + printerr(0, "WARNING: Error from getaddrinfo for server " + "'%s': %s", clp->servername, gai_strerror(errcode)); + goto out_fail; + } + + if (a == NULL) { + printerr(0, "WARNING: No address information found for " + "connection to server %s for user with uid %d", + clp->servername, uid); + goto out_fail; + } + if (a->ai_protocol == IPPROTO_TCP) { + if ((rpc_clnt = clnttcp_create( + (struct sockaddr_in *) a->ai_addr, + clp->prog, clp->vers, &sockp, + sendsz, recvsz)) == NULL) { + snprintf(rpc_errmsg, sizeof(rpc_errmsg), + "WARNING: can't create tcp rpc_clnt " + "for server %s for user with uid %d", + clp->servername, uid); + printerr(0, "%s\n", + clnt_spcreateerror(rpc_errmsg)); + goto out_fail; + } + } else if (a->ai_protocol == IPPROTO_UDP) { + const struct timeval timeout = {5, 0}; + if ((rpc_clnt = clntudp_bufcreate( + (struct sockaddr_in *) a->ai_addr, + clp->prog, clp->vers, timeout, + &sockp, sendsz, recvsz)) == NULL) { + snprintf(rpc_errmsg, sizeof(rpc_errmsg), + "WARNING: can't create udp rpc_clnt " + "for server %s for user with uid %d", + clp->servername, uid); + printerr(0, "%s\n", + clnt_spcreateerror(rpc_errmsg)); + goto out_fail; + } + } else { + /* Shouldn't happen! */ + printerr(0, "ERROR: requested protocol '%s', but " + "got addrinfo with protocol %d", + clp->protocol, a->ai_protocol); goto out_fail; } + /* We're done with this */ + freeaddrinfo(a); + a = NULL; printerr(2, "creating context with server %s\n", clp->servicename); auth = authgss_create_default(rpc_clnt, clp->servicename, &sec); if (!auth) { /* Our caller should print appropriate message */ - printerr(2, "WARNING: Failed to create krb5 context for " + printerr(2, "WARNING: Failed to create %s context for " "user with uid %d for server %s\n", + (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"), uid, clp->servername); goto out_fail; } @@ -511,6 +588,7 @@ int create_auth_rpc_client(struct clnt_info *clp, if (sec.cred != GSS_C_NO_CREDENTIAL) gss_release_cred(&min_stat, &sec.cred); if (rpc_clnt) clnt_destroy(rpc_clnt); + if (a != NULL) freeaddrinfo(a); return retval; } diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c index 353a93e..5f3e490 100644 --- a/utils/gssd/krb5_util.c +++ b/utils/gssd/krb5_util.c @@ -288,18 +288,16 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) &credh, NULL, NULL); if (maj_stat != GSS_S_COMPLETE) { - printerr(0, "WARNING: error from gss_acquire_cred " - "for user with uid %d (%s)\n", - uid, error_message(min_stat)); + pgsserr("gss_acquire_cred", + maj_stat, min_stat, &krb5oid); return -1; } maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid, num_enctypes, &enctypes); if (maj_stat != GSS_S_COMPLETE) { - printerr(0, "WARNING: error from gss_set_allowable_enctypes " - "for user with uid %d (%s)\n", - uid, error_message(min_stat)); + pgsserr("gss_set_allowable_enctypes", + maj_stat, min_stat, &krb5oid); return -1; } sec->cred = credh; |