From 5b14453f9fc5ae923c613e2154ede85637462469 Mon Sep 17 00:00:00 2001 Message-Id: <5b14453f9fc5ae923c613e2154ede85637462469.1716935266.git.mdw@distorted.org.uk> From: Mark Wooding Date: Tue, 1 Jan 2008 14:21:10 +0000 Subject: [PATCH] disorder authorize now creates ~USER/.disorder/passwd instead of /etc/disorder/config.USER. This is a bit fiddlier than the old code but reduces the number of places the user must look for their password. Organization: Straylight/Edgeware From: Richard Kettlewell Generated passwords are base64 rather than hex, and are slightly longer (in terms of the underlying bytes). They aren't human memorable but in practice they are expected to be kept in ~/.disorder/passwd or a browser's password store. The configuration parser now always uses pw_home rather than $HOME to find ~/.disorder. Mention Ubuntu in README as the debs work there too. --- README | 14 ++++--- clients/authorize.c | 86 +++++++++++++++++++++++++--------------- doc/disorder.1.in | 8 +++- doc/disorder_config.5.in | 15 ++++--- lib/configuration.c | 2 +- 5 files changed, 79 insertions(+), 46 deletions(-) diff --git a/README b/README index 11bbbb0..1c5edde 100644 --- a/README +++ b/README @@ -8,12 +8,13 @@ DisOrder is a multi-user software jukebox. * It supports both ALSA and OSS and can also broadcast an RTP stream over a LAN; a player for the latter is included. * Tracks may be selected either via a hierarchical interface or by a fast - word search. + word or tag search. * It has a web interface (allowing access from graphical web browsers) and a GTK+ interface that runs on Linux and Mac systems. * Playing tracks can be paused or cancelled ("scratched"). -See CHANGES for details of recent changes to DisOrder. +See CHANGES for details of recent changes to DisOrder and README.upgrades for +upgrade instructions. The server supports Linux and can be made to work on a Mac (see README.mac). The clients work on both Linux and the Mac. It could probably be ported to @@ -71,10 +72,11 @@ Installation "This place'd be a paradise tomorrow, if every department had a supervisor with a machine-gun" -NOTE: If you are upgrading from an earlier version, see README.upgrades. +IMPORTANT: If you are upgrading from an earlier version, see README.upgrades. -On a Debian system, if you install from .deb files then you should be able to -skip steps 1 to 6 and configure it via debconf. This is strongly recommended! +On a Debian or Ubuntu system, if you install from .deb files then you should be +able to skip steps 1 to 6 and configure it via debconf. This is strongly +recommended! 1. Build the software. Do something like this: @@ -164,7 +166,7 @@ skip steps 1 to 6 and configure it via debconf. This is strongly recommended! disorder authorize USERNAME This will automatically choose a random password and create - /etc/disorder/config.USERNAME. + ~USERNAME/.disorder/passwd. Those users should now be able to access the server from the same host as it runs on, either via the disorder command or Disobedience. To run diff --git a/clients/authorize.c b/clients/authorize.c index c442d23..fb88c68 100644 --- a/clients/authorize.c +++ b/clients/authorize.c @@ -34,7 +34,7 @@ #include "log.h" #include "configuration.h" #include "printf.h" -#include "hex.h" +#include "base64.h" /** @brief Create a DisOrder login for the calling user, called @p user * @param client DisOrder client @@ -43,49 +43,73 @@ * @return 0 on success, non-0 on error */ int authorize(disorder_client *client, const char *user, const char *rights) { - uint8_t pwbin[10]; - const struct passwd *pw, *jbpw; - gid_t jbgid; - char *c, *t, *pwhex; + /* base64 is 3-into-4 so we make the password a multiple of 3 bytes long */ + uint8_t pwbin[12]; + const struct passwd *pw; + char *pwhex; int fd; FILE *fp; + char *configdir, *configpath, *configpathtmp; + struct stat sb; + uid_t old_uid = getuid(); + gid_t old_gid = getgid(); - if(!(jbpw = getpwnam(config->user))) - fatal(0, "cannot find user %s", config->user); - jbgid = jbpw->pw_gid; if(!(pw = getpwnam(user))) - fatal(0, "no such user as %s", user); - if((c = config_userconf(0, pw)) && access(c, F_OK) == 0) { - error(0, "%s already exists", c); - return -1; - } - if((c = config_usersysconf(pw)) && access(c, F_OK) == 0) { - error(0, "%s already exists", c); + /* If it's a NIS world then /etc/passwd may be a lie, but it emphasizes + * that it's talking about the login user, not the DisOrder user */ + fatal(0, "no such user as %s in /etc/passwd", user); + + /* Choose a random password */ + gcry_randomize(pwbin, sizeof pwbin, GCRY_STRONG_RANDOM); + pwhex = mime_to_base64(pwbin, sizeof pwbin); + + /* Create the user on the server */ + if(disorder_adduser(client, user, pwhex, rights)) return -1; + + /* Become the target user */ + if(setegid(pw->pw_gid) < 0) + fatal(errno, "setegid %lu", (unsigned long)pw->pw_gid); + if(seteuid(pw->pw_uid) < 0) + fatal(errno, "seteuid %lu", (unsigned long)pw->pw_uid); + + /* Make sure the configuration directory exists*/ + byte_xasprintf(&configdir, "%s/.disorder", pw->pw_dir); + if(mkdir(configdir, 02700) < 0) { + if(errno != EEXIST) + fatal(errno, "creating %s", configdir); } - byte_xasprintf(&t, "%s.new", c); - gcry_randomize(pwbin, sizeof pwbin, GCRY_STRONG_RANDOM); - pwhex = hex(pwbin, sizeof pwbin); - /* create config.USER, to end up with mode 400 user: */ - if((fd = open(t, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) - fatal(errno, "error creating %s", t); - if(fchown(fd, pw->pw_uid, -1) < 0) - fatal(errno, "error chowning %s", t); - if(fchmod(fd, 0400) < 0) - fatal(errno, "error chmoding %s", t); + /* Make sure the configuration file does not exist */ + byte_xasprintf(&configpath, "%s/passwd", configdir); + if(lstat(configpath, &sb) == 0) + fatal(0, "%s already exists", configpath); + if(errno != ENOENT) + fatal(errno, " checking %s", configpath); + + byte_xasprintf(&configpathtmp, "%s.new", configpath); + + /* Create config file with mode 600 */ + if((fd = open(configpathtmp, O_WRONLY|O_CREAT, 0600)) < 0) + fatal(errno, "error creating %s", configpathtmp); + + /* Write password */ if(!(fp = fdopen(fd, "w"))) fatal(errno, "error calling fdopen"); if(fprintf(fp, "password %s\n", pwhex) < 0 || fclose(fp) < 0) - fatal(errno, "error writing to %s", t); - if(rename(t, c) < 0) - fatal(errno, "error renaming %s to %s", t, c); + fatal(errno, "error writing to %s", configpathtmp); - /* create the user on the server */ - if(disorder_adduser(client, user, pwhex, rights)) - return -1; + /* Rename config file into place */ + if(rename(configpathtmp, configpath) < 0) + fatal(errno, "error renaming %s to %s", configpathtmp, configpath); + /* Put our identity back */ + if(seteuid(old_uid) < 0) + fatal(errno, "seteuid %lu", (unsigned long)old_uid); + if(setegid(old_gid) < 0) + fatal(errno, "setegid %lu", (unsigned long)old_gid); + return 0; } diff --git a/doc/disorder.1.in b/doc/disorder.1.in index 1fd94b5..7a443b7 100644 --- a/doc/disorder.1.in +++ b/doc/disorder.1.in @@ -63,8 +63,12 @@ Create \fIUSER\fR with a random password. \fIUSER\fR must be a UNIX login user (not just any old string). If \fIRIGHTS\fR is not specified then the \fBdefault_rights\fR setting from the server's configuration file applies. .IP -An appropriate \fIconfig.USER\fR is created, owned by the user, so they should -be able to log in immediately. +\fI~USER/.disorder/passwd\fR is created with the password in it, so the new +user should be able to log in immediately. +.IP +If writing the \fIpasswd\fR file fails then the user will already have been +created in DisOrder's user database. Use \fBdisorder deluser\fR to remove them +before trying again. .TP .B deluser \fIUSER\fR Delete a user. diff --git a/doc/disorder_config.5.in b/doc/disorder_config.5.in index 3b2e5a9..b545b69 100644 --- a/doc/disorder_config.5.in +++ b/doc/disorder_config.5.in @@ -200,17 +200,20 @@ Configuration files are read in the following order: .TP .I pkgconfdir/config.private Should be readable only by the jukebox group. Not really useful any more and -may be abolished in future. -.TP -.I pkgconfdir/config.\fRUSER -Per-user system-controlled client configuration. Optional but if it -exists must be readable only by the relevant user. Would normally -contain a \fBpassword\fR directive. +will be abolished in future. .TP .I ~\fRUSER\fI/.disorder/passwd Per-user client configuration. Optional but if it exists must be readable only by the relevant user. Would normally contain a \fBpassword\fR directive. +.TP +.I pkgconfdir/config.\fRUSER +Per-user system-controlled client configuration. Optional but if it +exists must be readable only by the relevant user. Would normally +contain a \fBpassword\fR directive. +.IP +The prefererred location for per-user passwords is \fI~/.disorder/passwd\fR and +\fBdisorder authorize\fR writes there now. .SS "Global Configuration" .TP .B home \fIDIRECTORY\fR diff --git a/lib/configuration.c b/lib/configuration.c index d81b09b..ba50f3c 100644 --- a/lib/configuration.c +++ b/lib/configuration.c @@ -1359,7 +1359,7 @@ int config_read(int server) { return -1; xfree(privconf); /* if we have a password file, read it */ - if((privconf = config_userconf(getenv("HOME"), pw)) + if((privconf = config_userconf(0, pw)) && access(privconf, F_OK) == 0 && config_include(c, privconf)) return -1; -- [mdw]