summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--utils/gssd/gssd.c93
-rw-r--r--utils/gssd/gssd.h13
-rw-r--r--utils/gssd/gssd_proc.c73
3 files changed, 96 insertions, 83 deletions
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
index 9bf7917..2179e15 100644
--- a/utils/gssd/gssd.c
+++ b/utils/gssd/gssd.c
@@ -363,54 +363,91 @@ gssd_destroy_client(struct clnt_info *clp)
static void gssd_scan(void);
-static inline void
-wait_for_child_and_detach(pthread_t th)
+static int
+start_upcall_thread(void (*func)(struct clnt_upcall_info *), void *info)
{
- pthread_mutex_lock(&pmutex);
- while (!thread_started)
- pthread_cond_wait(&pcond, &pmutex);
- thread_started = false;
- pthread_mutex_unlock(&pmutex);
- pthread_detach(th);
+ pthread_attr_t attr;
+ pthread_t th;
+ int ret;
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0) {
+ printerr(0, "ERROR: failed to init pthread attr: ret %d: %s\n",
+ ret, strerror(errno));
+ return ret;
+ }
+ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (ret != 0) {
+ printerr(0, "ERROR: failed to create pthread attr: ret %d: "
+ "%s\n", ret, strerror(errno));
+ return ret;
+ }
+
+ ret = pthread_create(&th, &attr, (void *)func, (void *)info);
+ if (ret != 0)
+ printerr(0, "ERROR: pthread_create failed: ret %d: %s\n",
+ ret, strerror(errno));
+ return ret;
+}
+
+static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp)
+{
+ struct clnt_upcall_info *info;
+
+ info = malloc(sizeof(struct clnt_upcall_info));
+ if (info == NULL)
+ return NULL;
+ info->clp = clp;
+
+ return info;
}
-/* For each upcall create a thread, detach from the main process so that
- * resources are released back into the system without the need for a join.
- * We need to wait for the child thread to start and consume the event from
- * the file descriptor.
+/* For each upcall read the upcall info into the buffer, then create a
+ * thread in a detached state so that resources are released back into
+ * the system without the need for a join.
*/
static void
gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data)
{
struct clnt_info *clp = data;
- pthread_t th;
- int ret;
+ struct clnt_upcall_info *info;
- ret = pthread_create(&th, NULL, (void *)handle_gssd_upcall,
- (void *)clp);
- if (ret != 0) {
- printerr(0, "ERROR: pthread_create failed: ret %d: %s\n",
- ret, strerror(errno));
+ info = alloc_upcall_info(clp);
+ if (info == NULL)
+ return;
+
+ info->lbuflen = read(clp->gssd_fd, info->lbuf, sizeof(info->lbuf));
+ if (info->lbuflen <= 0 || info->lbuf[info->lbuflen-1] != '\n') {
+ printerr(0, "WARNING: %s: failed reading request\n", __func__);
+ free(info);
return;
}
- wait_for_child_and_detach(th);
+ info->lbuf[info->lbuflen-1] = 0;
+
+ if (start_upcall_thread(handle_gssd_upcall, info))
+ free(info);
}
static void
gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data)
{
struct clnt_info *clp = data;
- pthread_t th;
- int ret;
+ struct clnt_upcall_info *info;
- ret = pthread_create(&th, NULL, (void *)handle_krb5_upcall,
- (void *)clp);
- if (ret != 0) {
- printerr(0, "ERROR: pthread_create failed: ret %d: %s\n",
- ret, strerror(errno));
+ info = alloc_upcall_info(clp);
+ if (info == NULL)
+ return;
+
+ if (read(clp->krb5_fd, &info->uid,
+ sizeof(info->uid)) < (ssize_t)sizeof(info->uid)) {
+ printerr(0, "WARNING: %s: failed reading uid from krb5 "
+ "upcall pipe: %s\n", __func__, strerror(errno));
+ free(info);
return;
}
- wait_for_child_and_detach(th);
+
+ if (start_upcall_thread(handle_krb5_upcall, info))
+ free(info);
}
static struct clnt_info *
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
index 565bce3..f4f5975 100644
--- a/utils/gssd/gssd.h
+++ b/utils/gssd/gssd.h
@@ -49,7 +49,7 @@
#define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine"
#define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab"
#define GSSD_SERVICE_NAME "nfs"
-
+#define RPC_CHAN_BUF_SIZE 32768
/*
* The gss mechanisms that we can handle
*/
@@ -85,8 +85,15 @@ struct clnt_info {
struct sockaddr_storage addr;
};
-void handle_krb5_upcall(struct clnt_info *clp);
-void handle_gssd_upcall(struct clnt_info *clp);
+struct clnt_upcall_info {
+ struct clnt_info *clp;
+ char lbuf[RPC_CHAN_BUF_SIZE];
+ int lbuflen;
+ uid_t uid;
+};
+
+void handle_krb5_upcall(struct clnt_upcall_info *clp);
+void handle_gssd_upcall(struct clnt_upcall_info *clp);
#endif /* _RPC_GSSD_H_ */
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index b19c595..cc3e9dc 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -79,7 +79,6 @@
#include "nfsrpc.h"
#include "nfslib.h"
#include "gss_names.h"
-#include "misc.h"
/* Encryption types supported by the kernel rpcsec_gss code */
int num_krb5_enctypes = 0;
@@ -713,45 +712,22 @@ out_return_error:
goto out;
}
-/* signal to the parent thread that we have read from the file descriptor.
- * it should allow the parent to proceed to poll on the descriptor for
- * the next upcall from the kernel.
- */
-static inline void
-signal_parent_event_consumed(void)
-{
- pthread_mutex_lock(&pmutex);
- thread_started = true;
- pthread_cond_signal(&pcond);
- pthread_mutex_unlock(&pmutex);
-}
-
void
-handle_krb5_upcall(struct clnt_info *clp)
+handle_krb5_upcall(struct clnt_upcall_info *info)
{
- uid_t uid;
- int status;
+ struct clnt_info *clp = info->clp;
- status = read(clp->krb5_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid);
- signal_parent_event_consumed();
+ printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath);
- if (status) {
- printerr(0, "WARNING: failed reading uid from krb5 "
- "upcall pipe: %s\n", strerror(errno));
- return;
- }
-
- printerr(2, "\n%s: uid %d (%s)\n", __func__, uid, clp->relpath);
-
- process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
+ process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL);
+ free(info);
}
void
-handle_gssd_upcall(struct clnt_info *clp)
+handle_gssd_upcall(struct clnt_upcall_info *info)
{
+ struct clnt_info *clp = info->clp;
uid_t uid;
- char lbuf[RPC_CHAN_BUF_SIZE];
- int lbuflen = 0;
char *p;
char *mech = NULL;
char *uidstr = NULL;
@@ -759,19 +735,9 @@ handle_gssd_upcall(struct clnt_info *clp)
char *service = NULL;
char *enctypes = NULL;
- lbuflen = read(clp->gssd_fd, lbuf, sizeof(lbuf));
- signal_parent_event_consumed();
-
- if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') {
- printerr(0, "WARNING: handle_gssd_upcall: "
- "failed reading request\n");
- return;
- }
- lbuf[lbuflen-1] = 0;
-
- printerr(2, "\n%s: '%s' (%s)\n", __func__, lbuf, clp->relpath);
+ printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath);
- for (p = strtok(lbuf, " "); p; p = strtok(NULL, " ")) {
+ for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) {
if (!strncmp(p, "mech=", strlen("mech=")))
mech = p + strlen("mech=");
else if (!strncmp(p, "uid=", strlen("uid=")))
@@ -787,8 +753,8 @@ handle_gssd_upcall(struct clnt_info *clp)
if (!mech || strlen(mech) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to find gss mechanism name "
- "in upcall string '%s'\n", lbuf);
- return;
+ "in upcall string '%s'\n", info->lbuf);
+ goto out;
}
if (uidstr) {
@@ -800,21 +766,21 @@ handle_gssd_upcall(struct clnt_info *clp)
if (!uidstr) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to find uid "
- "in upcall string '%s'\n", lbuf);
- return;
+ "in upcall string '%s'\n", info->lbuf);
+ goto out;
}
if (enctypes && parse_enctypes(enctypes) != 0) {
printerr(0, "WARNING: handle_gssd_upcall: "
"parsing encryption types failed: errno %d\n", errno);
- return;
+ goto out;
}
if (target && strlen(target) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to parse target name "
- "in upcall string '%s'\n", lbuf);
- return;
+ "in upcall string '%s'\n", info->lbuf);
+ goto out;
}
/*
@@ -828,8 +794,8 @@ handle_gssd_upcall(struct clnt_info *clp)
if (service && strlen(service) < 1) {
printerr(0, "WARNING: handle_gssd_upcall: "
"failed to parse service type "
- "in upcall string '%s'\n", lbuf);
- return;
+ "in upcall string '%s'\n", info->lbuf);
+ goto out;
}
if (strcmp(mech, "krb5") == 0 && clp->servername)
@@ -840,5 +806,8 @@ handle_gssd_upcall(struct clnt_info *clp)
"received unknown gss mech '%s'\n", mech);
do_error_downcall(clp->gssd_fd, uid, -EACCES);
}
+out:
+ free(info);
+ return;
}