From: Richard Kettlewell Date: Sat, 22 Dec 2007 15:34:58 +0000 (+0000) Subject: 'cookie' response now includes the username. X-Git-Tag: 3.0~179 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/0227f67dfe89db21ec0262bc054e50f38c2102fb 'cookie' response now includes the username. Rewrote the mad address lookup code shared by client/eclient. disorder_connect_cookie() connects trying to use a cookie and backing off to guest otherwise. --- diff --git a/doc/disorder_protocol.5.in b/doc/disorder_protocol.5.in index 15c8396..6bb2857 100644 --- a/doc/disorder_protocol.5.in +++ b/doc/disorder_protocol.5.in @@ -65,7 +65,8 @@ Confirm user registration. \fICONFIRMATION\fR is as returned from \fBregister\fR below. This command can be used without logging in. .TP .B cookie \fICOOKIE -Log a user back in using a cookie created with \fBmake-cookie\fR. +Log a user back in using a cookie created with \fBmake-cookie\fR. The response +contains the username. .TP .B deluser \fIUSERNAME Delete the named user. Requires the \fBadmin\fR right, and only works on diff --git a/lib/client-common.c b/lib/client-common.c index e1fcce9..d269129 100644 --- a/lib/client-common.c +++ b/lib/client-common.c @@ -1,6 +1,6 @@ /* * This file is part of DisOrder - * Copyright (C) 2004, 2005, 2006 Richard Kettlewell + * Copyright (C) 2004, 2005, 2006, 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 @@ -33,23 +33,19 @@ #include "configuration.h" #include "client-common.h" #include "addr.h" +#include "mem.h" -/** @brief Invoke a function with the connect address - * @param c Passed to callback - * @param function Function to call - * - * Calls @p function with the result of looking up the connect address. +/** @brief Figure out what address to connect to + * @param sap Where to store pointer to sockaddr + * @param namep Where to store socket name + * @return Socket length, or (socklen_t)-1 */ -int with_sockaddr(void *c, - int (*function)(void *c, - const struct sockaddr *sa, - socklen_t len, - const char *ident)) { - const char *path; +socklen_t find_server(struct sockaddr **sap, char **namep) { + struct sockaddr *sa; struct sockaddr_un su; - struct addrinfo *res; + struct addrinfo *res = 0; char *name; - int n; + socklen_t len; static const struct addrinfo pref = { 0, @@ -65,20 +61,27 @@ int with_sockaddr(void *c, if(config->connect.n) { res = get_address(&config->connect, &pref, &name); if(!res) return -1; - n = function(c, res->ai_addr, res->ai_addrlen, name); - freeaddrinfo(res); - return n; + sa = res->ai_addr; + len = res->ai_addrlen; } else { - path = config_get_file("socket"); - if(strlen(path) >= sizeof su.sun_path) { + name = config_get_file("socket"); + if(strlen(name) >= sizeof su.sun_path) { error(errno, "socket path is too long"); return -1; } memset(&su, 0, sizeof su); su.sun_family = AF_UNIX; - strcpy(su.sun_path, path); - return function(c, (struct sockaddr *)&su, sizeof su, path); + strcpy(su.sun_path, name); + sa = (struct sockaddr *)&su; + len = sizeof su; } + *sap = xmalloc_noptr(len); + memcpy(*sap, sa, len); + if(namep) + *namep = name; + if(res) + freeaddrinfo(res); + return len; } /* diff --git a/lib/client-common.h b/lib/client-common.h index 0d88369..bf7e0b5 100644 --- a/lib/client-common.h +++ b/lib/client-common.h @@ -21,11 +21,7 @@ #ifndef CLIENT_COMMON_H #define CLIENT_COMMON_H -int with_sockaddr(void *c, - int (*function)(void *c, - const struct sockaddr *sa, - socklen_t len, - const char *ident)); +socklen_t find_server(struct sockaddr **sap, char **namep); #endif /* CLIENT_COMMON_H */ diff --git a/lib/client.c b/lib/client.c index 0c12c90..fcb0dba 100644 --- a/lib/client.c +++ b/lib/client.c @@ -66,19 +66,13 @@ struct disorder_client { int verbose; }; -static int disorder_connect_sock(disorder_client *c, - const struct sockaddr *sa, - socklen_t len, - const char *username, - const char *password, - const char *ident); - /** @brief Create a new client * @param verbose If nonzero, write extra junk to stderr * @return Pointer to new client * - * You must call disorder_connect() to connect it. Use - * disorder_close() to dispose of the client when finished with it. + * You must call disorder_connect() or disorder_connect_cookie() to + * connect it. Use disorder_close() to dispose of the client when + * finished with it. */ disorder_client *disorder_new(int verbose) { disorder_client *c = xmalloc(sizeof (struct disorder_client)); @@ -208,68 +202,58 @@ static int disorder_simple(disorder_client *c, return ret; } -static int connect_sock(void *vc, - const struct sockaddr *sa, - socklen_t len, - const char *ident) { - const char *username, *password; - disorder_client *c = vc; - - if(!(username = config->username)) { - error(0, "no username configured"); - return -1; - } - password = config->password; - if(!password) { - /* Maybe we can read the database */ - /* TODO failure to open the database should not be fatal */ - trackdb_init(TRACKDB_NO_RECOVER|TRACKDB_NO_UPGRADE); - trackdb_open(TRACKDB_READ_ONLY); - password = trackdb_get_password(username); - trackdb_close(); - } - if(!password) { - /* Oh well */ - error(0, "no password configured"); - return -1; +/** @brief Dequote a result string + * @param rc 0 on success, non-0 on error + * @param rp Where result string is stored (UTF-8) + * @return @p rc + * + * This is used as a wrapper around disorder_simple() to dequote + * results in place. + */ +static int dequote(int rc, char **rp) { + char **rr; + if(!rc) { + if((rr = split(*rp, 0, SPLIT_QUOTES, 0, 0)) && *rr) { + *rp = *rr; + return 0; + } + error(0, "invalid reply: %s", *rp); } - return disorder_connect_sock(c, sa, len, username, password, ident); + return -1; } -/** @brief Connect a client +/** @brief Generic connection routine * @param c Client + * @param username Username to log in with or NULL + * @param password Password to log in with or NULL + * @param cookie Cookie to log in with or NULL * @return 0 on success, non-0 on error * - * The connection will use the username and password found in @ref - * config. + * @p cookie is tried first if not NULL. If it is NULL then @p + * username must not be. If @p username is not NULL then nor may @p + * password be. */ -int disorder_connect(disorder_client *c) { - return with_sockaddr(c, connect_sock); -} - -static int disorder_connect_sock(disorder_client *c, - const struct sockaddr *sa, - socklen_t len, - const char *username, - const char *password, - const char *ident) { +static int disorder_connect_generic(disorder_client *c, + const char *username, + const char *password, + const char *cookie) { int fd = -1, fd2 = -1, nrvec; unsigned char *nonce; size_t nl; const char *res; char *r, **rvec; const char *protocol, *algorithm, *challenge; + struct sockaddr *sa; + socklen_t salen; - if(!password) { - error(0, "no password found"); + if((salen = find_server(&sa, &c->ident)) == (socklen_t)-1) return -1; - } c->fpin = c->fpout = 0; if((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { error(errno, "error calling socket"); return -1; } - if(connect(fd, sa, len) < 0) { + if(connect(fd, sa, salen) < 0) { error(errno, "error calling connect"); goto error; } @@ -287,7 +271,6 @@ static int disorder_connect_sock(disorder_client *c, goto error; } fd2 = -1; - c->ident = xstrdup(ident); if(disorder_simple(c, &r, 0, (const char *)0)) return -1; if(!(rvec = split(r, &nrvec, SPLIT_QUOTES, 0, 0))) @@ -305,6 +288,15 @@ static int disorder_connect_sock(disorder_client *c, challenge = *rvec++; if(!(nonce = unhex(challenge, &nl))) return -1; + if(cookie) { + if(!dequote(disorder_simple(c, &c->user, "cookie", cookie, (char *)0), + &c->user)) + return 0; /* success */ + if(!username) { + error(0, "cookie did not work and no username available"); + return -1; + } + } if(!(res = authhash(nonce, nl, password, algorithm))) goto error; if(disorder_simple(c, 0, "user", username, res, (char *)0)) return -1; @@ -318,6 +310,58 @@ error: return -1; } +/** @brief Connect a client + * @param c Client + * @return 0 on success, non-0 on error + * + * The connection will use the username and password found in @ref + * config, or directly from the database if no password is found and + * the database is readable (usually only for root). + */ +int disorder_connect(disorder_client *c) { + const char *username, *password; + + if(!(username = config->username)) { + error(0, "no username configured"); + return -1; + } + password = config->password; + if(!password) { + /* Maybe we can read the database */ + /* TODO failure to open the database should not be fatal */ + trackdb_init(TRACKDB_NO_RECOVER|TRACKDB_NO_UPGRADE); + trackdb_open(TRACKDB_READ_ONLY); + password = trackdb_get_password(username); + trackdb_close(); + } + if(!password) { + /* Oh well */ + error(0, "no password configured"); + return -1; + } + return disorder_connect_generic(c, + username, + password, + 0); +} + +/** @brief Connect a client + * @param c Client + * @param cookie Cookie to log in with, or NULL + * @return 0 on success, non-0 on error + * + * If @p cookie is NULL or does not work then we attempt to log in as + * guest instead (so when the cookie expires only an extra round trip + * is needed rathre than a complete new login). + */ +int disorder_connect_cookie(disorder_client *c, + const char *cookie) { + return disorder_connect_generic(c, + "guest", + "", + cookie); +} + /** @brief Close a client * @param c Client * @return 0 on succcess, non-0 on errior @@ -342,6 +386,8 @@ int disorder_close(disorder_client *c) { } c->fpout = 0; } + c->ident = 0; + c->user = 0; return 0; } @@ -431,26 +477,6 @@ int disorder_rescan(disorder_client *c) { return disorder_simple(c, 0, "rescan", (char *)0); } -/** @brief Dequote a result string - * @param rc 0 on success, non-0 on error - * @param rp Where result string is stored (UTF-8) - * @return @p rc - * - * This is used as a wrapper around disorder_simple() to dequote - * results in place. - */ -static int dequote(int rc, char **rp) { - char **rr; - if(!rc) { - if((rr = split(*rp, 0, SPLIT_QUOTES, 0, 0)) && *rr) { - *rp = *rr; - return 0; - } - error(0, "invalid reply: %s", *rp); - } - return -1; -} - /** @brief Get server version number * @param c Client * @param rp Where to store version string (UTF-8) @@ -593,7 +619,7 @@ static int disorder_simple_list(disorder_client *c, /** @brief List directories below @p dir * @param c Client - * @param dir Directory to list (UTF-8) + * @param dir Directory to list, or NULL for root (UTF-8) * @param re Regexp that results must match, or NULL (UTF-8) * @param vecp Where to store list (UTF-8) * @param nvecp Where to store number of items, or NULL @@ -606,7 +632,7 @@ int disorder_directories(disorder_client *c, const char *dir, const char *re, /** @brief List files below @p dir * @param c Client - * @param dir Directory to list (UTF-8) + * @param dir Directory to list, or NULL for root (UTF-8) * @param re Regexp that results must match, or NULL (UTF-8) * @param vecp Where to store list (UTF-8) * @param nvecp Where to store number of items, or NULL @@ -619,7 +645,7 @@ int disorder_files(disorder_client *c, const char *dir, const char *re, /** @brief List files and directories below @p dir * @param c Client - * @param dir Directory to list (UTF-8) + * @param dir Directory to list, or NULL for root (UTF-8) * @param re Regexp that results must match, or NULL (UTF-8) * @param vecp Where to store list (UTF-8) * @param nvecp Where to store number of items, or NULL diff --git a/lib/client.h b/lib/client.h index 3201081..4ce194f 100644 --- a/lib/client.h +++ b/lib/client.h @@ -36,6 +36,7 @@ struct sink; disorder_client *disorder_new(int verbose); int disorder_connect(disorder_client *c); +int disorder_connect_cookie(disorder_client *c, const char *cookie); int disorder_close(disorder_client *c); int disorder_become(disorder_client *c, const char *user); int disorder_version(disorder_client *c, char **versionp); diff --git a/lib/eclient.c b/lib/eclient.c index 012db98..0037fb5 100644 --- a/lib/eclient.c +++ b/lib/eclient.c @@ -114,7 +114,7 @@ struct operation { /** @brief Client structure */ struct disorder_eclient { - const char *ident; + char *ident; int fd; /**< @brief connection to server */ enum client_state state; /**< @brief current state */ int authenticated; /**< @brief true when authenicated */ @@ -150,15 +150,8 @@ struct disorder_eclient { /* Forward declarations ******************************************************/ -static int start_connect(void *cc, - const struct sockaddr *sa, - socklen_t len, - const char *ident); +static int start_connect(disorder_eclient *c); static void process_line(disorder_eclient *c, char *line); -static int start_connect(void *cc, - const struct sockaddr *sa, - socklen_t len, - const char *ident); static void maybe_connected(disorder_eclient *c); static void authbanner_opcallback(disorder_eclient *c, struct operation *op); @@ -341,7 +334,7 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { comms_error(c, "no password is configured"); return; } - with_sockaddr(c, start_connect); + start_connect(c); /* might now be state_disconnected (on error), state_connecting (slow * connect) or state_connected (fast connect). If state_disconnected then * we just rely on a periodic callback from the event loop sometime. */ @@ -467,14 +460,13 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) { } /** @brief Called to start connecting */ -static int start_connect(void *cc, - const struct sockaddr *sa, - socklen_t len, - const char *ident) { - disorder_eclient *c = cc; +static int start_connect(disorder_eclient *c) { + struct sockaddr *sa; + socklen_t len; D(("start_connect")); - c->ident = xstrdup(ident); + if((len = find_server(&sa, &c->ident)) == (socklen_t)-1) + return comms_error(c, "cannot look up server"); /* TODO better error */ if(c->fd != -1) { xclose(c->fd); c->fd = -1; @@ -494,7 +486,7 @@ static int start_connect(void *cc, return 0; default: /* Signal the error to the caller. */ - return comms_error(c, "connecting to %s: %s", ident, strerror(errno)); + return comms_error(c, "connecting to %s: %s", c->ident, strerror(errno)); } } else c->state = state_connected; diff --git a/server/server.c b/server/server.c index 54dfe55..4fc1690 100644 --- a/server/server.c +++ b/server/server.c @@ -1048,7 +1048,8 @@ static int c_cookie(struct conn *c, info("S%x %s connected with cookie from %s", c->tag, user, host); c->rights |= RIGHT__LOCAL; } - sink_writes(ev_writer_sink(c->w), "230 OK\n"); + /* Response contains username so client knows who they are acting as */ + sink_printf(ev_writer_sink(c->w), "232 %s\n", quoteutf8(user)); return 1; }