]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - audiod.c
audiod: Allow to specify usernames in --user-allow.
[paraslash.git] / audiod.c
index acf41376f50f196414d327bfb11f506c4fe8d7e2..3fe654a73c1f71004baf554996df82d100f83933 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -14,6 +14,7 @@
 #include <sys/un.h>
 #include <netdb.h>
 #include <signal.h>
+#include <pwd.h>
 
 #include "para.h"
 #include "error.h"
@@ -144,10 +145,12 @@ struct audiod_args_info conf;
 static char *socket_name;
 static struct audio_format_info afi[NUM_AUDIO_FORMATS];
 
-static struct signal_task signal_task_struct, *sig_task = &signal_task_struct;
+static struct signal_task *signal_task;
 
 static struct status_task status_task_struct;
 
+static uid_t *uid_whitelist;
+
 /**
  * the task that calls the status command of para_server
  *
@@ -320,7 +323,7 @@ empty:
 
 static void parse_config_or_die(void)
 {
-       int ret;
+       int ret, i;
        char *config_file;
        struct audiod_cmdline_parser_params params = {
                .override = 0,
@@ -340,6 +343,7 @@ static void parse_config_or_die(void)
        ret = file_exists(config_file);
        if (conf.config_file_given && !ret) {
                PARA_EMERG_LOG("can not read config file %s\n", config_file);
+               free(config_file);
                goto err;
        }
        if (ret) {
@@ -347,16 +351,35 @@ static void parse_config_or_die(void)
                daemon_set_loglevel(conf.loglevel_arg);
        }
        free(config_file);
+       if (conf.user_allow_given > 0) {
+               uid_whitelist = para_malloc(conf.user_allow_given
+                       * sizeof(uid_t));
+               for (i = 0; i < conf.user_allow_given; i++) {
+                       int32_t val;
+                       struct passwd *pw;
+                       ret = para_atoi32(conf.user_allow_arg[i], &val);
+                       if (ret >= 0) {
+                               uid_whitelist[i] = val;
+                               continue;
+                       }
+                       errno = 0; /* see getpwnam(3) */
+                       pw = getpwnam(conf.user_allow_arg[i]);
+                       if (!pw) {
+                               PARA_EMERG_LOG("invalid username: %s\n",
+                                       conf.user_allow_arg[i]);
+                               goto err;
+                       }
+                       uid_whitelist[i] = pw->pw_uid;
+               }
+       }
        return;
 err:
-       free(config_file);
        exit(EXIT_FAILURE);
 }
 
 static void setup_signal_handling(void)
 {
-       sig_task->fd = para_signal_init();
-       PARA_INFO_LOG("signal pipe: fd %d\n", sig_task->fd);
+       signal_task = signal_init_or_die();
        para_install_sighandler(SIGINT);
        para_install_sighandler(SIGTERM);
        para_install_sighandler(SIGHUP);
@@ -986,12 +1009,6 @@ static void init_local_sockets(struct command_task *ct)
        exit(EXIT_FAILURE);
 }
 
-static void signal_pre_select(struct sched *s, void *context)
-{
-       struct signal_task *st = context;
-       para_fd_set(st->fd, &s->rfds, &s->max_fileno);
-}
-
 static int signal_post_select(struct sched *s, void *context)
 {
        struct signal_task *st = context;
@@ -1036,7 +1053,7 @@ static int command_post_select(struct sched *s, void *context)
        for (i = 0; i < 2; i++) {
                if (ct->fd[i] < 0)
                        continue;
-               ret = handle_connect(ct->fd[i], &s->rfds);
+               ret = handle_connect(ct->fd[i], &s->rfds, uid_whitelist);
                if (ret < 0) {
                        PARA_ERROR_LOG("%s\n", para_strerror(-ret));
                        if (ret == -E_AUDIOD_TERM) {
@@ -1163,6 +1180,7 @@ static void audiod_cleanup(void)
        close_unused_slots();
        audiod_cmdline_parser_free(&conf);
        close_stat_clients();
+       free(uid_whitelist);
 }
 
 /*
@@ -1418,11 +1436,11 @@ int main(int argc, char *argv[])
        if (conf.daemon_given)
                daemonize(false /* parent exits immediately */);
 
-       sig_task->task = task_register(&(struct task_info) {
+       signal_task->task = task_register(&(struct task_info) {
                .name = "signal",
                .pre_select = signal_pre_select,
                .post_select = signal_post_select,
-               .context = sig_task,
+               .context = signal_task,
        }, &sched);
 
        sched.default_timeout.tv_sec = 2;
@@ -1430,6 +1448,7 @@ int main(int argc, char *argv[])
        ret = schedule(&sched);
        audiod_cleanup();
        sched_shutdown(&sched);
+       signal_shutdown(signal_task);
 
        if (ret < 0)
                PARA_EMERG_LOG("%s\n", para_strerror(-ret));