summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-12-24 15:53:04 +0100
committerLennart Poettering <lennart@poettering.net>2013-12-24 15:53:04 +0100
commiteff05270986a13e7de93ae16311f654d3f7c166f (patch)
treec5c7d7c456f8a8b9d3e75cb9e36b5974215003ed
parent96415cad2fdd8d280ae94b02651b5f826a2f7f3d (diff)
util: unify SO_PEERCRED/SO_PEERSEC invocations
Introduce new call getpeercred() which internally just uses SO_PEERCRED but checks if the returned data is actually useful due to namespace quirks.
-rw-r--r--src/bus-proxyd/bus-proxyd.c45
-rw-r--r--src/core/socket.c7
-rw-r--r--src/journal/journald-stream.c5
-rw-r--r--src/libsystemd-bus/bus-socket.c6
-rw-r--r--src/login/pam-module.c6
-rw-r--r--src/shared/socket-util.c7
-rw-r--r--src/shared/util.c58
-rw-r--r--src/shared/util.h4
-rw-r--r--src/udev/udev-ctrl.c10
9 files changed, 81 insertions, 67 deletions
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index b87dffe0e..60490d516 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -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);
}
diff --git a/src/core/socket.c b/src/core/socket.c
index 31fc2a252..88599ca9c 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -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",
diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c
index aba9054b2..c032ee4a0 100644
--- a/src/journal/journald-stream.c
+++ b/src/journal/journald-stream.c
@@ -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;
}
diff --git a/src/libsystemd-bus/bus-socket.c b/src/libsystemd-bus/bus-socket.c
index 66924b29f..0c4b6af44 100644
--- a/src/libsystemd-bus/bus-socket.c
+++ b/src/libsystemd-bus/bus-socket.c
@@ -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) {
diff --git a/src/login/pam-module.c b/src/login/pam-module.c
index 45428a090..89623aa76 100644
--- a/src/login/pam-module.c
+++ b/src/login/pam-module.c
@@ -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)
diff --git a/src/shared/socket-util.c b/src/shared/socket-util.c
index 75c47d1f7..45ada7eb3 100644
--- a/src/shared/socket-util.c
+++ b/src/shared/socket-util.c
@@ -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;
diff --git a/src/shared/util.c b/src/shared/util.c
index 8d7cf5398..6b6722c27 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -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;
+}
diff --git a/src/shared/util.h b/src/shared/util.h
index 338d79c7a..57667ef89 100644
--- a/src/shared/util.h
+++ b/src/shared/util.h
@@ -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);
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 4bb0ceafe..39d777ec7 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -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) {