From: Andre Noll Date: Sun, 3 May 2015 09:51:22 +0000 (+0200) Subject: Merge branch 'refs/heads/t/audiod_acl' X-Git-Tag: v0.5.5~37 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=e70beecd3fa6378aadf8773660741873023befcf;hp=db212616a42fb6d33385f79cfc9b8cca9721a8b9;p=paraslash.git Merge branch 'refs/heads/t/audiod_acl' Cooking for about one month. * audiod: Allow to specify usernames in --user-allow. --- diff --git a/NEWS b/NEWS index 2eaad812..87f678f5 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ current master branch "magnetic momentum" - On Linux systems, local sockets are now created in the abstract name space by default. This allows to get rid of the socket specials in /var/paraslash. + - The --user-allow option of para_audiod now accepts also + usernames rather than only user IDs. - New autoconf macros to avoid duplication in configure.ac. - Status items (as shown by para_gui) are updated correctly when the meta information of the current audio changes. @@ -14,6 +16,7 @@ current master branch "magnetic momentum" the background if no log file is given. Instead, all log messages go to /dev/null in this case. + Download: ./releases/paraslash-git.tar.bz2 (tarball) ------------------------------------------ diff --git a/audiod.c b/audiod.c index 1f226265..40443a61 100644 --- a/audiod.c +++ b/audiod.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "para.h" #include "error.h" @@ -172,6 +173,8 @@ 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 * @@ -390,7 +393,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, @@ -410,6 +413,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) { @@ -417,9 +421,29 @@ 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); } @@ -1099,7 +1123,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) { @@ -1226,6 +1250,7 @@ static void audiod_cleanup(void) close_unused_slots(); audiod_cmdline_parser_free(&conf); close_stat_clients(); + free(uid_whitelist); } /* diff --git a/audiod.h b/audiod.h index 94288eec..3b4b9bd0 100644 --- a/audiod.h +++ b/audiod.h @@ -40,7 +40,7 @@ __malloc char *audiod_get_decoder_flags(void); extern struct audiod_args_info conf; extern int audiod_status; -int handle_connect(int accept_fd, fd_set *rfds); +int handle_connect(int accept_fd, fd_set *rfds, uid_t *uid_whitelist); void audiod_status_dump(bool force); char *get_time_string(void); struct btr_node *audiod_get_btr_root(void); diff --git a/audiod_command.c b/audiod_command.c index b847e5aa..98dba3b3 100644 --- a/audiod_command.c +++ b/audiod_command.c @@ -396,14 +396,14 @@ static int com_version(int fd, int argc, char **argv) return ret; } -static int check_perms(uid_t uid) +static int check_perms(uid_t uid, uid_t *whitelist) { int i; if (!conf.user_allow_given) return 1; for (i = 0; i < conf.user_allow_given; i++) - if (uid == conf.user_allow_arg[i]) + if (uid == whitelist[i]) return 1; return -E_UCRED_PERM; } @@ -413,6 +413,7 @@ static int check_perms(uid_t uid) * * \param accept_fd The fd to accept connections on. * \param rfds If \a accept_fd is not set in \a rfds, do nothing. + * \param uid_whitelist Array of UIDs which are allowed to connect. * * This is called in each iteration of the select loop. If there is an incoming * connection on \a accept_fd, this function reads the command sent by the peer, @@ -425,7 +426,7 @@ static int check_perms(uid_t uid) * * \sa para_accept(), recv_cred_buffer() * */ -int handle_connect(int accept_fd, fd_set *rfds) +int handle_connect(int accept_fd, fd_set *rfds, uid_t *uid_whitelist) { int i, argc, ret, clifd; char buf[MAXLINE], **argv = NULL; @@ -440,7 +441,7 @@ int handle_connect(int accept_fd, fd_set *rfds) goto out; uid = ret; PARA_INFO_LOG("connection from user %i, buf: %s\n", ret, buf); - ret = check_perms(uid); + ret = check_perms(uid, uid_whitelist); if (ret < 0) goto out; ret = create_argv(buf, "\n", &argv); diff --git a/m4/gengetopt/audiod.m4 b/m4/gengetopt/audiod.m4 index 2e6f936f..732f8087 100644 --- a/m4/gengetopt/audiod.m4 +++ b/m4/gengetopt/audiod.m4 @@ -82,20 +82,21 @@ details=" option "user-allow" - #~~~~~~~~~~~~~~~~~~~~ -"allow this uid" -int typestr="uid" -default="-1" +"allow this user to connect to audiod" +string typestr = "username" optional multiple -details=" - Allow the user identified by \"uid\" to connect to para_audiod. - May be specified multiple times. If not specified at all, - all users are allowed to connect. - - This feature requires unix socket credentials and is currently - only supported on Linux systems. On other operating systems, - the option is silently ignored and all local users are allowed - to connect to para_audiod. +details = " + Allow the user identified by username (either a string or + a UID) to connect to para_audiod. This option may be given + multiple times. If not specified at all, all users are allowed + to connect. + + This feature is based on the ability to send unix + credentials through local sockets using ancillary data + (SCM_CREDENTIALS). Currently it only works on Linux. On + other operating systems the option is silently ignored and + all local users are allowed to connect. " option "clock-diff-count" -