From: Michal Nazarewicz <[email protected]>
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
[email protected]
http://mailman.blarg.de/listinfo/mpd-devel