From: Michal Nazarewicz <min...@mina86.com> Instead of storing password in MPD_HOST environment variable (which is passed around everywhere) allow saving password in an ~/.authinfo file. This is especially useful if MPD is listening on default host:port, i.e. localhost:6600, in which case all one needs to do is to put line like machine localhost port 6600 password some-password to make MPD clients use “some-password” when connecting to it. --- src/fd_util.c | 23 +++++++++++++ src/fd_util.h | 8 +++++ src/settings.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+)
diff --git a/src/fd_util.c b/src/fd_util.c index 09373e3..3a21ce5 100644 --- a/src/fd_util.c +++ b/src/fd_util.c @@ -38,6 +38,8 @@ #include <stdbool.h> #include <fcntl.h> #include <errno.h> +#include <sys/stat.h> +#include <sys/types.h> #ifdef WIN32 #include <winsock2.h> @@ -117,3 +119,24 @@ socket_cloexec_nonblock(int domain, int type, int protocol) return fd; } + +FILE * +mpd_fopen(const char *path) +{ + int fd = -1; + +#ifdef O_CLOEXEC + fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0 && errno != EINVAL) + return NULL; +#endif + + if (fd < 0) { + fd = open(path, O_RDONLY); + if (fd == -1) + return NULL; + fd_set_cloexec(fd, true); + } + + return fdopen(fd, "r"); +} diff --git a/src/fd_util.h b/src/fd_util.h index f0c13c9..858896d 100644 --- a/src/fd_util.h +++ b/src/fd_util.h @@ -36,6 +36,8 @@ #ifndef FD_UTIL_H #define FD_UTIL_H +#include <stdio.h> + /** * Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag * (atomically if supported by the OS). @@ -43,4 +45,10 @@ int socket_cloexec_nonblock(int domain, int type, int protocol); +/** + * Opens FILE for reading (mode="r") setting O_CLOEXEC flag. + */ +FILE * +mpd_fopen(const char *path); + #endif diff --git a/src/settings.c b/src/settings.c index d8e9247..4721f3b 100644 --- a/src/settings.c +++ b/src/settings.c @@ -35,6 +35,7 @@ #include <netdb.h> #include <string.h> #include <stdlib.h> +#include <stdio.h> struct mpd_settings { char *host; @@ -133,6 +134,100 @@ mpd_check_port(unsigned port) return port; } +static char * +mpd_parse_authinfo_line(const char *host, unsigned port, char *line) +{ + /* If port is zero (e.g. if socket is used), allow authinfo lines w/o + * a port. */ + bool got_host = false, got_port = !port; + char *pwd = NULL, *saveptr, *kw, *val; + + while ((kw = strtok_r(line, " \t\n", &saveptr))) { + val = strtok_r(NULL, " \t\n", &saveptr); + /* Ignore line if there's a keyword w/o value. */ + if (!val) + return NULL; + line = NULL; + + if (!strcmp(kw, "machine")) { + /* Ignore line if hosts differ. */ + if (strcmp(val, host)) + return NULL; + got_host = true; + + } else if (!strcmp(kw, "port")) { + /* Ignore line if ports differ. */ + if (!port || mpd_parse_port(val) != port) + return NULL; + got_port = true; + + } else if (!strcmp(kw, "password")) { + pwd = val; + + } else { + /* Unknown keyword present, ignore line. */ + return NULL; + } + } + + return got_host && got_port ? pwd : NULL; +} + +static char * +mpd_parse_authinfo(const char *host, unsigned port, FILE *fd) +{ + char line[1024], *pwd = NULL; + + do { + if (!fgets(line, sizeof line, fd)) { + return NULL; + } + + if (!strchr(line, '\n')) { + /* Discard partial lines. TODO: handle lines of + * arbitrary length */ + while (fgets(line, sizeof line, fd) && + !strchr(line, '\n')) { } + } else { + pwd = mpd_parse_authinfo_line(host, port, line); + } + } while (!pwd); + + return strdup(pwd); +} + +static char * +mpd_read_authinfo_password(const char *host, unsigned port) +{ + static const char *const filenames[] = { + /* Code assumes the first entry is the longest. */ + ".authinfo", ".netrc" + }; + + char *str = getenv("HOME"); + if (!str) { + return NULL; + } + + size_t i = strlen(str); + char *path = malloc(i + strlen(filenames[0]) + 2); + memcpy(path, str, i); + path[i] = '/'; + str = path + i + 1; + + char *pwd = NULL; + for (i = 0; !pwd && i < sizeof filenames / sizeof *filenames; ++i) { + strcpy(str, filenames[i]); + FILE *fd = mpd_fopen(path); + if (fd) { + pwd = mpd_parse_authinfo(host, port, fd); + fclose(fd); + } + } + free(path); + return pwd; +} + static unsigned mpd_default_timeout_ms(void) { @@ -186,6 +281,11 @@ mpd_settings_new(const char *host, unsigned port, unsigned timeout_ms, ? 0 /* no port for local socket */ : (port != 0 ? port : DEFAULT_PORT); + if (settings->host && !settings->password) { + settings->password = mpd_read_authinfo_password( + settings->host, settings->port); + } + return settings; } -- 2.2.0.rc0.207.ga3a616c _______________________________________________ mpd-devel mailing list mpd-devel@musicpd.org http://mailman.blarg.de/listinfo/mpd-devel