mirror of
https://github.com/systemd/systemd.git
synced 2024-12-21 08:03:49 +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;
|
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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
_cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
|
_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;
|
sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
|
||||||
|
|
||||||
if (is_unix) {
|
if (is_unix) {
|
||||||
socklen_t l = sizeof(ucred);
|
getpeercred(in_fd, &ucred);
|
||||||
|
|
||||||
r = getsockopt(in_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
|
|
||||||
if (r < 0) {
|
|
||||||
r = -errno;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(l == sizeof(ucred));
|
|
||||||
|
|
||||||
getpeersec(in_fd, &peersec);
|
getpeersec(in_fd, &peersec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -671,10 +671,11 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
|
|||||||
|
|
||||||
case AF_UNIX: {
|
case AF_UNIX: {
|
||||||
struct ucred ucred;
|
struct ucred ucred;
|
||||||
|
int k;
|
||||||
|
|
||||||
l = sizeof(ucred);
|
k = getpeercred(fd, &ucred);
|
||||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
|
if (k < 0)
|
||||||
return -errno;
|
return k;
|
||||||
|
|
||||||
if (asprintf(&r,
|
if (asprintf(&r,
|
||||||
"%u-%lu-%lu",
|
"%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;
|
Server *s = userdata;
|
||||||
StdoutStream *stream;
|
StdoutStream *stream;
|
||||||
int fd, r;
|
int fd, r;
|
||||||
socklen_t len;
|
|
||||||
|
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
@ -386,8 +385,8 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
|
|||||||
|
|
||||||
stream->fd = fd;
|
stream->fd = fd;
|
||||||
|
|
||||||
len = sizeof(stream->ucred);
|
r = getpeercred(fd, &stream->ucred);
|
||||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &stream->ucred, &len) < 0) {
|
if (r < 0) {
|
||||||
log_error("Failed to determine peer credentials: %m");
|
log_error("Failed to determine peer credentials: %m");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
@ -625,14 +625,10 @@ void bus_socket_setup(sd_bus *b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void bus_get_peercred(sd_bus *b) {
|
static void bus_get_peercred(sd_bus *b) {
|
||||||
socklen_t l;
|
|
||||||
|
|
||||||
assert(b);
|
assert(b);
|
||||||
|
|
||||||
/* Get the peer for socketpair() sockets */
|
/* Get the peer for socketpair() sockets */
|
||||||
l = sizeof(b->ucred);
|
b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0;
|
||||||
if (getsockopt(b->input_fd, SOL_SOCKET, SO_PEERCRED, &b->ucred, &l) >= 0 && l >= sizeof(b->ucred))
|
|
||||||
b->ucred_valid = b->ucred.pid > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bus_socket_start_auth_client(sd_bus *b) {
|
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_free_ char *p = NULL, *tty = NULL;
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
struct ucred ucred;
|
struct ucred ucred;
|
||||||
socklen_t l;
|
|
||||||
int v, r;
|
int v, r;
|
||||||
|
|
||||||
assert(display);
|
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)
|
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
l = sizeof(ucred);
|
r = getpeercred(fd, &ucred);
|
||||||
r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
r = get_ctty(ucred.pid, NULL, &tty);
|
r = get_ctty(ucred.pid, NULL, &tty);
|
||||||
if (r < 0)
|
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) {
|
int getpeername_pretty(int fd, char **ret) {
|
||||||
union sockaddr_union sa;
|
union sockaddr_union sa;
|
||||||
socklen_t salen;
|
socklen_t salen;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
@ -593,9 +594,9 @@ int getpeername_pretty(int fd, char **ret) {
|
|||||||
/* UNIX connection sockets are anonymous, so let's use
|
/* UNIX connection sockets are anonymous, so let's use
|
||||||
* PID/UID as pretty credentials instead */
|
* PID/UID as pretty credentials instead */
|
||||||
|
|
||||||
salen = sizeof(ucred);
|
r = getpeercred(fd, &ucred);
|
||||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &salen) < 0)
|
if (r < 0)
|
||||||
return -errno;
|
return r;
|
||||||
|
|
||||||
if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.pid) < 0)
|
if (asprintf(ret, "PID %lu/UID %lu", (unsigned long) ucred.pid, (unsigned long) ucred.pid) < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -6117,3 +6117,61 @@ bool pid_valid(pid_t pid) {
|
|||||||
|
|
||||||
return errno != ESRCH;
|
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 <unistd.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "time-util.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);
|
int namespace_enter(int pidns_fd, int mntns_fd, int root_fd);
|
||||||
|
|
||||||
bool pid_valid(pid_t pid);
|
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 udev_ctrl_connection *conn;
|
||||||
struct ucred ucred;
|
struct ucred ucred;
|
||||||
socklen_t slen;
|
|
||||||
const int on = 1;
|
const int on = 1;
|
||||||
|
int r;
|
||||||
|
|
||||||
conn = calloc(1, sizeof(struct udev_ctrl_connection));
|
conn = new(struct udev_ctrl_connection, 1);
|
||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
conn->refcount = 1;
|
conn->refcount = 1;
|
||||||
@ -198,9 +198,9 @@ struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check peer credential of connection */
|
/* check peer credential of connection */
|
||||||
slen = sizeof(ucred);
|
r = getpeercred(conn->sock, &ucred);
|
||||||
if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
|
if (r < 0) {
|
||||||
log_error("unable to receive credentials of ctrl connection: %m\n");
|
log_error("unable to receive credentials of ctrl connection: %s", strerror(-r));
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
if (ucred.uid > 0) {
|
if (ucred.uid > 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user