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

Reply via email to