diff options
author | Max Kellermann <max@duempel.org> | 2008-10-15 22:34:21 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2008-10-15 22:34:21 +0200 |
commit | 4a7ad5b618957f75da5b305a3d0cc8006e3e7416 (patch) | |
tree | 80947f009e0efe11e45b0e64ebb2b81cc5c16abe | |
parent | fa56ff3d5250219d39d3cb077fd1e265fd6f92be (diff) | |
download | mpd-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.
-rw-r--r-- | src/client.c | 13 | ||||
-rw-r--r-- | src/client.h | 8 | ||||
-rw-r--r-- | src/listen.c | 23 |
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"); |