]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
Merge branch 'refs/heads/t/audiod_acl'
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 3 May 2015 09:51:22 +0000 (11:51 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sun, 3 May 2015 09:54:22 +0000 (11:54 +0200)
Cooking for about one month.

* audiod: Allow to specify usernames in --user-allow.

1  2 
NEWS
audiod.c
audiod.h
audiod_command.c

diff --combined NEWS
index 2eaad812d3b617cd1fb048c129139e354a4d59e5,b29d4b828ed1245b59795927667d3c6470d10332..87f678f578b27d8d3708b38fb2a14e6af7f4bd42
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -7,15 -7,8 +7,18 @@@ current master branch "magnetic momentu
        - 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.
 +      - para_server and para_audiod no longer refuse to start in
 +        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)
 +
  ------------------------------------------
  0.5.4 (2015-01-23) "exponential alignment"
  ------------------------------------------
diff --combined audiod.c
index 1f226265b0c9c79593f255bba4805cfdb8a53e9a,3fe654a73c1f71004baf554996df82d100f83933..40443a612569988e00ade13c8f384a7090d133e3
+++ b/audiod.c
@@@ -14,6 -14,7 +14,7 @@@
  #include <sys/un.h>
  #include <netdb.h>
  #include <signal.h>
+ #include <pwd.h>
  
  #include "para.h"
  #include "error.h"
