aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2008-10-15 22:34:21 +0200
committerMax Kellermann <max@duempel.org>2008-10-15 22:34:21 +0200
commit4a7ad5b618957f75da5b305a3d0cc8006e3e7416 (patch)
tree80947f009e0efe11e45b0e64ebb2b81cc5c16abe
parentfa56ff3d5250219d39d3cb077fd1e265fd6f92be (diff)
downloadmpd-4a7ad5b618957f75da5b305a3d0cc8006e3e7416.tar.gz
mpd-4a7ad5b618957f75da5b305a3d0cc8006e3e7416.tar.xz
mpd-4a7ad5b618957f75da5b305a3d0cc8006e3e7416.zip
listen, client: enable SO_PASSCRED, get client's uid
Enable authentication over unix sockets. Store the client's uid in the client struct.
Diffstat (limited to '')
-rw-r--r--src/client.c13
-rw-r--r--src/client.h8
-rw-r--r--src/listen.c23
3 files changed, 41 insertions, 3 deletions
diff --git a/src/client.c b/src/client.c
index 5b3b161b5..f3e2b32a4 100644
--- a/src/client.c
+++ b/src/client.c
@@ -72,8 +72,13 @@ struct client {
char buffer[CLIENT_MAX_BUFFER_LENGTH];
size_t bufferLength;
size_t bufferPos;
+
int fd; /* file descriptor; -1 if expired */
int permission;
+
+ /** the uid of the client process, or -1 if unknown */
+ int uid;
+
time_t lastTime;
struct strnode *cmd_list; /* for when in list mode */
struct strnode *cmd_list_tail; /* for when in list mode */
@@ -147,6 +152,11 @@ int client_is_expired(const struct client *client)
return client->fd < 0;
}
+int client_get_uid(const struct client *client)
+{
+ return client->uid;
+}
+
int client_get_permission(const struct client *client)
{
return client->permission;
@@ -323,7 +333,7 @@ sockaddr_to_tmp_string(const struct sockaddr *addr)
return hostname;
}
-void client_new(int fd, const struct sockaddr *addr)
+void client_new(int fd, const struct sockaddr *addr, int uid)
{
struct client *client;
@@ -337,6 +347,7 @@ void client_new(int fd, const struct sockaddr *addr)
list_add(&client->siblings, &clients);
++num_clients;
client_init(client, fd);
+ client->uid = uid;
SECURE("client %i: opened from %s\n", client->num,
sockaddr_to_tmp_string(addr));
}
diff --git a/src/client.h b/src/client.h
index 50238d9f0..58c2003de 100644
--- a/src/client.h
+++ b/src/client.h
@@ -33,10 +33,16 @@ void client_manager_deinit(void);
int client_manager_io(void);
void client_manager_expire(void);
-void client_new(int fd, const struct sockaddr *addr);
+void client_new(int fd, const struct sockaddr *addr, int uid);
int client_is_expired(const struct client *client);
+/**
+ * returns the uid of the client process, or a negative value if the
+ * uid is unknown
+ */
+int client_get_uid(const struct client *client);
+
int client_get_permission(const struct client *client);
void client_set_permission(struct client *client, int permission);
diff --git a/src/listen.c b/src/listen.c
index 063540428..1a52202ac 100644
--- a/src/listen.c
+++ b/src/listen.c
@@ -74,6 +74,7 @@ static int establishListen(int pf, const struct sockaddr *addrp,
{
int sock;
int allowReuse = ALLOW_REUSE;
+ int passcred = 1;
if ((sock = socket(pf, SOCK_STREAM, 0)) < 0)
FATAL("socket < 0\n");
@@ -96,6 +97,10 @@ static int establishListen(int pf, const struct sockaddr *addrp,
if (listen(sock, 5) < 0)
FATAL("problems listen'ing: %s\n", strerror(errno));
+#if defined(HAVE_UN) && defined(SO_PASSCRED)
+ setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred, sizeof(passcred));
+#endif
+
numberOfListenSockets++;
listenSockets =
xrealloc(listenSockets, sizeof(int) * numberOfListenSockets);
@@ -258,6 +263,22 @@ void freeAllListenSockets(void)
listenSockets = NULL;
}
+static int get_remote_uid(int fd)
+{
+#if defined(HAVE_UN) && defined(SO_PEERCRED)
+ struct ucred cred;
+ socklen_t len = sizeof (cred);
+
+ if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0)
+ return 0;
+
+ return cred.uid;
+#else
+ (void)fd;
+ return -1;
+#endif
+}
+
void getConnections(fd_set * fds)
{
int i;
@@ -269,7 +290,7 @@ void getConnections(fd_set * fds)
if (FD_ISSET(listenSockets[i], fds)) {
if ((fd = accept(listenSockets[i], &sockAddr, &socklen))
>= 0) {
- client_new(fd, &sockAddr);
+ client_new(fd, &sockAddr, get_remote_uid(fd));
} else if (fd < 0
&& (errno != EAGAIN && errno != EINTR)) {
ERROR("Problems accept()'ing\n");