/*
* 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 */
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;
}
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;
return 1; /* completed */
}
-/** @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
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;
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 {
c->ev = ev;
c->w = ev_writer_new(ev, fd, writer_error, c,
"client writer");
+ if(!c->w) {
+ error(0, "ev_writer_new for file inbound connection (fd=%d) failed",
+ fd);
+ close(fd);
+ return 0;
+ }
c->r = ev_reader_new(ev, fd, redirect_reader_callback, reader_error, c,
"client reader");
+ if(!c->r)
+ /* Main reason for failure is the FD is too big and that will already have
+ * been handled */
+ fatal(0, "ev_reader_new for file inbound connection (fd=%d) failed", fd);
ev_tie(c->r, c->w);
c->fd = fd;
c->reader = reader_callback;
l->pf = pf;
if(ev_listen(ev, fd, listen_callback, l, "server listener"))
exit(EXIT_FAILURE);
+ info("listening on %s", name);
return fd;
}