From 62c4197d5b41b66af58c34a4cc79c023599f0f72 Mon Sep 17 00:00:00 2001 From: neilbrown Date: Fri, 16 Dec 2005 05:24:38 +0000 Subject: [PATCH] Updates from Kevin Coffman at UMich --- ChangeLog | 105 +++++++++++++++++ configure.in | 1 + support/include/config.h.in | 3 + utils/gssd/context.c | 203 ++++++++++++++++++++------------- utils/gssd/gssd_proc.c | 96 ++++++++++++++-- utils/gssd/krb5_util.c | 10 +- utils/idmapd/idmapd.c | 207 +++++++++++++++++++++++----------- utils/rquotad/hasquota.c | 1 + utils/rquotad/rquota_server.c | 1 + utils/svcgssd/Makefile | 2 +- utils/svcgssd/svcgssd.c | 3 +- utils/svcgssd/svcgssd_proc.c | 77 +++++++++---- 12 files changed, 526 insertions(+), 183 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1557e90..36bb027 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,108 @@ +2005-12-16 Kevin Coffman + svcgssd needs -lnfs when using new function closeall(). + + --- + Remove unused argument from nfsdopen() + + After previous changes, the arguement to nfsdopen() has become unused. + Remove it. + + --- + Fix idmapd error reporting after call to mydaemon() + + After call to mydaemon(), calls to err[x] and warn[x] result + in the message going nowhere. Change to using idmapd_* + versions of these routines which write to syslog. + Original problem reported by Vincent Roqueta + with a different patch. + + --- + Don't add @domain to names that cannot be mapped. + + Per rfc3530 section 5.8: when unable to map a uid to a name, don't + add the @domain to the "nobody" name. + + --- + Fix idmapd for systems where sizeof(uid_t)!=4 and sizeof(gid_t)!=4 + + Fix conversion cases where uid_t and gid_t are not 32 bits. + + --- + Don't segfault because mech wasn't filled in because of an error + + From Kevin Coffman + + Initialize mech to null to avoid segfault if an error occurs + and mech is never returned from gss_accept_sec_context. + + --- + Remove use of static buffer in do_downcall + + Signed-off-by: Kevin Coffman + + Dynamically allocate buffer of the correct length rather + than using fixed-length buffer. + + --- + Print better error message if rpc routine clnt_create() fails. + + --- + Print appropriate error messages after gss calls. + + Print gss error messages after calls to gss functions, even if they + are for Kerberos only. + + --- + Update gssd and svcgssd to use the new gss mech glue lucid context calls. + + Signed-off-by: Kevin Coffman + + Update gssd and svcgssd to use a lucid context from SPKM3 to send down + to the kernel. + Update gssd and svcgssd to use the new gss mech glue lucid context calls. + Add configure check to see if spkm3 support is available. + + --- + Add support for CONTINUE_NEEDED return from gss_accept_sec_context. + + Signed-off-by: Kevin Coffman + + Add CONTINUE_INIT handling to svcgssd. Store the partially complete spkm + context handle in the out_handle of CONTINUE_INIT messages so that it is + returned in the in_handle of subsequent messages. + + --- + Replace GSS_C_ANON_FLAG with GSS_C_MUTUAL_FLAG. + + Signed-off-by: Kevin Coffman + + Specify GSS_C_MUTUAL_FLAG rather than GSS_C_ANON_FLAG for + spkm3. + + NOTE: we need a way to pass the appropriate value rather than + hard-coding this flag. + + --- + Increase size of rpc send/receive buffers + + Change the clnt_create() to use routines which allow us to set the + send and receive buffer size. This is needed for larger spkm3 + exchanges including certificate chains. + + This has the side-effect of skipping the portmap call since + we specify the port (by specifying the service) when getting + the server's address information. + + --- + Define _LINUX_QUOTA_VERSION to 1 + + The rquotad code is written against the "old" kernel quota interface. + Fedora Core 4 is the only platform known to check for different + versions, so this should not have any affect on other platforms + and fixes the build for FC4. + + --- + 2005-12-12 Usha Ketineni , NeilBrown *support/nfs/rpcmisc.c(rpc_init): is stdin is a socket, but is already connected (as e.g. from ssh), don't assume we diff --git a/configure.in b/configure.in index 8e239ab..174436e 100644 --- a/configure.in +++ b/configure.in @@ -136,6 +136,7 @@ AC_SUBST(LIBWRAP) if test "$enable_gss" = yes; then dnl 'gss' also depends on nfsidmap.h - at least for svcgssd_proc.c AC_CHECK_HEADERS(nfsidmap.h, ,[AC_MSG_ERROR(libnfsidmap needed for gss support)]) + AC_CHECK_HEADERS(spkm3.h, ,[AC_MSG_WARN(could not locate SPKM3 header; will not have SPKM3 support)]) dnl Checks for Kerberos dnl NOTE: while we intend to do generic gss-api, currently we diff --git a/support/include/config.h.in b/support/include/config.h.in index 73db5a2..769afff 100644 --- a/support/include/config.h.in +++ b/support/include/config.h.in @@ -30,6 +30,9 @@ */ #undef RESTRICTED_STATD +/* Define this if you have */ +#undef HAVE_SPKM3_H + /* Define this if you want support for rpcsec_gss with * the MIT krb5 mechanism compiled in */ #undef HAVE_KRB5 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 +#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; diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c index 4c13273..73c30b9 100644 --- a/utils/idmapd/idmapd.c +++ b/utils/idmapd/idmapd.c @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include #include @@ -131,7 +133,7 @@ static void imconv(struct idmap_client *, struct idmap_msg *); static void idtonameres(struct idmap_msg *); static void nametoidres(struct idmap_msg *); -static int nfsdopen(char *); +static int nfsdopen(); static int nfsdopenone(struct idmap_client *); static void nfsdreopen(void); @@ -178,6 +180,71 @@ flush_nfsd_idmap_cache(void) return ret; } +static void +msg_format(char *rtnbuff, int rtnbuffsize, int errval, + const char *fmt, va_list args) +{ + char buff[1024]; + int n; + + vsnprintf(buff, sizeof(buff), fmt, args); + + if ((n = strlen(buff)) > 0 && buff[n-1] == '\n') + buff[--n] = '\0'; + + snprintf(rtnbuff, rtnbuffsize, "%s: %s", buff, strerror(errval)); +} + +static void +idmapd_warn(const char *fmt, ...) +{ + int errval = errno; /* save this! */ + char buff[1024]; + va_list args; + + va_start(args, fmt); + msg_format(buff, sizeof(buff), errval, fmt, args); + va_end(args); + + syslog(LOG_WARNING, "%s", buff); +} + +static void +idmapd_warnx(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vsyslog(LOG_WARNING, fmt, args); + va_end(args); +} + +static void +idmapd_err(int eval, const char *fmt, ...) +{ + int errval = errno; /* save this! */ + char buff[1024]; + va_list args; + + va_start(args, fmt); + msg_format(buff, sizeof(buff), errval, fmt, args); + va_end(args); + + syslog(LOG_ERR, "%s", buff); + exit(eval); +} + +static void +idmapd_errx(int eval, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vsyslog(LOG_ERR, fmt, args); + va_end(args); + exit(eval); +} + int main(int argc, char **argv) { @@ -191,12 +258,19 @@ main(int argc, char **argv) char *xpipefsdir = NULL; int serverstart = 1, clientstart = 1; int ret; + char *progname; conf_path = _PATH_IDMAPDCONF; nobodyuser = NFS4NOBODY_USER; nobodygroup = NFS4NOBODY_GROUP; strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir)); + if ((progname = strrchr(argv[0], '/'))) + progname++; + else + progname = argv[0]; + openlog(progname, LOG_PID, LOG_DAEMON); + #define GETOPTSTR "vfd:p:U:G:c:CS" opterr=0; /* Turn off error messages */ while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { @@ -269,11 +343,12 @@ main(int argc, char **argv) event_init(); if (serverstart) { - nfsdret = nfsdopen(NFSD_DIR); + nfsdret = nfsdopen(); if (nfsdret == 0) { ret = flush_nfsd_idmap_cache(); if (ret) - errx(1, "Failed to flush nfsd idmap cache\n"); + idmapd_errx(1, + "main: Failed to flush nfsd idmap cache\n"); } } @@ -284,13 +359,14 @@ main(int argc, char **argv) }; if ((fd = open(pipefsdir, O_RDONLY)) == -1) - err(1, "open(%s)", pipefsdir); + idmapd_err(1, "main: open(%s)", pipefsdir); if (fcntl(fd, F_SETSIG, SIGUSR1) == -1) - err(1, "fcntl(%s)", pipefsdir); + idmapd_err(1, "main: fcntl(%s)", pipefsdir); + if (fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_MODIFY | DN_MULTISHOT) == -1) - err(1, "fcntl(%s)", pipefsdir); + idmapd_err(1, "main: fcntl(%s)", pipefsdir); TAILQ_INIT(&icq); @@ -310,12 +386,13 @@ main(int argc, char **argv) } if (nfsdret != 0 && fd == 0) - errx(1, "Neither NFS client nor NFSd found"); + idmapd_errx(1, "main: Neither NFS client nor NFSd found"); release_parent(); if (event_dispatch() < 0) - errx(1, "event_dispatch: returns errno %d (%s)", errno, strerror(errno)); + idmapd_errx(1, "main: event_dispatch returns errno %d (%s)", + errno, strerror(errno)); /* NOTREACHED */ return 1; } @@ -331,7 +408,7 @@ dirscancb(int fd, short which, void *data) nent = scandir(pipefsdir, &ents, NULL, alphasort); if (nent == -1) { - warn("scandir(%s)", pipefsdir); + idmapd_warn("dirscancb: scandir(%s)", pipefsdir); return; } @@ -353,7 +430,7 @@ dirscancb(int fd, short which, void *data) pipefsdir, ents[i]->d_name); if ((ic->ic_dirfd = open(path, O_RDONLY, 0)) == -1) { - warn("open(%s)", path); + idmapd_warn("dirscancb: open(%s)", path); free(ic); return; } @@ -362,7 +439,7 @@ dirscancb(int fd, short which, void *data) strlcpy(ic->ic_path, path, sizeof(ic->ic_path)); if (verbose > 0) - warnx("New client: %s", ic->ic_clid); + idmapd_warnx("New client: %s", ic->ic_clid); if (nfsopen(ic) == -1) { close(ic->ic_dirfd); @@ -386,8 +463,8 @@ dirscancb(int fd, short which, void *data) close(ic->ic_dirfd); TAILQ_REMOVE(icq, ic, ic_next); if (verbose > 0) { - warnx("Stale client: %s", ic->ic_clid); - warnx("\t-> closed %s", ic->ic_path); + idmapd_warnx("Stale client: %s", ic->ic_clid); + idmapd_warnx("\t-> closed %s", ic->ic_path); } free(ic); } else @@ -425,13 +502,14 @@ nfsdcb(int fd, short which, void *data) size_t len, bsiz; char *bp, typebuf[IDMAP_MAXMSGSZ], buf1[IDMAP_MAXMSGSZ], authbuf[IDMAP_MAXMSGSZ], *p; + unsigned long tmp; if (which != EV_READ) goto out; if ((len = read(ic->ic_fd, buf, sizeof(buf))) == -1) { - warnx("nfsdcb: read(%s) failed: errno %d (%s)", - ic->ic_path, errno, strerror(errno)); + idmapd_warnx("nfsdcb: read(%s) failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); goto out; } @@ -443,15 +521,16 @@ nfsdcb(int fd, short which, void *data) /* Authentication name -- ignored for now*/ if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) { - warnx("nfsdcb: bad authentication name in upcall\n"); + idmapd_warnx("nfsdcb: bad authentication name in upcall\n"); return; } if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) { - warnx("nfsdcb: bad type in upcall\n"); + idmapd_warnx("nfsdcb: bad type in upcall\n"); return; } if (verbose > 0) - warnx("nfsdcb: authbuf=%s authtype=%s", authbuf, typebuf); + idmapd_warnx("nfsdcb: authbuf=%s authtype=%s", + authbuf, typebuf); im.im_type = strcmp(typebuf, "user") == 0 ? IDMAP_TYPE_USER : IDMAP_TYPE_GROUP; @@ -460,25 +539,26 @@ nfsdcb(int fd, short which, void *data) case IC_NAMEID: im.im_conv = IDMAP_CONV_NAMETOID; if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) { - warnx("nfsdcb: bad name in upcall\n"); + idmapd_warnx("nfsdcb: bad name in upcall\n"); return; } break; case IC_IDNAME: im.im_conv = IDMAP_CONV_IDTONAME; if (getfield(&bp, buf1, sizeof(buf1)) == -1) { - warnx("nfsdcb: bad id in upcall\n"); + idmapd_warnx("nfsdcb: bad id in upcall\n"); return; } - if ((im.im_id = strtoul(buf1, (char **)NULL, 10)) == ULONG_MAX && - errno == ERANGE) { - warnx("nfsdcb: id '%s' too big!\n", buf1); + tmp = strtoul(buf1, (char **)NULL, 10); + im.im_id = (u_int32_t)tmp; + if ((tmp == ULONG_MAX && errno == ERANGE) + || (unsigned long)im.im_id != tmp) { + idmapd_warnx("nfsdcb: id '%s' too big!\n", buf1); return; } - break; default: - warnx("Unknown which type %d", ic->ic_which); + idmapd_warnx("nfsdcb: Unknown which type %d", ic->ic_which); return; } @@ -528,15 +608,15 @@ nfsdcb(int fd, short which, void *data) break; default: - warnx("Unknown which type %d", ic->ic_which); + idmapd_warnx("nfsdcb: Unknown which type %d", ic->ic_which); return; } bsiz = sizeof(buf) - bsiz; if (atomicio(write, ic->ic_fd, buf, bsiz) != bsiz) - warnx("nfsdcb: write(%s) failed: errno %d (%s)", - ic->ic_path, errno, strerror(errno)); + idmapd_warnx("nfsdcb: write(%s) failed: errno %d (%s)", + ic->ic_path, errno, strerror(errno)); out: event_add(&ic->ic_event, NULL); @@ -549,7 +629,7 @@ imconv(struct idmap_client *ic, struct idmap_msg *im) case IDMAP_CONV_IDTONAME: idtonameres(im); if (verbose > 1) - warnx("%s %s: (%s) id \"%d\" -> name \"%s\"", + idmapd_warnx("%s %s: (%s) id \"%d\" -> name \"%s\"", ic->ic_id, ic->ic_clid, im->im_type == IDMAP_TYPE_USER ? "user" : "group", im->im_id, im->im_name); @@ -561,13 +641,14 @@ imconv(struct idmap_client *ic, struct idmap_msg *im) } nametoidres(im); if (verbose > 1) - warnx("%s %s: (%s) name \"%s\" -> id \"%d\"", + idmapd_warnx("%s %s: (%s) name \"%s\" -> id \"%d\"", ic->ic_id, ic->ic_clid, im->im_type == IDMAP_TYPE_USER ? "user" : "group", im->im_name, im->im_id); break; default: - warnx("Invalid conversion type (%d) in message", im->im_conv); + idmapd_warnx("imconv: Invalid conversion type (%d) in message", + im->im_conv); im->im_status |= IDMAP_STATUS_INVALIDMSG; break; } @@ -584,7 +665,7 @@ nfscb(int fd, short which, void *data) if (atomicio(read, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) { if (verbose > 0) - warn("read(%s)", ic->ic_path); + idmapd_warn("nfscb: read(%s)", ic->ic_path); if (errno == EPIPE) return; goto out; @@ -593,7 +674,7 @@ nfscb(int fd, short which, void *data) imconv(ic, &im); if (atomicio(write, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) - warn("write(%s)", ic->ic_path); + idmapd_warn("nfscb: write(%s)", ic->ic_path); out: event_add(&ic->ic_event, NULL); } @@ -604,7 +685,7 @@ nfsdreopen_one(struct idmap_client *ic) int fd; if (verbose > 0) - warnx("ReOpening %s", ic->ic_path); + idmapd_warnx("ReOpening %s", ic->ic_path); if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) { if (ic->ic_fd != -1) @@ -616,7 +697,7 @@ nfsdreopen_one(struct idmap_client *ic) event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic); event_add(&ic->ic_event, NULL); } else { - warnx("nfsdreopen: Opening '%s' failed: errno %d (%s)", + idmapd_warnx("nfsdreopen: Opening '%s' failed: errno %d (%s)", ic->ic_path, errno, strerror(errno)); } } @@ -630,7 +711,7 @@ nfsdreopen() } static int -nfsdopen(char *path) +nfsdopen() { return ((nfsdopenone(&nfsd_ic[IC_NAMEID]) == 0 && nfsdopenone(&nfsd_ic[IC_IDNAME]) == 0) ? 0 : -1); @@ -641,7 +722,8 @@ nfsdopenone(struct idmap_client *ic) { if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) { if (verbose > 0) - warnx("Opening %s failed: errno %d (%s)", + idmapd_warnx("nfsdopenone: Opening %s failed: " + "errno %d (%s)", ic->ic_path, errno, strerror(errno)); return (-1); } @@ -650,7 +732,7 @@ nfsdopenone(struct idmap_client *ic) event_add(&ic->ic_event, NULL); if (verbose > 0) - warnx("Opened %s", ic->ic_path); + idmapd_warnx("Opened %s", ic->ic_path); return (0); } @@ -666,7 +748,7 @@ nfsopen(struct idmap_client *ic) DN_CREATE | DN_DELETE | DN_MULTISHOT); break; default: - warn("open(%s)", ic->ic_path); + idmapd_warn("nfsopen: open(%s)", ic->ic_path); return (-1); } } else { @@ -675,23 +757,12 @@ nfsopen(struct idmap_client *ic) fcntl(ic->ic_dirfd, F_SETSIG, 0); fcntl(ic->ic_dirfd, F_NOTIFY, 0); if (verbose > 0) - warnx("Opened %s", ic->ic_path); + idmapd_warnx("Opened %s", ic->ic_path); } return (0); } -static int write_name(char *dest, char *localname, char *domain, size_t len) -{ - if (strlen(localname) + 1 + strlen(domain) + 1 > len) { - return -ENOMEM; /* XXX: Is there an -ETOOLONG? */ - } - strcpy(dest, localname); - strcat(dest, "@"); - strcat(dest, domain); - return 0; -} - static void idtonameres(struct idmap_msg *im) { @@ -703,16 +774,22 @@ idtonameres(struct idmap_msg *im) case IDMAP_TYPE_USER: ret = nfs4_uid_to_name(im->im_id, domain, im->im_name, sizeof(im->im_name)); - if (ret) - write_name(im->im_name, nobodyuser, domain, - sizeof(im->im_name)); + if (ret) { + if (strlen(nobodyuser) < sizeof(im->im_name)) + strcpy(im->im_name, nobodyuser); + else + strcpy(im->im_name, NFS4NOBODY_USER); + } break; case IDMAP_TYPE_GROUP: ret = nfs4_gid_to_name(im->im_id, domain, im->im_name, sizeof(im->im_name)); - if (ret) - write_name(im->im_name, nobodygroup, domain, - sizeof(im->im_name)); + if (ret) { + if (strlen(nobodygroup) < sizeof(im->im_name)) + strcpy(im->im_name, nobodygroup); + else + strcpy(im->im_name, NFS4NOBODY_GROUP); + } break; } /* XXX Hack? */ @@ -722,6 +799,8 @@ idtonameres(struct idmap_msg *im) static void nametoidres(struct idmap_msg *im) { + uid_t uid; + gid_t gid; int ret = 0; /* XXX: nobody fallbacks shouldn't always happen: @@ -734,12 +813,14 @@ nametoidres(struct idmap_msg *im) * have a chance on looking up server/whatever. */ switch (im->im_type) { case IDMAP_TYPE_USER: - ret = nfs4_name_to_uid(im->im_name, &im->im_id); + ret = nfs4_name_to_uid(im->im_name, &uid); + im->im_id = (u_int32_t) uid; if (ret) im->im_id = nobodyuid; break; case IDMAP_TYPE_GROUP: - ret = nfs4_name_to_gid(im->im_name, &im->im_id); + ret = nfs4_name_to_gid(im->im_name, &gid); + im->im_id = (u_int32_t) gid; if (ret) im->im_id = nobodygid; break; @@ -850,10 +931,10 @@ mydaemon(int nochdir, int noclose) int pid, status, tempfd; if (pipe(pipefds) < 0) - err(1, "mydaemon: pipe() failed: errno %d (%s)\n", errno, strerror(errno)); + err(1, "mydaemon: pipe() failed: errno %d", errno); if ((pid = fork ()) < 0) - err(1, "mydaemon: fork() failed: errno %d (%s)\n", errno, strerror(errno)); + err(1, "mydaemon: fork() failed: errno %d", errno); if (pid != 0) { /* @@ -869,13 +950,13 @@ mydaemon(int nochdir, int noclose) setsid (); if (nochdir == 0) { if (chdir ("/") == -1) - err(1, "mydaemon: chdir() failed: errno %d (%s)\n", errno, strerror(errno)); + err(1, "mydaemon: chdir() failed: errno %d", errno); } while (pipefds[1] <= 2) { pipefds[1] = dup(pipefds[1]); if (pipefds[1] < 0) - err(1, "mydaemon: dup() failed: errno %d (%s)\n", errno, strerror(errno)); + err(1, "mydaemon: dup() failed: errno %d", errno); } if (noclose == 0) { diff --git a/utils/rquotad/hasquota.c b/utils/rquotad/hasquota.c index 99fd5c5..f93e90a 100644 --- a/utils/rquotad/hasquota.c +++ b/utils/rquotad/hasquota.c @@ -20,6 +20,7 @@ * 2 of the License, or (at your option) any later version. */ #include "config.h" +#define _LINUX_QUOTA_VERSION 1 #include #include diff --git a/utils/rquotad/rquota_server.c b/utils/rquotad/rquota_server.c index 27a206c..45f351f 100644 --- a/utils/rquotad/rquota_server.c +++ b/utils/rquotad/rquota_server.c @@ -19,6 +19,7 @@ * 2 of the License, or (at your option) any later version. */ #include "config.h" +#define _LINUX_QUOTA_VERSION 1 #include #include "rquota.h" diff --git a/utils/svcgssd/Makefile b/utils/svcgssd/Makefile index 0c46af9..954b659 100644 --- a/utils/svcgssd/Makefile +++ b/utils/svcgssd/Makefile @@ -7,7 +7,7 @@ PROGRAM = svcgssd PREFIX = rpc. OBJS = svcgssd.o svcgssd_main_loop.o svcgssd_proc.o err_util.o gss_util.o \ gss_oids.o context.o context_heimdal.o cacheio.o svcgssd_mech2file.o -LIBS = -Wl,-rpath=$(KRBDIR)/lib -lrpcsecgss -lgssapi -ldl $(KRBLIB) -lnfsidmap +LIBS = -Wl,-rpath=$(KRBDIR)/lib -lrpcsecgss -lgssapi -ldl $(KRBLIB) -lnfsidmap -lnfs MAN8 = svcgssd LINKED = err_util.c gss_util.c gss_oids.c context.c context_heimdal.c diff --git a/utils/svcgssd/svcgssd.c b/utils/svcgssd/svcgssd.c index 3059253..4e0806c 100644 --- a/utils/svcgssd/svcgssd.c +++ b/utils/svcgssd/svcgssd.c @@ -54,6 +54,7 @@ #include #include #include +#include "nfslib.h" #include "svcgssd.h" #include "gss_util.h" #include "err_util.h" @@ -69,7 +70,7 @@ int pipefds[2] = { -1, -1}; static void mydaemon(int nochdir, int noclose) { - int pid, status, tempfd, fdmax, filedes; + int pid, status, tempfd; if (pipe(pipefds) < 0) { printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n", diff --git a/utils/svcgssd/svcgssd_proc.c b/utils/svcgssd/svcgssd_proc.c index dfa3c4c..b43a023 100644 --- a/utils/svcgssd/svcgssd_proc.c +++ b/utils/svcgssd/svcgssd_proc.c @@ -56,6 +56,8 @@ extern char * mech2file(gss_OID mech); #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel" #define SVCGSSD_INIT_CHANNEL "/proc/net/rpc/auth.rpcsec.init/channel" +#define TOKEN_BUF_SIZE 8192 + struct svc_cred { uid_t cr_uid; gid_t cr_gid; @@ -111,7 +113,7 @@ send_response(FILE *f, gss_buffer_desc *in_handle, gss_buffer_desc *in_token, u_int32_t maj_stat, u_int32_t min_stat, gss_buffer_desc *out_handle, gss_buffer_desc *out_token) { - char buf[2 * 4096]; + char buf[2 * TOKEN_BUF_SIZE]; char *bp = buf; int blen = sizeof(buf); /* XXXARG: */ @@ -189,25 +191,37 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred) char *sname; int res = -1; uid_t uid, gid; - gss_OID name_type; + gss_OID name_type = GSS_C_NO_OID; char *secname; gid_t *groups; maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type); - if (maj_stat != GSS_S_COMPLETE) + if (maj_stat != GSS_S_COMPLETE) { + pgsserr("get_ids: gss_display_name", + maj_stat, min_stat, mech); goto out; - if (!(sname = calloc(name.length + 1, 1))) + } + if (!(sname = calloc(name.length + 1, 1))) { + printerr(0, "WARNING: get_ids: error allocating %d bytes " + "for sname\n", name.length + 1); goto out; + } memcpy(sname, name.value, name.length); printerr(1, "sname = %s\n", sname); res = -EINVAL; - if ((secname = mech2file(mech)) == NULL) + 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) + if (res < 0) { + printerr(0, "WARNING: get_ids: unable to map " + "name '%s' to a uid\n", sname); goto out_free; + } cred->cr_uid = uid; cred->cr_gid = gid; add_supplementary_groups(secname, sname, cred); @@ -215,8 +229,6 @@ get_ids(gss_name_t client_name, gss_OID mech, struct svc_cred *cred) out_free: free(sname); out: - if (res) - printerr(0, "WARNING: get_uid failed\n"); return res; } @@ -262,7 +274,7 @@ handle_nullreq(FILE *f) { /* XXX initialize to a random integer to reduce chances of unnecessary * invalidation of existing ctx's on restarting svcgssd. */ static u_int32_t handle_seq = 0; - char in_tok_buf[8192]; + 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}, @@ -275,7 +287,7 @@ handle_nullreq(FILE *f) { u_int32_t ret_flags; gss_ctx_id_t ctx = GSS_C_NO_CONTEXT; gss_name_t client_name; - gss_OID mech; + gss_OID mech = GSS_C_NO_OID; u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0; struct svc_cred cred; static char *lbuf = NULL; @@ -296,9 +308,6 @@ handle_nullreq(FILE *f) { sizeof(in_handle_buf)); printerr(2, "in_handle: \n"); print_hexl(2, in_handle.value, in_handle.length); - handle_seq++; - out_handle.length = sizeof(handle_seq); - memcpy(out_handle.value, &handle_seq, sizeof(handle_seq)); in_tok.length = (size_t) qword_get(&cp, in_tok.value, sizeof(in_tok_buf)); @@ -312,26 +321,48 @@ handle_nullreq(FILE *f) { } if (in_handle.length != 0) { /* CONTINUE_INIT case */ - printerr(0, "WARNING: handle_nullreq: " - "CONTINUE_INIT unsupported\n"); - goto out_err; + 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); } maj_stat = gss_accept_sec_context(&min_stat, &ctx, gssd_creds, &in_tok, GSS_C_NO_CHANNEL_BINDINGS, &client_name, &mech, &out_tok, &ret_flags, NULL, NULL); - if (maj_stat != GSS_S_COMPLETE) { + + if (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) { printerr(0, "WARNING: gss_accept_sec_context failed\n"); pgsserr("handle_nullreq: gss_accept_sec_context", maj_stat, min_stat, mech); goto out_err; } if (get_ids(client_name, mech, &cred)) { - printerr(0, "WARNING: handle_nullreq: get_uid failed\n"); + /* get_ids() prints error msg */ maj_stat = GSS_S_BAD_NAME; /* XXX ? */ goto out_err; } + + /* Context complete. Pass handle_seq in out_handle to use + * for context lookup in the kernel. */ + handle_seq++; + out_handle.length = sizeof(handle_seq); + memcpy(out_handle.value, &handle_seq, sizeof(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)) { @@ -341,15 +372,17 @@ handle_nullreq(FILE *f) { goto out_err; } 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); - goto out; -out_err: - send_response(f, &in_handle, &in_tok, maj_stat, min_stat, - &null_token, &null_token); out: if (ctx_token.value != NULL) free(ctx_token.value); printerr(1, "finished handling null request\n"); return; + +out_err: + send_response(f, &in_handle, &in_tok, maj_stat, min_stat, + &null_token, &null_token); + goto out; } -- 2.39.2