asprintf.c fprintf.c snprintf.c \
queue.c queue.h \
regsub.c regsub.h \
+ rights.c rights.h \
rtp.h \
selection.c selection.h \
signame.c signame.h \
#include "addr.h"
#include "authhash.h"
#include "client-common.h"
+#include "rights.h"
#include "trackdb.h"
struct disorder_client {
return disorder_simple(c, 0, "deluser", user, (char *)0);
}
+int disorder_userinfo(disorder_client *c, const char *user, const char *key) {
+ return disorder_simple(c, 0, "userinfo", user, key, (char *)0);
+}
+
+int disorder_edituser(disorder_client *c, const char *user,
+ const char *key, const char *value) {
+ return disorder_simple(c, 0, "edituser", user, key, value, (char *)0);
+}
+
/*
Local Variables:
c-basic-offset:2
int disorder_adduser(disorder_client *c,
const char *user, const char *password);
int disorder_deluser(disorder_client *c, const char *user);
+int disorder_userinfo(disorder_client *c, const char *user, const char *key);
+int disorder_edituser(disorder_client *c, const char *user,
+ const char *key, const char *value);
#endif /* CLIENT_H */
#include "mime.h"
#include "configuration.h"
#include "kvp.h"
+#include "rights.h"
#include "trackdb.h"
/** @brief Hash function used in signing HMAC */
--- /dev/null
+/*
+ * This file is part of DisOrder
+ * Copyright (C) 2007 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+/** @file lib/rights.c
+ * @brief User rights
+ */
+
+#include <config.h>
+#include "types.h"
+
+#include <string.h>
+
+#include "mem.h"
+#include "log.h"
+#include "configuration.h"
+#include "rights.h"
+#include "vector.h"
+
+static const struct {
+ rights_type bit;
+ const char *name;
+} rights_names[] = {
+ { RIGHT_READ, "read" },
+ { RIGHT_PLAY, "play" },
+ { RIGHT_MOVE_ANY, "move any" },
+ { RIGHT_MOVE_MINE, "move mine" },
+ { RIGHT_MOVE_RANDOM, "move random" },
+ { RIGHT_REMOVE_ANY, "remove any" },
+ { RIGHT_REMOVE_MINE, "remove mine" },
+ { RIGHT_REMOVE_RANDOM, "remove random" },
+ { RIGHT_SCRATCH_ANY, "scratch any" },
+ { RIGHT_SCRATCH_MINE, "scratch mine" },
+ { RIGHT_SCRATCH_RANDOM, "scratch random" },
+ { RIGHT_VOLUME, "volume" },
+ { RIGHT_ADMIN, "admin" },
+ { RIGHT_RESCAN, "rescan" },
+ { RIGHT_REGISTER, "register" },
+ { RIGHT_USERINFO, "userinfo" },
+ { RIGHT_PREFS, "prefs" },
+ { RIGHT_GLOBAL_PREFS, "global prefs" }
+};
+#define NRIGHTS (sizeof rights_names / sizeof *rights_names)
+
+/** @brief Convert a rights word to a string */
+char *rights_string(rights_type r) {
+ struct dynstr d[1];
+ size_t n;
+
+ dynstr_init(d);
+ for(n = 0; n < NRIGHTS; ++n) {
+ if(r & rights_names[n].bit) {
+ if(d->nvec)
+ dynstr_append(d, ',');
+ dynstr_append_string(d, rights_names[n].name);
+ }
+ }
+ dynstr_terminate(d);
+ return d->vec;
+}
+
+/** @brief Compute default rights for a new user
+ * @return Default rights value
+ */
+rights_type default_rights(void) {
+ /* TODO get rights from config */
+ rights_type r = RIGHTS__MASK & ~(RIGHT_ADMIN|RIGHT_REGISTER
+ |RIGHT_MOVE__MASK
+ |RIGHT_SCRATCH__MASK
+ |RIGHT_REMOVE__MASK);
+ if(config->restrictions & RESTRICT_SCRATCH)
+ r |= RIGHT_SCRATCH_MINE|RIGHT_SCRATCH_RANDOM;
+ else
+ r |= RIGHT_SCRATCH_ANY;
+ if(!(config->restrictions & RESTRICT_MOVE))
+ r |= RIGHT_MOVE_ANY;
+ if(config->restrictions & RESTRICT_REMOVE)
+ r |= RIGHT_REMOVE_MINE;
+ else
+ r |= RIGHT_REMOVE_ANY;
+ return r;
+}
+
+/** @brief Parse a rights list
+ * @param s Rights list in string form
+ * @param rp Where to store rights, or NULL to just validate
+ * @return 0 on success, non-0 if @p s is not valid
+ */
+int parse_rights(const char *s, rights_type *rp) {
+ rights_type r = 0;
+ const char *t;
+ size_t n, l;
+
+ if(!*s) {
+ /* You can't have no rights */
+ error(0, "empty rights string");
+ return -1;
+ }
+ while(*s) {
+ t = strchr(s, ',');
+ if(!t)
+ t = s + strlen(s);
+ l = (size_t)(t - s);
+ if(l == 3 && !strncmp(s, "all", 3))
+ r = RIGHTS__MASK;
+ else {
+ for(n = 0; n < NRIGHTS; ++n)
+ if(strlen(rights_names[n].name) == l
+ && !strncmp(rights_names[n].name, s, l))
+ break;
+ if(n >= NRIGHTS) {
+ error(0, "unknown user right '%.*s'", (int)l, s);
+ return -1;
+ }
+ r |= rights_names[n].bit;
+ }
+ s = t;
+ if(*s == ',')
+ ++s;
+ }
+ if(rp)
+ *rp = r;
+ return 0;
+}
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
--- /dev/null
+/*
+ * This file is part of DisOrder
+ * Copyright (C) 2007 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+/** @file lib/rights.h
+ * @brief User rights
+ */
+
+#ifndef RIGHTS_H
+#define RIGHTS_H
+
+/** @brief User can perform read-only operations */
+#define RIGHT_READ 0x00000001
+
+/** @brief User can add tracks to the queue */
+#define RIGHT_PLAY 0x00000002
+
+/** @brief User can move any track */
+#define RIGHT_MOVE_ANY 0x00000004
+
+/** @brief User can move their own tracks */
+#define RIGHT_MOVE_MINE 0x00000008
+
+/** @brief User can move randomly chosen tracks */
+#define RIGHT_MOVE_RANDOM 0x00000010
+
+#define RIGHT_MOVE__MASK 0x0000001c
+
+/** @brief User can remove any track */
+#define RIGHT_REMOVE_ANY 0x00000020
+
+/** @brief User can remove their own tracks */
+#define RIGHT_REMOVE_MINE 0x00000040
+
+/** @brief User can remove randomly chosen tracks */
+#define RIGHT_REMOVE_RANDOM 0x00000080
+
+#define RIGHT_REMOVE__MASK 0x000000e0
+
+/** @brief User can scratch any track */
+#define RIGHT_SCRATCH_ANY 0x00000100
+
+/** @brief User can scratch their own tracks */
+#define RIGHT_SCRATCH_MINE 0x00000200
+
+/** @brief User can scratch randomly chosen tracks */
+#define RIGHT_SCRATCH_RANDOM 0x00000400
+
+#define RIGHT_SCRATCH__MASK 0x00000700
+
+/** @brief User can change the volume */
+#define RIGHT_VOLUME 0x00000800
+
+/** @brief User can perform admin operations */
+#define RIGHT_ADMIN 0x00001000
+
+/** @brief User can initiate a rescan */
+#define RIGHT_RESCAN 0x00002000
+
+/** @brief User can register new users */
+#define RIGHT_REGISTER 0x00004000
+
+/** @brief User can edit their own userinfo */
+#define RIGHT_USERINFO 0x00008000
+
+/** @brief User can modify track preferences */
+#define RIGHT_PREFS 0x00010000
+
+/** @brief User can modify global preferences */
+#define RIGHT_GLOBAL_PREFS 0x00020000
+
+/** @brief Current rights mask */
+#define RIGHTS__MASK 0x0003ffff
+
+/** @brief Unsigned type big enough for rights */
+typedef uint32_t rights_type;
+
+rights_type default_rights(void);
+char *rights_string(rights_type r);
+int parse_rights(const char *s, rights_type *rp);
+
+#endif /* RIGHTS_H */
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
#include "kvp.h"
#include "log.h"
#include "vector.h"
+#include "rights.h"
#include "trackdb.h"
#include "configuration.h"
#include "syscalls.h"
return n < config->trust.n;
}
-static const struct {
- rights_type bit;
- const char *name;
-} rights_names[] = {
- { RIGHT_READ, "read" },
- { RIGHT_PLAY, "play" },
- { RIGHT_MOVE_ANY, "move any" },
- { RIGHT_MOVE_MINE, "move mine" },
- { RIGHT_MOVE_RANDOM, "move random" },
- { RIGHT_REMOVE_ANY, "remove any" },
- { RIGHT_REMOVE_MINE, "remove mine" },
- { RIGHT_REMOVE_RANDOM, "remove random" },
- { RIGHT_SCRATCH_ANY, "scratch any" },
- { RIGHT_SCRATCH_MINE, "scratch mine" },
- { RIGHT_SCRATCH_RANDOM, "scratch random" },
- { RIGHT_VOLUME, "volume" },
- { RIGHT_ADMIN, "admin" },
- { RIGHT_RESCAN, "rescan" },
- { RIGHT_REGISTER, "register" },
- { RIGHT_USERINFO, "userinfo" },
- { RIGHT_PREFS, "prefs" },
- { RIGHT_GLOBAL_PREFS, "global prefs" }
-};
-#define NRIGHTS (sizeof rights_names / sizeof *rights_names)
-
-/** @brief Convert a rights word to a string */
-static char *rights_string(rights_type r) {
- struct dynstr d[1];
- size_t n;
-
- dynstr_init(d);
- for(n = 0; n < NRIGHTS; ++n) {
- if(r & rights_names[n].bit) {
- if(d->nvec)
- dynstr_append(d, ',');
- dynstr_append_string(d, rights_names[n].name);
- }
- }
- dynstr_terminate(d);
- return d->vec;
-}
-
-/** @brief Compute default rights for a new user */
-rights_type default_rights(void) {
- /* TODO get rights from config. This is probably in the wrong place but it
- * will do for now... */
- rights_type r = RIGHTS__MASK & ~(RIGHT_ADMIN|RIGHT_REGISTER
- |RIGHT_MOVE__MASK
- |RIGHT_SCRATCH__MASK
- |RIGHT_REMOVE__MASK);
- if(config->restrictions & RESTRICT_SCRATCH)
- r |= RIGHT_SCRATCH_MINE|RIGHT_SCRATCH_RANDOM;
- else
- r |= RIGHT_SCRATCH_ANY;
- if(!(config->restrictions & RESTRICT_MOVE))
- r |= RIGHT_MOVE_ANY;
- if(config->restrictions & RESTRICT_REMOVE)
- r |= RIGHT_REMOVE_MINE;
- else
- r |= RIGHT_REMOVE_ANY;
- return r;
-}
-
/** @brief Add a user */
static int create_user(const char *user,
const char *password,
* Only works if running as a user that can read the database!
*
* If the user exists but has no password, "" is returned.
+ *
+ * If the user was created with 'register' and has not yet been confirmed then
+ * NULL is still returned.
*/
const char *trackdb_get_password(const char *user) {
int e;
WITH_TRANSACTION(trackdb_getdata(trackdb_usersdb, user, &k, tid));
if(e)
return 0;
+ if(kvp_get(k, "confirmation"))
+ return 0;
password = kvp_get(k, "password");
return password ? password : "";
}
const char *key, const char *value) {
int e;
+ if(!strcmp(key, "rights")) {
+ if(!value) {
+ error(0, "cannot remove 'rights' key from user '%s'", user);
+ return -1;
+ }
+ if(parse_rights(value, 0)) {
+ error(0, "invalid rights string");
+ return -1;
+ }
+ } else if(!strcmp(key, "email")) {
+ if(!strchr(value, '@')) {
+ error(0, "invalid email address '%s' for user '%s'", user, value);
+ return -1;
+ }
+ } else if(!strcmp(key, "created")) {
+ error(0, "cannot change creation date for user '%s'", user);
+ return -1;
+ } else if(strcmp(key, "password")
+ && !strcmp(key, "confirmation")) {
+ error(0, "unknown user info key '%s' for user '%s'", key, user);
+ return -1;
+ }
WITH_TRANSACTION(trackdb_edituserinfo_tid(user, key, value, tid));
- if(e)
+ if(e) {
+ error(0, "unknown user '%s'", user);
return -1;
- else
+ } else
return 0;
}
extern unsigned long cache_files_hits, cache_files_misses;
/* Cache entry type and tracking for regexp-based lookups */
-/** @brief User can perform read-only operations */
-#define RIGHT_READ 0x00000001
-
-/** @brief User can add tracks to the queue */
-#define RIGHT_PLAY 0x00000002
-
-/** @brief User can move any track */
-#define RIGHT_MOVE_ANY 0x00000004
-
-/** @brief User can move their own tracks */
-#define RIGHT_MOVE_MINE 0x00000008
-
-/** @brief User can move randomly chosen tracks */
-#define RIGHT_MOVE_RANDOM 0x00000010
-
-#define RIGHT_MOVE__MASK 0x0000001c
-
-/** @brief User can remove any track */
-#define RIGHT_REMOVE_ANY 0x00000020
-
-/** @brief User can remove their own tracks */
-#define RIGHT_REMOVE_MINE 0x00000040
-
-/** @brief User can remove randomly chosen tracks */
-#define RIGHT_REMOVE_RANDOM 0x00000080
-
-#define RIGHT_REMOVE__MASK 0x000000e0
-
-/** @brief User can scratch any track */
-#define RIGHT_SCRATCH_ANY 0x00000100
-
-/** @brief User can scratch their own tracks */
-#define RIGHT_SCRATCH_MINE 0x00000200
-
-/** @brief User can scratch randomly chosen tracks */
-#define RIGHT_SCRATCH_RANDOM 0x00000400
-
-#define RIGHT_SCRATCH__MASK 0x00000700
-
-/** @brief User can change the volume */
-#define RIGHT_VOLUME 0x00000800
-
-/** @brief User can perform admin operations */
-#define RIGHT_ADMIN 0x00001000
-
-/** @brief User can initiate a rescan */
-#define RIGHT_RESCAN 0x00002000
-
-/** @brief User can register new users */
-#define RIGHT_REGISTER 0x00004000
-
-/** @brief User can edit their own userinfo */
-#define RIGHT_USERINFO 0x00008000
-
-/** @brief User can modify track preferences */
-#define RIGHT_PREFS 0x00010000
-
-/** @brief User can modify global preferences */
-#define RIGHT_GLOBAL_PREFS 0x00020000
-
-/** @brief Current rights mask */
-#define RIGHTS__MASK 0x0003ffff
-
-/** @brief Unsigned type big enough for rights */
-typedef uint32_t rights_type;
-
/** @brief Do not attempt database recovery (trackdb_init()) */
#define TRACKDB_NO_RECOVER 0x0000
int trackdb_edituserinfo(const char *user,
const char *key, const char *value);
-rights_type default_rights(void);
-
#endif /* TRACKDB_H */
/*
"""Delete a user"""
self._simple("deluser", user)
+ def userinfo(self, user, key):
+ """Get user information"""
+ res, details = self._simple("userinfo", user, key)
+ if res == 555:
+ return None
+ return _split(details)[0]
+
+ def edituser(self, user, key, value):
+ """Set user information"""
+ self._simple("edituser", user, key, value)
+
########################################################################
# I/O infrastructure
#include "mem.h"
#include "disorder.h"
#include "event.h"
+#include "rights.h"
#include "trackdb.h"
int disorder_track_exists(const char *track) {
#include "log.h"
#include "defs.h"
#include "kvp.h"
+#include "rights.h"
#include "trackdb.h"
#include "trackdb-int.h"
#include "mem.h"
#include "defs.h"
#include "mem.h"
#include "kvp.h"
+#include "rights.h"
#include "trackdb.h"
#include "trackdb-int.h"
#include "event.h"
#include "log.h"
#include "configuration.h"
+#include "rights.h"
#include "trackdb.h"
#include "queue.h"
#include "mem.h"
#include "kvp.h"
#include "vector.h"
#include "inputline.h"
+#include "rights.h"
#include "trackdb.h"
#include "trackdb-int.h"
#include "charset.h"
#include "configuration.h"
#include "queue.h"
#include "server-queue.h"
+#include "rights.h"
#include "trackdb.h"
#include "play.h"
#include "plugin.h"
#include "wstat.h"
#include "kvp.h"
#include "printf.h"
+#include "rights.h"
#include "trackdb.h"
#include "trackdb-int.h"
#include "trackname.h"
#include "split.h"
#include "configuration.h"
#include "hex.h"
+#include "rights.h"
#include "trackdb.h"
#include "table.h"
#include "kvp.h"
}
static int c_edituser(struct conn *c,
- char attribute((unused)) **vec,
+ char **vec,
int attribute((unused)) nvec) {
- sink_writes(ev_writer_sink(c->w), "550 Not implemented\n"); /* TODO */
+ /* TODO local only */
+ if(trusted(c)
+ || (!strcmp(c->who, vec[0])
+ && (!strcmp(vec[1], "email")
+ || !strcmp(vec[1], "password")))) {
+ if(trackdb_edituserinfo(vec[0], vec[1], vec[2]))
+ sink_writes(ev_writer_sink(c->w), "550 Failed to change setting\n");
+ else
+ sink_writes(ev_writer_sink(c->w), "250 OK\n");
+ } else
+ sink_writes(ev_writer_sink(c->w), "550 Restricted to administrators\n");
return 1;
}
static int c_userinfo(struct conn *c,
char attribute((unused)) **vec,
int attribute((unused)) nvec) {
- sink_writes(ev_writer_sink(c->w), "550 Not implemented\n"); /* TODO */
+ struct kvp *k;
+ const char *value;
+
+ /* TODO local only */
+ if(trusted(c)
+ || (!strcmp(c->who, vec[0])
+ && (!strcmp(vec[1], "email")
+ || !strcmp(vec[1], "rights")))) {
+ if((k = trackdb_getuserinfo(vec[0])))
+ if((value = kvp_get(k, vec[1])))
+ sink_printf(ev_writer_sink(c->w), "252 %s\n", quoteutf8(value));
+ else
+ sink_writes(ev_writer_sink(c->w), "555 Not set\n");
+ else
+ sink_writes(ev_writer_sink(c->w), "550 No such user\n");
+ } else
+ sink_writes(ev_writer_sink(c->w), "550 Restricted to administrators\n");
return 1;
}
#include "event.h"
#include "play.h"
+#include "rights.h"
#include "trackdb.h"
#include "state.h"
#include "configuration.h"
#include "log.h"
#include "syscalls.h"
#include "configuration.h"
+#include "rights.h"
#include "trackdb.h"
static const struct option options[] = {
print " checking new user can log in"
c = disorder.client(user="bob", password="bobpass")
c.version()
+ print " checking bob can set their email address"
+ c.edituser("bob", "email", "foo@bar")
+ email = c.userinfo("bob", "email")
+ assert email == "foo@bar", "checking bob's email address"
print " checking user deletion"
c = disorder.client()
c.deluser("bob")