chiark / gitweb /
util: unify SO_PEERCRED/SO_PEERSEC invocations
authorLennart Poettering <lennart@poettering.net>
Tue, 24 Dec 2013 14:53:04 +0000 (15:53 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 24 Dec 2013 14:53:04 +0000 (15:53 +0100)
Introduce new call getpeercred() which internally just uses SO_PEERCRED
but checks if the returned data is actually useful due to namespace
quirks.

src/bus-proxyd/bus-proxyd.c
src/core/socket.c
src/journal/journald-stream.c
src/libsystemd-bus/bus-socket.c
src/login/pam-module.c
src/shared/socket-util.c
src/shared/util.c
src/shared/util.h
src/udev/udev-ctrl.c

index b87dffe..60490d5 100644 (file)
@@ -358,40 +358,6 @@ static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hell
         return 1;
 }
 
-static int getpeersec(int fd, char **ret) {
-        socklen_t n = 64;
-        char *s;
-        int r;
-
-        assert(fd >= 0);
-        assert(ret);
-
-        s = new0(char, n);
-        if (!s)
-                return -ENOMEM;
-
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
-        if (r < 0) {
-                free(s);
-
-                if (errno != ERANGE)
-                        return r;
-
-                s = new0(char, n);
-                if (!s)
-                        return -ENOMEM;
-
-                r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
-                if (r < 0) {
-                        free(s);
-                        return r;
-                }
-        }
-
-        *ret = s;
-        return 0;
-}
-
 int main(int argc, char *argv[]) {
 
         _cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
@@ -427,16 +393,7 @@ int main(int argc, char *argv[]) {
                 sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
 
         if (is_unix) {
-                socklen_t l = sizeof(ucred);
-
-                r = getsockopt(in_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
-                if (r < 0) {
-                        r = -errno;
-                        goto finish;
-                }
-
-                assert(l == sizeof(ucred));
-
+                getpeercred(in_fd, &ucred);
                 getpeersec(in_fd, &peersec);
         }
 
index 31fc2a2..88599ca 100644 (file)
@@ -671,10 +671,11 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
 
         case AF_UNIX: {
                 struct ucred ucred;
+                int k;
 
-                l = sizeof(ucred);
-                if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
-                        return -errno;
+                k = getpeercred(fd, &ucred);
+                if (k < 0)
+                        return k;
 
                 if (asprintf(&r,
                              "%u-%lu-%lu",
index aba9054..c032ee4 100644 (file)
@@ -354,7 +354,6 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
         Server *s = userdata;
         StdoutStream *stream;
         int fd, r;
-        socklen_t len;
 
         assert(s);
 
@@ -386,8 +385,8 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
 
         stream->fd = fd;
 
-        len = sizeof(stream->ucred);
-        if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
+        r = getpeercred(fd, &stream->ucred);
+        if (r < 0) {
                 log_error("Failed to determine peer credentials: %m");
                 goto fail;
         }
index 66924b2..0c4b6af 100644 (file)
@@ -625,14 +625,10 @@ void bus_socket_setup(sd_bus *b) {
 }
 
 static void bus_get_peercred(sd_bus *b) {
-        socklen_t l;
-
         assert(b);
 
         /* Get the peer for socketpair() sockets */
-        l = sizeof(b->ucred);
-        if (getsockopt(b->input_fd, SOL_SOCKET, SO_PEERCRED, &b->ucred, &l) >= 0 && l >= sizeof(b->ucred))
-                b->ucred_valid = b->ucred.pid > 0;
+        b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0;
 }
 
 static int bus_socket_start_auth_client(sd_bus *b) {
index 45428a0..89623aa 100644 (file)
@@ -120,7 +120,6 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
         _cleanup_free_ char *p = NULL, *tty = NULL;
         _cleanup_close_ int fd = -1;
         struct ucred ucred;
-        socklen_t l;
         int v, r;
 
         assert(display);
@@ -144,10 +143,9 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
         if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
                 return -errno;
 
-        l = sizeof(ucred);
-        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
+        r = getpeercred(fd, &ucred);
         if (r < 0)
-                return -errno;
+                return r;
 
         r = get_ctty(ucred.pid, NULL, &tty);
         if (r < 0)
index 75c47d1..45ada7e 100644 (file)
@@ -579,6 +579,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_
 int getpeername_pretty(int fd, char **ret) {
         union sockaddr_union sa;
         socklen_t salen;
+        int r;
 
         assert(fd >= 0);
         assert(ret);
@@ -593,9 +594,9 @@ int getpeername_pretty(int fd, char **ret) {
                 /* UNIX connection sockets are anonymous, so let's use
                  * PID/UID as pretty credentials instead */
 
-                salen = sizeof(ucred);
-                if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &salen) < 0)
-                        return -errno;
+                r = getpeercred(fd, &ucred);
+                if (r < 0)
+                        return r;
 
                 if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.pid) < 0)
                         return -ENOMEM;
index 8d7cf53..6b6722c 100644 (file)
@@ -6117,3 +6117,61 @@ bool pid_valid(pid_t pid) {
 
         return errno != ESRCH;
 }
+
+int getpeercred(int fd, struct ucred *ucred) {
+        socklen_t n = sizeof(struct ucred);
+        struct ucred u;
+        int r;
+
+        assert(fd >= 0);
+        assert(ucred);
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
+        if (r < 0)
+                return -errno;
+
+        if (n != sizeof(struct ucred))
+                return -EIO;
+
+        /* Check if the data is actually useful and not suppressed due
+         * to namespacing issues */
+        if (u.pid <= 0)
+                return -ENODATA;
+
+        *ucred = u;
+        return 0;
+}
+
+int getpeersec(int fd, char **ret) {
+        socklen_t n = 64;
+        char *s;
+        int r;
+
+        assert(fd >= 0);
+        assert(ret);
+
+        s = new0(char, n);
+        if (!s)
+                return -ENOMEM;
+
+        r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+        if (r < 0) {
+                free(s);
+
+                if (errno != ERANGE)
+                        return -errno;
+
+                s = new0(char, n);
+                if (!s)
+                        return -ENOMEM;
+
+                r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+                if (r < 0) {
+                        free(s);
+                        return -errno;
+                }
+        }
+
+        *ret = s;
+        return 0;
+}
index 338d79c..57667ef 100644 (file)
@@ -40,6 +40,7 @@
 #include <unistd.h>
 #include <locale.h>
 #include <mntent.h>
+#include <sys/socket.h>
 
 #include "macro.h"
 #include "time-util.h"
@@ -811,3 +812,6 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *root_fd);
 int namespace_enter(int pidns_fd, int mntns_fd, int root_fd);
 
 bool pid_valid(pid_t pid);
+
+int getpeercred(int fd, struct ucred *ucred);
+int getpeersec(int fd, char **ret);
index 4bb0cea..39d777e 100644 (file)
@@ -181,10 +181,10 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
 {
         struct udev_ctrl_connection *conn;
         struct ucred ucred;
-        socklen_t slen;
         const int on = 1;
+        int r;
 
-        conn = calloc(1, sizeof(struct udev_ctrl_connection));
+        conn = new(struct udev_ctrl_connection, 1);
         if (conn == NULL)
                 return NULL;
         conn->refcount = 1;
@@ -198,9 +198,9 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
         }
 
         /* check peer credential of connection */
-        slen = sizeof(ucred);
-        if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
-                log_error("unable to receive credentials of ctrl connection: %m\n");
+        r = getpeercred(conn->sock, &ucred);
+        if (r < 0) {
+                log_error("unable to receive credentials of ctrl connection: %s", strerror(-r));
                 goto err;
         }
         if (ucred.uid > 0) {