chiark / gitweb /
copyright date
[disorder] / lib / configuration.c
index 35573c5c15dc6d03c26248315cc509132f21facb..7ed92761d76fe0fe86137b3922f55bedee43bf76 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * This file is part of DisOrder.
  * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell
 /*
  * This file is part of DisOrder.
  * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell
+ * Portions copyright (C) 2007 Mark Wooding
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -38,6 +39,7 @@
 #include <pcre.h>
 #include <signal.h>
 
 #include <pcre.h>
 #include <signal.h>
 
+#include "rights.h"
 #include "configuration.h"
 #include "mem.h"
 #include "log.h"
 #include "configuration.h"
 #include "mem.h"
 #include "log.h"
  */
 char *configfile;
 
  */
 char *configfile;
 
+/** @brief Read user configuration
+ *
+ * If clear, the user-specific configuration is not read.
+ */
+int config_per_user = 1;
+
 /** @brief Config file parser state */
 struct config_state {
   /** @brief Filename */
 /** @brief Config file parser state */
 struct config_state {
   /** @brief Filename */
@@ -226,6 +234,10 @@ static int set_stringlist_accum(const struct config_state *cs,
   struct stringlistlist *sll;
 
   sll = ADDRESS(cs->config, struct stringlistlist);
   struct stringlistlist *sll;
 
   sll = ADDRESS(cs->config, struct stringlistlist);
+  if(nvec == 0) {
+    sll->n = 0;
+    return 0;
+  }
   sll->n++;
   sll->s = xrealloc(sll->s, (sll->n * sizeof (struct stringlist)));
   s = &sll->s[sll->n - 1];
   sll->n++;
   sll->s = xrealloc(sll->s, (sll->n * sizeof (struct stringlist)));
   s = &sll->s[sll->n - 1];
@@ -243,6 +255,10 @@ static int set_string_accum(const struct config_state *cs,
   struct stringlist *sl;
 
   sl = ADDRESS(cs->config, struct stringlist);
   struct stringlist *sl;
 
   sl = ADDRESS(cs->config, struct stringlist);
+  if(nvec == 0) {
+    sl->n = 0;
+    return 0;
+  }
   for(n = 0; n < nvec; ++n) {
     sl->n++;
     sl->s = xrealloc(sl->s, (sl->n * sizeof (char *)));
   for(n = 0; n < nvec; ++n) {
     sl->n++;
     sl->s = xrealloc(sl->s, (sl->n * sizeof (char *)));
@@ -474,6 +490,23 @@ static int set_backend(const struct config_state *cs,
   return 0;
 }
 
   return 0;
 }
 
+static int set_rights(const struct config_state *cs,
+                     const struct conf *whoami,
+                     int nvec, char **vec) {
+  if(nvec != 1) {
+    error(0, "%s:%d: '%s' requires one argument",
+         cs->path, cs->line, whoami->name);
+    return -1;
+  }
+  if(parse_rights(vec[0], 0, 1)) {
+    error(0, "%s:%d: invalid rights string '%s'",
+         cs->path, cs->line, vec[0]);
+    return -1;
+  }
+  *ADDRESS(cs->config, char *) = vec[0];
+  return 0;
+}
+
 /* free functions */
 
 static void free_none(struct config attribute((unused)) *c,
 /* free functions */
 
 static void free_none(struct config attribute((unused)) *c,
@@ -572,6 +605,7 @@ static const struct conftype
   type_restrict = { set_restrict, free_none },
   type_namepart = { set_namepart, free_namepartlist },
   type_transform = { set_transform, free_transformlist },
   type_restrict = { set_restrict, free_none },
   type_namepart = { set_namepart, free_namepartlist },
   type_transform = { set_transform, free_transformlist },
+  type_rights = { set_rights, free_none },
   type_backend = { set_backend, free_none };
 
 /* specific validation routine */
   type_backend = { set_backend, free_none };
 
 /* specific validation routine */
@@ -635,6 +669,17 @@ static int validate_player(const struct config_state *cs,
   return 0;
 }
 
   return 0;
 }
 
+static int validate_tracklength(const struct config_state *cs,
+                               int nvec,
+                               char attribute((unused)) **vec) {
+  if(nvec < 2) {
+    error(0, "%s:%d: should be at least 'tracklength PATTERN MODULE'",
+         cs->path, cs->line);
+    return -1;
+  }
+  return 0;
+}
+
 static int validate_allow(const struct config_state *cs,
                          int nvec,
                          char attribute((unused)) **vec) {
 static int validate_allow(const struct config_state *cs,
                          int nvec,
                          char attribute((unused)) **vec) {
@@ -873,6 +918,10 @@ static const struct conf conf[] = {
   { C(checkpoint_min),   &type_integer,          validate_non_negative },
   { C(collection),       &type_collections,      validate_any },
   { C(connect),          &type_stringlist,       validate_addrport },
   { C(checkpoint_min),   &type_integer,          validate_non_negative },
   { C(collection),       &type_collections,      validate_any },
   { C(connect),          &type_stringlist,       validate_addrport },
+  { C(cookie_login_lifetime),  &type_integer,    validate_positive },
+  { C(cookie_key_lifetime),  &type_integer,      validate_positive },
+  { C(dbversion),        &type_integer,          validate_positive },
+  { C(default_rights),   &type_rights,           validate_any },
   { C(device),           &type_string,           validate_any },
   { C(gap),              &type_integer,          validate_non_negative },
   { C(history),          &type_integer,          validate_positive },
   { C(device),           &type_string,           validate_any },
   { C(gap),              &type_integer,          validate_non_negative },
   { C(history),          &type_integer,          validate_positive },
@@ -880,6 +929,7 @@ static const struct conf conf[] = {
   { C(listen),           &type_stringlist,       validate_port },
   { C(lock),             &type_boolean,          validate_any },
   { C(mixer),            &type_string,           validate_ischr },
   { C(listen),           &type_stringlist,       validate_port },
   { C(lock),             &type_boolean,          validate_any },
   { C(mixer),            &type_string,           validate_ischr },
+  { C(multicast_loop),   &type_boolean,          validate_any },
   { C(multicast_ttl),    &type_integer,          validate_non_negative },
   { C(namepart),         &type_namepart,         validate_any },
   { C2(nice, nice_rescan), &type_integer,        validate_non_negative },
   { C(multicast_ttl),    &type_integer,          validate_non_negative },
   { C(namepart),         &type_namepart,         validate_any },
   { C2(nice, nice_rescan), &type_integer,        validate_non_negative },
@@ -896,12 +946,14 @@ static const struct conf conf[] = {
   { C2(restrict, restrictions),         &type_restrict,         validate_any },
   { C(sample_format),    &type_sample_format,    validate_sample_format },
   { C(scratch),          &type_string_accum,     validate_isreg },
   { C2(restrict, restrictions),         &type_restrict,         validate_any },
   { C(sample_format),    &type_sample_format,    validate_sample_format },
   { C(scratch),          &type_string_accum,     validate_isreg },
+  { C(short_display),    &type_integer,          validate_positive },
   { C(signal),           &type_signal,           validate_any },
   { C(sox_generation),   &type_integer,          validate_non_negative },
   { C(speaker_backend),  &type_backend,          validate_any },
   { C(speaker_command),  &type_string,           validate_any },
   { C(stopword),         &type_string_accum,     validate_any },
   { C(templates),        &type_string_accum,     validate_isdir },
   { C(signal),           &type_signal,           validate_any },
   { C(sox_generation),   &type_integer,          validate_non_negative },
   { C(speaker_backend),  &type_backend,          validate_any },
   { C(speaker_command),  &type_string,           validate_any },
   { C(stopword),         &type_string_accum,     validate_any },
   { C(templates),        &type_string_accum,     validate_isdir },
+  { C(tracklength),      &type_stringlist_accum, validate_tracklength },
   { C(transform),        &type_transform,        validate_any },
   { C(trust),            &type_string_accum,     validate_any },
   { C(url),              &type_string,           validate_url },
   { C(transform),        &type_transform,        validate_any },
   { C(trust),            &type_string_accum,     validate_any },
   { C(url),              &type_string,           validate_url },
@@ -1021,8 +1073,15 @@ static struct config *config_default(void) {
   c->queue_pad = 10;
   c->speaker_backend = -1;
   c->multicast_ttl = 1;
   c->queue_pad = 10;
   c->speaker_backend = -1;
   c->multicast_ttl = 1;
+  c->multicast_loop = 1;
   c->authorization_algorithm = xstrdup("sha1");
   c->noticed_history = 31;
   c->authorization_algorithm = xstrdup("sha1");
   c->noticed_history = 31;
+  c->short_display = 32;
+  c->mixer = xstrdup("/dev/mixer");
+  c->channel = xstrdup("pcm");
+  c->dbversion = 2;
+  c->cookie_login_lifetime = 86400;
+  c->cookie_key_lifetime = 86400 * 7;
   return c;
 }
 
   return c;
 }
 
@@ -1128,7 +1187,26 @@ static void config_postdefaults(struct config *c,
     c->sample_format.bits = 16;
     c->sample_format.endian = ENDIAN_NATIVE;
     break; 
     c->sample_format.bits = 16;
     c->sample_format.endian = ENDIAN_NATIVE;
     break; 
- }
+  }
+  if(!c->default_rights) {
+    rights_type r = RIGHTS__MASK & ~(RIGHT_ADMIN|RIGHT_REGISTER
+                                    |RIGHT_MOVE__MASK
+                                    |RIGHT_SCRATCH__MASK
+                                    |RIGHT_REMOVE__MASK);
+    /* The idea is to approximate the meaning of the old 'restrict' directive
+     * in the default rights if they are not overridden. */
+    if(c->restrictions & RESTRICT_SCRATCH)
+      r |= RIGHT_SCRATCH_MINE|RIGHT_SCRATCH_RANDOM;
+    else
+      r |= RIGHT_SCRATCH_ANY;
+    if(!(c->restrictions & RESTRICT_MOVE))
+      r |= RIGHT_MOVE_ANY;
+    if(c->restrictions & RESTRICT_REMOVE)
+      r |= RIGHT_REMOVE_MINE;
+    else
+      r |= RIGHT_REMOVE_ANY;
+    c->default_rights = rights_string(r);
+  }
 }
 
 /** @brief (Re-)read the config file
 }
 
 /** @brief (Re-)read the config file
@@ -1152,23 +1230,32 @@ int config_read(int server) {
     return -1;
   xfree(privconf);
   /* if there's a per-user system config file for this user, read it */
     return -1;
   xfree(privconf);
   /* if there's a per-user system config file for this user, read it */
-  if(!(pw = getpwuid(getuid())))
-    fatal(0, "cannot determine our username");
-  if((privconf = config_usersysconf(pw))
-     && access(privconf, F_OK) == 0
-     && config_include(c, privconf))
+  if(config_per_user) {
+    if(!(pw = getpwuid(getuid())))
+      fatal(0, "cannot determine our username");
+    if((privconf = config_usersysconf(pw))
+       && access(privconf, F_OK) == 0
+       && config_include(c, privconf))
       return -1;
       return -1;
-  xfree(privconf);
-  /* if we have a password file, read it */
-  if((privconf = config_userconf(getenv("HOME"), pw))
-     && access(privconf, F_OK) == 0
-     && config_include(c, privconf))
-    return -1;
-  xfree(privconf);
+    xfree(privconf);
+    /* if we have a password file, read it */
+    if((privconf = config_userconf(getenv("HOME"), pw))
+       && access(privconf, F_OK) == 0
+       && config_include(c, privconf))
+      return -1;
+    xfree(privconf);
+  }
   /* install default namepart and transform settings */
   config_postdefaults(c, server);
   /* everything is good so we shall use the new config */
   config_free(config);
   /* install default namepart and transform settings */
   config_postdefaults(c, server);
   /* everything is good so we shall use the new config */
   config_free(config);
+  /* warn about obsolete directives */
+  if(c->restrictions)
+    error(0, "'restrict' will be removed in a future version");
+  if(c->allow.n)
+    error(0, "'allow' will be removed in a future version");
+  if(c->trust.n)
+    error(0, "'trust' will be removed in a future version");
   config = c;
   return 0;
 }
   config = c;
   return 0;
 }
@@ -1186,6 +1273,8 @@ char *config_private(void) {
 char *config_userconf(const char *home, const struct passwd *pw) {
   char *s;
 
 char *config_userconf(const char *home, const struct passwd *pw) {
   char *s;
 
+  if(!home && !pw && !(pw = getpwuid(getuid())))
+    fatal(0, "cannot determine our username");
   byte_xasprintf(&s, "%s/.disorder/passwd", home ? home : pw->pw_dir);
   return s;
 }
   byte_xasprintf(&s, "%s/.disorder/passwd", home ? home : pw->pw_dir);
   return s;
 }