+2005-12-16 Kevin Coffman <kwc@citi.umich.edu>
+ 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 <vincent.roqueta@ext.bull.net>
+ 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 <kwc@citi.umich.edu>
+
+ 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 <kwc@citi.umich.edu>
+
+ 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 <kwc@citi.umich.edu>
+
+ 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 <kwc@citi.umich.edu>
+
+ 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 <kwc@citi.umich.edu>
+
+ 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 <ketineni@us.ibm.com>, NeilBrown <neilb@suse.de>
*support/nfs/rpcmisc.c(rpc_init): is stdin is a socket, but
is already connected (as e.g. from ssh), don't assume we
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
*/
#undef RESTRICTED_STATD
+/* Define this if you have <spkm3.h> */
+#undef HAVE_SPKM3_H
+
/* Define this if you want support for rpcsec_gss with
* the MIT krb5 mechanism compiled in */
#undef HAVE_KRB5
#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
#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 {
return -1;
}
+
static int
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;
#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)
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");
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: */
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;
}
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;
}
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) "
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;
}
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;
}
&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;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
#include <pwd.h>
#include <grp.h>
#include <limits.h>
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);
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)
{
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) {
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");
}
}
};
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);
}
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;
}
nent = scandir(pipefsdir, &ents, NULL, alphasort);
if (nent == -1) {
- warn("scandir(%s)", pipefsdir);
+ idmapd_warn("dirscancb: scandir(%s)", pipefsdir);
return;
}
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;
}
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);
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
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;
}
/* 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;
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;
}
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);
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);
}
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;
}
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;
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);
}
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)
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));
}
}
}
static int
-nfsdopen(char *path)
+nfsdopen()
{
return ((nfsdopenone(&nfsd_ic[IC_NAMEID]) == 0 &&
nfsdopenone(&nfsd_ic[IC_IDNAME]) == 0) ? 0 : -1);
{
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);
}
event_add(&ic->ic_event, NULL);
if (verbose > 0)
- warnx("Opened %s", ic->ic_path);
+ idmapd_warnx("Opened %s", ic->ic_path);
return (0);
}
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 {
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)
{
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? */
static void
nametoidres(struct idmap_msg *im)
{
+ uid_t uid;
+ gid_t gid;
int ret = 0;
/* XXX: nobody fallbacks shouldn't always happen:
* 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;
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) {
/*
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) {
* 2 of the License, or (at your option) any later version.
*/
#include "config.h"
+#define _LINUX_QUOTA_VERSION 1
#include <sys/types.h>
#include <sys/quota.h>
* 2 of the License, or (at your option) any later version.
*/
#include "config.h"
+#define _LINUX_QUOTA_VERSION 1
#include <rpc/rpc.h>
#include "rquota.h"
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
#include <stdlib.h>
#include <string.h>
#include <signal.h>
+#include "nfslib.h"
#include "svcgssd.h"
#include "gss_util.h"
#include "err_util.h"
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",
#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;
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: */
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);
out_free:
free(sname);
out:
- if (res)
- printerr(0, "WARNING: get_uid failed\n");
return res;
}
/* 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},
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;
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));
}
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)) {
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;
}