@@@ -68,30 -69,6 +69,30 @@@ struct audio_format_info 
        struct timeval restart_barrier;
  };
  
 +/* Describes one instance of a receiver-filter-writer chain. */
 +struct slot_info {
 +      /* Number of the audio format in this slot. */
 +      int format;
 +      /* The stream_start status item announced by para_server.  */
 +      struct timeval server_stream_start;
 +      /* The offset status item announced by para_server. */
 +      unsigned offset_seconds;
 +      /* The seconds_total status item announced by para_server. */
 +      unsigned seconds_total;
 +      /* The receiver info associated with this slot. */
 +      struct receiver_node *receiver_node;
 +      /* The array of filter nodes. */
 +      struct filter_node *fns;
 +      /* The array of writers attached to the last filter. */
 +      struct writer_node *wns;
 +};
 +
 +/** Maximal number of simultaneous instances. */
 +#define MAX_STREAM_SLOTS 5
 +
 +/** Iterate over all slots. */
 +#define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++)
 +
  /**
   * para_audiod uses \p MAX_STREAM_SLOTS different slots, each of which may
   * be associated with a receiver/filter/writer triple. This array holds all
@@@ -172,6 -149,8 +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
   *
@@@ -222,35 -201,6 +225,35 @@@ static int get_audio_format_num(const c
        return -E_UNSUPPORTED_AUDIO_FORMAT;
  }
  
 +/**
 + * Return the flags for the \a decoder_flags status item.
 + *
 + * Allocates a string which contains one octal digit per slot.  Bit zero (value
 + * 1) is set if a receiver is active. Bit one (value 2) and bit three (value 4)
 + * have the analogous meaning for filter and writer, respectively.
 + *
 + * \return String that must be freed by the caller.
 + */
 +__malloc char *audiod_get_decoder_flags(void)
 +{
 +      int i;
 +      char flags[MAX_STREAM_SLOTS + 1];
 +
 +      FOR_EACH_SLOT(i) {
 +              struct slot_info *s = &slot[i];
 +              char flag = '0';
 +              if (s->receiver_node)
 +                      flag += 1;
 +              if (s->fns)
 +                      flag += 2;
 +              if (s->wns)
 +                      flag += 4;
 +              flags[i] = flag;
 +      }
 +      flags[MAX_STREAM_SLOTS] = '\0';
 +      return para_strdup(flags);
 +}
 +
  static int get_matching_audio_format_nums(const char *re)
  {
        int i, ret;
        return ret;
  }
  
 +static int get_play_time_slot_num(void)
 +{
 +      int i, oldest_slot = -1;
 +      struct timeval oldest_wstime = {0, 0};
 +
 +      FOR_EACH_SLOT(i) {
 +              struct slot_info *s = &slot[i];
 +              struct timeval wstime;
 +              if (!s->wns || !s->wns[0].btrn)
 +                      continue;
 +              btr_get_node_start(s->wns[0].btrn, &wstime);
 +              if (oldest_slot >= 0 && tv_diff(&wstime, &oldest_wstime, NULL) > 0)
 +                      continue;
 +              oldest_wstime = wstime;
 +              oldest_slot = i;
 +      }
 +      return oldest_slot;
 +}
 +
  /**
 - * Compute the play time based on information of the given slot.
 - *
 - * \param slot_num The slot number (negative means: no slot).
 + * Compute the play time based on information of the current slot.
   *
   * This computes a string of the form "0:07 [3:33] (3%/3:40)" using information
   * from the status items received from para_server and the start time of the
 - * (first) writer of the given slot.
 + * (first) writer of the current slot.
   *
   * It has to take into account that the stream was probably not started at
   * the beginning of the file, that the clock between the server and the client
   * host may differ and that playback of the stream was delayed, e.g. because
 - * the prebuffer filter is used in the filter configuration of the given slot.
 + * the prebuffer filter is used in the filter configuration.
   *
 - * If no writer is active in the given slot, or \a slot_num is negative
 - * (indicating that para_audiod runs in standby mode), an approximation based
 - * only on the status items is computed and the returned string is prefixed
 - * with "~".
 + * If no writer is active, for example because para_audiod runs in standby
 + * mode, an approximation based only on the status items is computed and the
 + * returned string is prefixed with "~".
   *
   * \return A string that must be freed by the caller.
   */
 -char *get_time_string(int slot_num)
 +char *get_time_string(void)
  {
        int ret, seconds = 0, length;
        struct timeval *tmp, sum, sss, /* server stream start */
                wstime, /* writer start time */
                wtime, /* now - writer start */
                rskip; /* receiver start - sss */
 +      int slot_num = get_play_time_slot_num();
        struct slot_info *s = slot_num < 0? NULL : &slot[slot_num];
        char *msg;
  
@@@ -390,7 -323,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,
        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) {
                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 -1053,7 +1123,7 @@@ static int command_post_select(struct s
        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 -1180,7 +1250,7 @@@ static void audiod_cleanup(void
        close_unused_slots();
        audiod_cmdline_parser_free(&conf);
        close_stat_clients();
+       free(uid_whitelist);
  }
  
  /*
diff --combined audiod.h
index 94288eec702dd016dbebcaa2f5bf68a882aab1e7,21e34e65fc2346d441957f8fbb48bbdc198a0800..3b4b9bd0416720e5e7d9455df23221cb049a2fc8
+++ b/audiod.h
@@@ -13,6 -13,9 +13,6 @@@ enum {AUDIOD_AUDIO_FORMATS_ENUM}
  /** array of audio format names supported by para_audiod */
  extern const char *audio_formats[];
  
 -/** maximal number of simultaneous instances */
 -#define MAX_STREAM_SLOTS 5
 -
  /**
   * the possible modes of operation
   *
@@@ -36,15 -39,41 +36,15 @@@ struct audiod_command 
        const char *help;
  };
  
 -/**
 - * Describes one instance of a receiver-filter-writer chain.
 - *
 - * \sa receiver_node, receiver, filter, filter_node, writer, writer_node,
 - * writer_node_group.
 - */
 -struct slot_info {
 -      /** Number of the audio format in this slot. */
 -      int format;
 -      /** The stream_start status item announced by para_server.  */
 -      struct timeval server_stream_start;
 -      /** The offset status item announced by para_server. */
 -      unsigned offset_seconds;
 -      /** The seconds_total status item announced by para_server. */
 -      unsigned seconds_total;
 -      /** The receiver info associated with this slot. */
 -      struct receiver_node *receiver_node;
 -      /** The array of filter nodes. */
 -      struct filter_node *fns;
 -      /** The array of writers attached to the last filter. */
 -      struct writer_node *wns;
 -};
 -
 -extern struct slot_info slot[MAX_STREAM_SLOTS];
 +__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(int slot_num);
 +char *get_time_string(void);
  struct btr_node *audiod_get_btr_root(void);
  
  void stat_client_write_item(int item_num);
  void clear_and_dump_items(void);
  void close_stat_clients(void);
 -
 -/** iterate over all slots */
 -#define FOR_EACH_SLOT(_slot) for (_slot = 0; _slot < MAX_STREAM_SLOTS; _slot++)
diff --combined audiod_command.c
index b847e5aa264fa4ccb9e8c9aafcfcb61713ae2131,5c7d2d53937df19706952ecce185246711be615a..98dba3b32dfcaee1a7532d8e3021947102d98f89
@@@ -216,6 -216,46 +216,6 @@@ __malloc static char *audiod_status_str
        return para_strdup(status);
  }
  
 -static int get_play_time_slot_num(void)
 -{
 -      int i, oldest_slot = -1;
 -      struct timeval oldest_wstime = {0, 0};
 -
 -      FOR_EACH_SLOT(i) {
 -              struct slot_info *s = &slot[i];
 -              struct timeval wstime;
 -              if (!s->wns || !s->wns[0].btrn)
 -                      continue;
 -              btr_get_node_start(s->wns[0].btrn, &wstime);
 -              if (oldest_slot >= 0 && tv_diff(&wstime, &oldest_wstime, NULL) > 0)
 -                      continue;
 -              oldest_wstime = wstime;
 -              oldest_slot = i;
 -      }
 -      //PARA_CRIT_LOG("oldest slot: %d\n", oldest_slot);
 -      return oldest_slot;
 -}
 -
 -__malloc static char *decoder_flags(void)
 -{
 -      int i;
 -      char flags[MAX_STREAM_SLOTS + 1];
 -
 -      FOR_EACH_SLOT(i) {
 -              struct slot_info *s = &slot[i];
 -              char flag = '0';
 -              if (s->receiver_node)
 -                      flag += 1;
 -              if (s->fns)
 -                      flag += 2;
 -              if (s->wns)
 -                      flag += 4;
 -              flags[i] = flag;
 -      }
 -      flags[MAX_STREAM_SLOTS] = '\0';
 -      return para_strdup(flags);
 -}
 -
  static int dump_commands(int fd)
  {
        char *buf = para_strdup(""), *tmp = NULL;
@@@ -396,14 -436,14 +396,14 @@@ static int com_version(int fd, int argc
        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;
  }
   *
   * \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,
   *
   * \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;
                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);
@@@ -473,10 -514,11 +474,10 @@@ out
   */
  void audiod_status_dump(bool force)
  {
 -      int slot_num = get_play_time_slot_num();
        char *old, *new;
  
        old = stat_item_values[SI_PLAY_TIME];
 -      new = get_time_string(slot_num);
 +      new = get_time_string();
        if (new) {
                if (force || !old || strcmp(old, new)) {
                        free(old);
                free(new);
  
        old = stat_item_values[SI_DECODER_FLAGS];
 -      new = decoder_flags();
 +      new = audiod_get_decoder_flags();
        if (force || !old || strcmp(old, new)) {
                free(old);
                stat_item_values[SI_DECODER_FLAGS] = new;