diff options
Diffstat (limited to 'utils/gssd/gssd.c')
-rw-r--r-- | utils/gssd/gssd.c | 93 |
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 * |