chiark / gitweb /
Merge playlist support.
[disorder] / server / server.c
index 320cbb174ec94c0f925d8e607773d03e6193fc8d..ce45a1dd6a968c7c116fbb061638f545a4c3fbe6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This file is part of DisOrder.
- * Copyright (C) 2004-2008 Richard Kettlewell
+ * Copyright (C) 2004-2009 Richard Kettlewell
  *
  * 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
  */
 
 #include "disorder-server.h"
+#include "basen.h"
 
 #ifndef NONCE_SIZE
 # define NONCE_SIZE 16
 #endif
 
 #ifndef CONFIRM_SIZE
-# define CONFIRM_SIZE 10
+/** @brief Size of nonce in confirmation string in 32-bit words
+ *
+ * 64 bits gives 11 digits (in base 62).
+ */
+# define CONFIRM_SIZE 2
 #endif
 
 int volume_left, volume_right;         /* last known volume */
@@ -874,17 +879,18 @@ static int c_volume(struct conn *c,
     sink_writes(ev_writer_sink(c->w), "510 Prohibited\n");
     return 1;
   }
-  if(mixer_control(-1/*as configured*/, &l, &r, set))
+  if(!api || !api->set_volume) {
     sink_writes(ev_writer_sink(c->w), "550 error accessing mixer\n");
-  else {
-    sink_printf(ev_writer_sink(c->w), "252 %d %d\n", l, r);
-    if(l != volume_left || r != volume_right) {
-      volume_left = l;
-      volume_right = r;
-      snprintf(lb, sizeof lb, "%d", l);
-      snprintf(rb, sizeof rb, "%d", r);
-      eventlog("volume", lb, rb, (char *)0);
-    }
+    return 1;
+  }
+  (set ? api->set_volume : api->get_volume)(&l, &r);
+  sink_printf(ev_writer_sink(c->w), "252 %d %d\n", l, r);
+  if(l != volume_left || r != volume_right) {
+    volume_left = l;
+    volume_right = r;
+    snprintf(lb, sizeof lb, "%d", l);
+    snprintf(rb, sizeof rb, "%d", r);
+    eventlog("volume", lb, rb, (char *)0);
   }
   return 1;
 }
@@ -1151,10 +1157,13 @@ static int c_new(struct conn *c,
 static int c_rtp_address(struct conn *c,
                         char attribute((unused)) **vec,
                         int attribute((unused)) nvec) {
-  if(config->api == BACKEND_NETWORK) {
+  if(api == &uaudio_rtp) {
+    char **addr;
+
+    netaddress_format(&config->broadcast, NULL, &addr);
     sink_printf(ev_writer_sink(c->w), "252 %s %s\n",
-               quoteutf8(config->broadcast.s[0]),
-               quoteutf8(config->broadcast.s[1]));
+               quoteutf8(addr[1]),
+               quoteutf8(addr[2]));
   } else
     sink_writes(ev_writer_sink(c->w), "550 No RTP\n");
   return 1;
@@ -1361,30 +1370,23 @@ static int c_users(struct conn *c,
   return list_response(c, "User list follows", trackdb_listusers());
 }
 
-/** @brief Base64 mapping table for confirmation strings
- *
- * This is used with generic_to_base64() and generic_base64().  We cannot use
- * the MIME table as that contains '+' and '=' which get quoted when
- * URL-encoding.  (The CGI still does the URL encoding but it is desirable to
- * avoid it being necessary.)
- */
-static const char confirm_base64_table[] =
-  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/.*";
-
 static int c_register(struct conn *c,
                      char **vec,
                      int attribute((unused)) nvec) {
-  char *buf, *cs;
-  size_t bufsize;
-  int offset;
-
-  /* The confirmation string is base64(username;nonce) */
-  bufsize = strlen(vec[0]) + CONFIRM_SIZE + 2;
-  buf = xmalloc_noptr(bufsize);
-  offset = byte_snprintf(buf, bufsize, "%s;", vec[0]);
-  gcry_randomize(buf + offset, CONFIRM_SIZE, GCRY_STRONG_RANDOM);
-  cs = generic_to_base64((uint8_t *)buf, offset + CONFIRM_SIZE,
-                        confirm_base64_table);
+  char *cs;
+  uint32_t nonce[CONFIRM_SIZE];
+  char nonce_str[(32 * CONFIRM_SIZE) / 5 + 1];
+
+  /* The confirmation string is username/base62(nonce).  The confirmation
+   * process will pick the username back out to identify them but the _whole_
+   * string is used as the confirmation string.  Base 62 means we used only
+   * letters and digits, minimizing the chance of the URL being mispasted. */
+  gcry_randomize(nonce, sizeof nonce, GCRY_STRONG_RANDOM);
+  if(basen(nonce, CONFIRM_SIZE, nonce_str, sizeof nonce_str, 62)) {
+    error(0, "buffer too small encoding confirmation string");
+    sink_writes(ev_writer_sink(c->w), "550 Cannot create user\n");
+  }
+  byte_xasprintf(&cs, "%s/%s", vec[0], nonce_str);
   if(trackdb_adduser(vec[0], vec[1], config->default_rights, vec[2], cs))
     sink_writes(ev_writer_sink(c->w), "550 Cannot create user\n");
   else
@@ -1395,7 +1397,6 @@ static int c_register(struct conn *c,
 static int c_confirm(struct conn *c,
                     char **vec,
                     int attribute((unused)) nvec) {
-  size_t nuser;
   char *user, *sep;
   rights_type rights;
   const char *host;
@@ -1405,12 +1406,12 @@ static int c_confirm(struct conn *c,
     sink_writes(ev_writer_sink(c->w), "530 Authentication failure\n");
     return 1;
   }
-  if(!(user = generic_base64(vec[0], &nuser, confirm_base64_table))
-     || !(sep = memchr(user, ';', nuser))) {
+  /* Picking the LAST / means we don't (here) rule out slashes in usernames. */
+  if(!(sep = strrchr(vec[0], '/'))) {
     sink_writes(ev_writer_sink(c->w), "550 Malformed confirmation string\n");
     return 1;
   }
-  *sep = 0;
+  user = xstrndup(vec[0], sep - vec[0]);
   if(trackdb_confirm(user, vec[0], &rights))
     sink_writes(ev_writer_sink(c->w), "550 Incorrect confirmation string\n");
   else {
@@ -2092,6 +2093,7 @@ int server_start(ev_source *ev, int pf,
   l->pf = pf;
   if(ev_listen(ev, fd, listen_callback, l, "server listener"))
     exit(EXIT_FAILURE);
+  info("listening on %s", name);
   return fd;
 }