X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fgssd%2Fgssd_proc.c;h=4c3d85da766ebdef5f1352ada8c0c6f8f2fbd9b9;hp=416653be28144238b858f6049b3a51157a31df4c;hb=a6037e23a8c9d649bf5946ac9d23114f9097b997;hpb=6b7bfb3b630ad704424ac967cd9695f5a1d63534 diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c index 416653b..4c3d85d 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,14 @@ 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; + char service[64]; + char *at_sign; sec.qop = GSS_C_QOP_DEFAULT; sec.svc = RPCSEC_GSS_SVC_NONE; @@ -435,7 +449,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 +490,95 @@ 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; + } + + /* extract the service name from clp->servicename */ + if ((at_sign = strchr(clp->servicename, '@')) == NULL) { + printerr(0, "WARNING: servicename (%s) not formatted as " + "expected with service@host", clp->servicename); + goto out_fail; + } + if ((at_sign - clp->servicename) >= sizeof(service)) { + printerr(0, "WARNING: service portion of servicename (%s) " + "is too long!", clp->servicename); + goto out_fail; + } + strncpy(service, clp->servicename, at_sign - clp->servicename); + service[at_sign - clp->servicename] = '\0'; + + errcode = getaddrinfo(clp->servername, service, &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; } @@ -504,9 +596,14 @@ int create_auth_rpc_client(struct clnt_info *clp, retval = 0; out_fail: + if ((save_uid != -1) && (seteuid(save_uid) != 0)) { + printerr(0, "WARNING: Failed to restore euid" + " to uid %d (in error path)\n", save_uid); + } 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; } @@ -591,7 +688,7 @@ handle_krb5_upcall(struct clnt_info *clp) goto out_return_error; } - if (serialize_context_for_kernel(pd.pd_ctx, &token)) { + if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid)) { printerr(0, "WARNING: Failed to serialize krb5 context for " "user with uid %d for server %s\n", uid, clp->servername); @@ -646,7 +743,7 @@ handle_spkm3_upcall(struct clnt_info *clp) goto out_return_error; } - if (serialize_context_for_kernel(pd.pd_ctx, &token)) { + if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid)) { printerr(0, "WARNING: Failed to serialize spkm3 context for " "user with uid %d for server\n", uid, clp->servername);