#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/fsuid.h>
+#include <sys/resource.h>
#include <stdio.h>
#include <stdlib.h>
struct pollfd * pollarray;
-int pollsize; /* the size of pollaray (in pollfd's) */
+unsigned long pollsize; /* the size of pollaray (in pollfd's) */
/*
* convert a presentation address string to a sockaddr_storage struct. Returns
{
socklen_t addrlen;
int err;
- char *hostname;
+ char *hostname;
char hbuf[NI_MAXHOST];
switch (sa->sa_family) {
if ((p = strstr(buf, "port")) != NULL)
sscanf(p, "port: %127s\n", port);
- /* check service, program, and version */
- if (memcmp(service, "nfs", 3) != 0)
- return -1;
+ /* get program, and version numbers */
*prog = atoi(program + 1); /* skip open paren */
*vers = atoi(version);
- if (strlen(service) == 3 ) {
- if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
- (*vers != 4)))
- goto fail;
- } else if (memcmp(service, "nfs4_cb", 7) == 0) {
- if (*vers != 1)
- goto fail;
- }
-
if (!addrstr_to_sockaddr(addr, address, port))
goto fail;
if (clp->krb5_poll_index != -1)
memset(&pollarray[clp->krb5_poll_index], 0,
sizeof(struct pollfd));
- if (clp->spkm3_poll_index != -1)
- memset(&pollarray[clp->spkm3_poll_index], 0,
- sizeof(struct pollfd));
if (clp->gssd_poll_index != -1)
memset(&pollarray[clp->gssd_poll_index], 0,
sizeof(struct pollfd));
if (clp->dir_fd != -1) close(clp->dir_fd);
if (clp->krb5_fd != -1) close(clp->krb5_fd);
- if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
if (clp->gssd_fd != -1) close(clp->gssd_fd);
free(clp->dirname);
free(clp->servicename);
goto out;
}
clp->krb5_poll_index = -1;
- clp->spkm3_poll_index = -1;
clp->gssd_poll_index = -1;
clp->krb5_fd = -1;
- clp->spkm3_fd = -1;
clp->gssd_fd = -1;
clp->dir_fd = -1;
char gname[PATH_MAX];
char info_file_name[PATH_MAX];
+ if (clp->gssd_close_me) {
+ printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
+ close(clp->gssd_fd);
+ memset(&pollarray[clp->gssd_poll_index], 0,
+ sizeof(struct pollfd));
+ clp->gssd_fd = -1;
+ clp->gssd_poll_index = -1;
+ clp->gssd_close_me = 0;
+ }
+ if (clp->krb5_close_me) {
+ printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
+ close(clp->krb5_fd);
+ memset(&pollarray[clp->krb5_poll_index], 0,
+ sizeof(struct pollfd));
+ clp->krb5_fd = -1;
+ clp->krb5_poll_index = -1;
+ clp->krb5_close_me = 0;
+ }
+
if (clp->gssd_fd == -1) {
snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
clp->gssd_fd = open(gname, O_RDWR);
snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
clp->krb5_fd = open(name, O_RDWR);
}
- if (clp->spkm3_fd == -1) {
- snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
- clp->spkm3_fd = open(name, O_RDWR);
- }
/* If we opened a gss-specific pipe, let's try opening
* the new upcall pipe again. If we succeed, close
* gss-specific pipe(s).
*/
- if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) {
+ if (clp->krb5_fd != -1) {
clp->gssd_fd = open(gname, O_RDWR);
if (clp->gssd_fd != -1) {
if (clp->krb5_fd != -1)
close(clp->krb5_fd);
clp->krb5_fd = -1;
- if (clp->spkm3_fd != -1)
- close(clp->spkm3_fd);
- clp->spkm3_fd = -1;
}
}
}
- if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) &&
- (clp->gssd_fd == -1))
+ if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
return -1;
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
clp->dirname);
static int
get_poll_index(int *ind)
{
- int i;
+ unsigned int i;
*ind = -1;
- for (i=0; i<FD_ALLOC_BLOCK; i++) {
+ for (i=0; i<pollsize; i++) {
if (pollarray[i].events == 0) {
*ind = i;
break;
pollarray[clp->krb5_poll_index].events |= POLLIN;
}
- if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
- if (get_poll_index(&clp->spkm3_poll_index)) {
- printerr(0, "ERROR: Too many spkm3 clients\n");
- return -1;
- }
- pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
- pollarray[clp->spkm3_poll_index].events |= POLLIN;
- }
-
return 0;
}
void
init_client_list(void)
{
+ struct rlimit rlim;
TAILQ_INIT(&clnt_list);
/* Eventually plan to grow/shrink poll array: */
pollsize = FD_ALLOC_BLOCK;
+ if (getrlimit(RLIMIT_NOFILE, &rlim) == 0 &&
+ rlim.rlim_cur != RLIM_INFINITY)
+ pollsize = rlim.rlim_cur;
pollarray = calloc(pollsize, sizeof(struct pollfd));
}
update_old_clients(namelist, j, pipe_name);
for (i=0; i < j; i++) {
- if (i < FD_ALLOC_BLOCK
- && !strncmp(namelist[i]->d_name, "clnt", 4)
- && !find_client(namelist[i]->d_name, pipe_name))
+ if (!strncmp(namelist[i]->d_name, "clnt", 4)
+ && !find_client(namelist[i]->d_name, pipe_name))
process_clnt_dir(namelist[i]->d_name, pipe_name);
free(namelist[i]);
}
static int
do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
- gss_buffer_desc *context_token)
+ gss_buffer_desc *context_token, OM_uint32 lifetime_rec)
{
char *buf = NULL, *p = NULL, *end = NULL;
unsigned int timeout = context_timeout;
unsigned int buf_size = 0;
- printerr(1, "doing downcall\n");
+ printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec);
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;
+ /* context_timeout set by -t option overrides context lifetime */
+ if (timeout == 0)
+ timeout = lifetime_rec;
if (WRITE_BYTES(&p, end, uid)) goto out_err;
if (WRITE_BYTES(&p, end, timeout)) goto out_err;
if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
/*
* If the port isn't already set, do an rpcbind query to the remote server
- * using the program and version and get the port.
+ * using the program and version and get the port.
*
* Newer kernels send the value of the port= mount option in the "info"
* file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
* Create an RPC connection and establish an authenticated
* gss context with a server.
*/
-int create_auth_rpc_client(struct clnt_info *clp,
- CLIENT **clnt_return,
- AUTH **auth_return,
- uid_t uid,
- int authtype)
+static int
+create_auth_rpc_client(struct clnt_info *clp,
+ CLIENT **clnt_return,
+ AUTH **auth_return,
+ uid_t uid,
+ int authtype)
{
CLIENT *rpc_clnt = NULL;
struct rpc_gss_sec sec;
sec.mech = (gss_OID)&krb5oid;
sec.req_flags = GSS_C_MUTUAL_FLAG;
}
- else if (authtype == AUTHTYPE_SPKM3) {
- sec.mech = (gss_OID)&spkm3oid;
- /* 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) "
"in create_auth_rpc_client\n", authtype);
auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
if (!auth) {
/* Our caller should print appropriate message */
- printerr(2, "WARNING: Failed to create %s context for "
+ printerr(2, "WARNING: Failed to create krb5 context for "
"user with uid %d for server %s\n",
- (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
uid, clp->servername);
goto out_fail;
}
char **dirname;
int create_resp = -1;
int err, downcall_err = -EACCES;
+ OM_uint32 maj_stat, min_stat, lifetime_rec;
printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
- if (tgtname) {
- if (clp->servicename) {
- free(clp->servicename);
- clp->servicename = strdup(tgtname);
- }
- }
token.length = 0;
token.value = NULL;
memset(&pd, 0, sizeof(struct authgss_private_data));
int success = 0;
do {
gssd_refresh_krb5_machine_credential(clp->servername,
- NULL, service);
+ NULL, service,
+ tgtname);
/*
* Get a list of credential cache names and try each
* of them until one works or we've tried them all
printerr(0, "ERROR: No credentials found "
"for connection to server %s\n",
clp->servername);
- goto out_return_error;
+ goto out_return_error;
}
for (ccname = credlist; ccname && *ccname; ccname++) {
gssd_setup_krb5_machine_gss_ccache(*ccname);
/* Success! */
success++;
break;
- }
+ }
printerr(2, "WARNING: Failed to create machine krb5 context "
"with credentials cache %s for server %s\n",
*ccname, clp->servername);
}
- gssd_free_krb5_machine_cred_list(credlist);
+ gssd_free_krb5_machine_cred_list(credlist);
if (!success) {
if(nocache == 0) {
nocache++;
goto out_return_error;
}
+ /* Grab the context lifetime to pass to the kernel. lifetime_rec
+ * is set to zero on error */
+ maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL,
+ &lifetime_rec, NULL, NULL, NULL, NULL);
+
+ if (maj_stat)
+ printerr(1, "WARNING: Failed to inquire context for lifetme "
+ "maj_stat %u\n", maj_stat);
+
if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
printerr(0, "WARNING: Failed to serialize krb5 context for "
"user with uid %d for server %s\n",
goto out_return_error;
}
- do_downcall(fd, uid, &pd, &token);
+ do_downcall(fd, uid, &pd, &token, lifetime_rec);
out:
if (token.value)
free(token.value);
-#ifndef HAVE_LIBTIRPC
+#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
if (pd.pd_ctx_hndl.length != 0)
authgss_free_private_data(&pd);
#endif
goto out;
}
-/*
- * this code uses the userland rpcsec gss library to create an spkm3
- * context on behalf of the kernel
- */
-static void
-process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
-{
- CLIENT *rpc_clnt = NULL;
- AUTH *auth = NULL;
- struct authgss_private_data pd;
- gss_buffer_desc token;
-
- printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
-
- token.length = 0;
- token.value = NULL;
-
- if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
- printerr(0, "WARNING: Failed to create spkm3 context for "
- "user with uid %d\n", uid);
- goto out_return_error;
- }
-
- if (!authgss_get_private_data(auth, &pd)) {
- printerr(0, "WARNING: Failed to obtain authentication "
- "data for user with uid %d for server %s\n",
- uid, clp->servername);
- goto out_return_error;
- }
-
- if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
- printerr(0, "WARNING: Failed to serialize spkm3 context for "
- "user with uid %d for server\n",
- uid, clp->servername);
- goto out_return_error;
- }
-
- do_downcall(fd, uid, &pd, &token);
-
-out:
- if (token.value)
- free(token.value);
- if (auth)
- AUTH_DESTROY(auth);
- if (rpc_clnt)
- clnt_destroy(rpc_clnt);
- return;
-
-out_return_error:
- do_error_downcall(fd, uid, -1);
- goto out;
-}
-
void
handle_krb5_upcall(struct clnt_info *clp)
{
return;
}
- return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
-}
-
-void
-handle_spkm3_upcall(struct clnt_info *clp)
-{
- uid_t uid;
-
- if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
- printerr(0, "WARNING: failed reading uid from spkm3 "
- "upcall pipe: %s\n", strerror(errno));
- return;
- }
-
- return process_spkm3_upcall(clp, uid, clp->spkm3_fd);
+ process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
}
void
if (strcmp(mech, "krb5") == 0)
process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
- else if (strcmp(mech, "spkm3") == 0)
- process_spkm3_upcall(clp, uid, clp->gssd_fd);
else
printerr(0, "WARNING: handle_gssd_upcall: "
"received unknown gss mech '%s'\n", mech);
free(enctypes);
free(target);
free(service);
- return;
+ return;
}