mirror of
https://github.com/systemd/systemd.git
synced 2024-12-20 23:53:38 +08:00
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.
This commit is contained in:
parent
96415cad2f
commit
eff0527098
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user