summaryrefslogtreecommitdiffstats
path: root/utils/gssd/gssd.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/gssd/gssd.c')
-rw-r--r--utils/gssd/gssd.c93
1 files changed, 65 insertions, 28 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 *