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));
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;
}
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)))
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;
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
}
c->fpout = 0;
}
+ c->ident = 0;
+ c->user = 0;
return 0;
}
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)
/** @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
/** @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
/** @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