X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-socket.c;h=82e683a9578724bd9acd2e5f459afb804ea01734;hp=cb1e942833b5b44e863ce5ddf0cbe5b29d9a505e;hb=2b4ac8896bdc6cc5159088d7d208559d53caacf3;hpb=2181a7f558eb52a22f09f8add9ac0abb4f2ee016 diff --git a/src/libsystemd-bus/bus-socket.c b/src/libsystemd-bus/bus-socket.c index cb1e94283..82e683a95 100644 --- a/src/libsystemd-bus/bus-socket.c +++ b/src/libsystemd-bus/bus-socket.c @@ -31,6 +31,7 @@ #include "missing.h" #include "strv.h" #include "utf8.h" +#include "sd-daemon.h" #include "sd-bus.h" #include "bus-socket.h" @@ -75,7 +76,6 @@ bool bus_socket_auth_needs_write(sd_bus *b) { } static int bus_socket_write_auth(sd_bus *b) { - struct msghdr mh; ssize_t k; assert(b); @@ -84,16 +84,26 @@ static int bus_socket_write_auth(sd_bus *b) { if (!bus_socket_auth_needs_write(b)) return 0; - zero(mh); - mh.msg_iov = b->auth_iovec + b->auth_index; - mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index; + if (b->prefer_writev) + k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index); + else { + struct msghdr mh; + zero(mh); + + mh.msg_iov = b->auth_iovec + b->auth_index; + mh.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index; + + k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); + if (k < 0 && errno == ENOTSOCK) { + b->prefer_writev = true; + k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index); + } + } - k = sendmsg(b->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); if (k < 0) return errno == EAGAIN ? 0 : -errno; iovec_advance(b->auth_iovec, &b->auth_index, (size_t) k); - return 1; } @@ -146,11 +156,11 @@ static int bus_socket_auth_verify_client(sd_bus *b) { peer.bytes[i/2] = ((uint8_t) x << 4 | (uint8_t) y); } - if (!sd_id128_equal(b->peer, SD_ID128_NULL) && - !sd_id128_equal(b->peer, peer)) + if (!sd_id128_equal(b->server_id, SD_ID128_NULL) && + !sd_id128_equal(b->server_id, peer)) return -EPERM; - b->peer = peer; + b->server_id = peer; /* And possibly check the second line, too */ @@ -225,7 +235,7 @@ static int verify_external_token(sd_bus *b, const char *p, size_t l) { * the owner of this bus wanted authentication he should have * checked SO_PEERCRED before even creating the bus object. */ - if (!b->ucred_valid) + if (!b->anonymous_auth && !b->ucred_valid) return 0; if (l <= 0) @@ -248,7 +258,9 @@ static int verify_external_token(sd_bus *b, const char *p, size_t l) { if (r < 0) return 0; - if (u != b->ucred.uid) + /* We ignore the passed value if anonymous authentication is + * on anyway. */ + if (!b->anonymous_auth && u != b->ucred.uid) return 0; return 1; @@ -286,7 +298,7 @@ static int bus_socket_auth_write_ok(sd_bus *b) { assert(b); - snprintf(t, sizeof(t), "OK " SD_ID128_FORMAT_STR "\r\n", SD_ID128_FORMAT_VAL(b->peer)); + snprintf(t, sizeof(t), "OK " SD_ID128_FORMAT_STR "\r\n", SD_ID128_FORMAT_VAL(b->server_id)); char_array_0(t); return bus_socket_auth_write(b, t); @@ -301,13 +313,16 @@ static int bus_socket_auth_verify_server(sd_bus *b) { assert(b); - if (b->rbuffer_size < 3) + if (b->rbuffer_size < 1) return 0; /* First char must be a NUL byte */ if (*(char*) b->rbuffer != 0) return -EIO; + if (b->rbuffer_size < 3) + return 0; + /* Begin with the first line */ if (b->auth_rbegin <= 0) b->auth_rbegin = 1; @@ -431,6 +446,7 @@ static int bus_socket_read_auth(sd_bus *b) { CMSG_SPACE(NAME_MAX)]; /*selinux label */ } control; struct cmsghdr *cmsg; + bool handle_cmsg = false; assert(b); assert(b->state == BUS_AUTHENTICATING); @@ -457,13 +473,22 @@ static int bus_socket_read_auth(sd_bus *b) { iov.iov_base = (uint8_t*) b->rbuffer + b->rbuffer_size; iov.iov_len = n - b->rbuffer_size; - zero(mh); - mh.msg_iov = &iov; - mh.msg_iovlen = 1; - mh.msg_control = &control; - mh.msg_controllen = sizeof(control); - - k = recvmsg(b->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (b->prefer_readv) + k = readv(b->input_fd, &iov, 1); + else { + zero(mh); + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + k = recvmsg(b->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (k < 0 && errno == ENOTSOCK) { + b->prefer_readv = true; + k = readv(b->input_fd, &iov, 1); + } else + handle_cmsg = true; + } if (k < 0) return errno == EAGAIN ? 0 : -errno; if (k == 0) @@ -471,32 +496,34 @@ static int bus_socket_read_auth(sd_bus *b) { b->rbuffer_size += k; - for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - int j; - - /* Whut? We received fds during the auth - * protocol? Somebody is playing games with - * us. Close them all, and fail */ - j = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - close_many((int*) CMSG_DATA(cmsg), j); - return -EIO; + if (handle_cmsg) { + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int j; + + /* Whut? We received fds during the auth + * protocol? Somebody is playing games with + * us. Close them all, and fail */ + j = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + close_many((int*) CMSG_DATA(cmsg), j); + return -EIO; - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_CREDENTIALS && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { - memcpy(&b->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); - b->ucred_valid = true; + memcpy(&b->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); + b->ucred_valid = true; - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_SECURITY) { + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_SECURITY) { - size_t l; - l = cmsg->cmsg_len - CMSG_LEN(0); - memcpy(&b->label, CMSG_DATA(cmsg), l); - b->label[l] = 0; + size_t l; + l = cmsg->cmsg_len - CMSG_LEN(0); + memcpy(&b->label, CMSG_DATA(cmsg), l); + b->label[l] = 0; + } } } @@ -515,12 +542,12 @@ static int bus_socket_setup(sd_bus *b) { /* Enable SO_PASSCRED + SO_PASSEC. We try this on any * socket, just in case. */ enable = !b->bus_client; - setsockopt(b->fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)); - setsockopt(b->fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable)); + setsockopt(b->input_fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)); + setsockopt(b->input_fd, SOL_SOCKET, SO_PASSSEC, &enable, sizeof(enable)); /* Increase the buffers to a MB */ - fd_inc_rcvbuf(b->fd, 1024*1024); - fd_inc_sndbuf(b->fd, 1024*1024); + fd_inc_rcvbuf(b->input_fd, 1024*1024); + fd_inc_sndbuf(b->output_fd, 1024*1024); return 0; } @@ -568,22 +595,18 @@ static int bus_socket_start_auth_client(sd_bus *b) { } static int bus_socket_start_auth(sd_bus *b) { - int domain = 0, r; - socklen_t sl; - assert(b); b->state = BUS_AUTHENTICATING; b->auth_timeout = now(CLOCK_MONOTONIC) + BUS_DEFAULT_TIMEOUT; - sl = sizeof(domain); - r = getsockopt(b->fd, SOL_SOCKET, SO_DOMAIN, &domain, &sl); - if (r < 0) - return -errno; - - if (domain != AF_UNIX) + if (sd_is_socket(b->input_fd, AF_UNIX, 0, 0) <= 0) b->negotiate_fds = false; + if (b->output_fd != b->input_fd) + if (sd_is_socket(b->output_fd, AF_UNIX, 0, 0) <= 0) + b->negotiate_fds = false; + if (b->is_server) return bus_socket_read_auth(b); else @@ -594,18 +617,21 @@ int bus_socket_connect(sd_bus *b) { int r; assert(b); - assert(b->fd < 0); + assert(b->input_fd < 0); + assert(b->output_fd < 0); assert(b->sockaddr.sa.sa_family != AF_UNSPEC); - b->fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); - if (b->fd < 0) + b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (b->input_fd < 0) return -errno; + b->output_fd = b->input_fd; + r = bus_socket_setup(b); if (r < 0) return r; - r = connect(b->fd, &b->sockaddr.sa, b->sockaddr_size); + r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); if (r < 0) { if (errno == EINPROGRESS) return 1; @@ -617,15 +643,16 @@ int bus_socket_connect(sd_bus *b) { } int bus_socket_exec(sd_bus *b) { - int s[2]; + int s[2], r; pid_t pid; assert(b); - assert(b->fd < 0); + assert(b->input_fd < 0); + assert(b->output_fd < 0); assert(b->exec_path); - b->fd = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s); - if (b->fd < 0) + r = socketpair(AF_UNIX, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, s); + if (r < 0) return -errno; pid = fork(); @@ -636,8 +663,9 @@ int bus_socket_exec(sd_bus *b) { if (pid == 0) { /* Child */ - close_all_fds(s, 2); - close_nointr_nofail(s[0]); + reset_all_signal_handlers(); + + close_all_fds(s+1, 1); assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO); assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO); @@ -661,7 +689,7 @@ int bus_socket_exec(sd_bus *b) { } close_nointr_nofail(s[1]); - b->fd = s[0]; + b->output_fd = b->input_fd = s[0]; return bus_socket_start_auth(b); } @@ -678,7 +706,6 @@ int bus_socket_take_fd(sd_bus *b) { } int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { - struct msghdr mh; struct iovec *iov; ssize_t k; size_t n; @@ -691,18 +718,6 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { if (*idx >= m->size) return 0; - zero(mh); - - if (m->n_fds > 0) { - struct cmsghdr *control; - control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds)); - - mh.msg_control = control; - control->cmsg_level = SOL_SOCKET; - control->cmsg_type = SCM_RIGHTS; - mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds); - memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds); - } n = m->n_iovec * sizeof(struct iovec); iov = alloca(n); @@ -711,10 +726,33 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) { j = 0; iovec_advance(iov, &j, *idx); - mh.msg_iov = iov; - mh.msg_iovlen = m->n_iovec; + if (bus->prefer_writev) + k = writev(bus->output_fd, iov, m->n_iovec); + else { + struct msghdr mh; + zero(mh); + + if (m->n_fds > 0) { + struct cmsghdr *control; + control = alloca(CMSG_SPACE(sizeof(int) * m->n_fds)); + + mh.msg_control = control; + control->cmsg_level = SOL_SOCKET; + control->cmsg_type = SCM_RIGHTS; + mh.msg_controllen = control->cmsg_len = CMSG_LEN(sizeof(int) * m->n_fds); + memcpy(CMSG_DATA(control), m->fds, sizeof(int) * m->n_fds); + } + + mh.msg_iov = iov; + mh.msg_iovlen = m->n_iovec; + + k = sendmsg(bus->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); + if (k < 0 && errno == ENOTSOCK) { + bus->prefer_writev = true; + k = writev(bus->output_fd, iov, m->n_iovec); + } + } - k = sendmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL); if (k < 0) return errno == EAGAIN ? 0 : -errno; @@ -826,6 +864,7 @@ int bus_socket_read_message(sd_bus *bus, sd_bus_message **m) { CMSG_SPACE(NAME_MAX)]; /*selinux label */ } control; struct cmsghdr *cmsg; + bool handle_cmsg; assert(bus); assert(m); @@ -848,13 +887,22 @@ int bus_socket_read_message(sd_bus *bus, sd_bus_message **m) { iov.iov_base = (uint8_t*) bus->rbuffer + bus->rbuffer_size; iov.iov_len = need - bus->rbuffer_size; - zero(mh); - mh.msg_iov = &iov; - mh.msg_iovlen = 1; - mh.msg_control = &control; - mh.msg_controllen = sizeof(control); - - k = recvmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (bus->prefer_readv) + k = readv(bus->input_fd, &iov, 1); + else { + zero(mh); + mh.msg_iov = &iov; + mh.msg_iovlen = 1; + mh.msg_control = &control; + mh.msg_controllen = sizeof(control); + + k = recvmsg(bus->input_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (k < 0 && errno == ENOTSOCK) { + bus->prefer_readv = true; + k = readv(bus->input_fd, &iov, 1); + } else + handle_cmsg = true; + } if (k < 0) return errno == EAGAIN ? 0 : -errno; if (k == 0) @@ -862,45 +910,47 @@ int bus_socket_read_message(sd_bus *bus, sd_bus_message **m) { bus->rbuffer_size += k; - for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS) { - int n, *f; - - n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - - if (!bus->can_fds) { - /* Whut? We received fds but this - * isn't actually enabled? Close them, - * and fail */ - - close_many((int*) CMSG_DATA(cmsg), n); - return -EIO; + if (handle_cmsg) { + for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + int n, *f; + + n = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + + if (!bus->can_fds) { + /* Whut? We received fds but this + * isn't actually enabled? Close them, + * and fail */ + + close_many((int*) CMSG_DATA(cmsg), n); + return -EIO; + } + + f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n)); + if (!f) { + close_many((int*) CMSG_DATA(cmsg), n); + return -ENOMEM; + } + + memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); + bus->fds = f; + bus->n_fds += n; + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + + memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); + bus->ucred_valid = true; + + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_SECURITY) { + + size_t l; + l = cmsg->cmsg_len - CMSG_LEN(0); + memcpy(&bus->label, CMSG_DATA(cmsg), l); + bus->label[l] = 0; } - - f = realloc(bus->fds, sizeof(int) + (bus->n_fds + n)); - if (!f) { - close_many((int*) CMSG_DATA(cmsg), n); - return -ENOMEM; - } - - memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int)); - bus->fds = f; - bus->n_fds += n; - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_CREDENTIALS && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { - - memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred)); - bus->ucred_valid = true; - - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_SECURITY) { - - size_t l; - l = cmsg->cmsg_len - CMSG_LEN(0); - memcpy(&bus->label, CMSG_DATA(cmsg), l); - bus->label[l] = 0; } } @@ -924,7 +974,7 @@ int bus_socket_process_opening(sd_bus *b) { assert(b->state == BUS_OPENING); zero(p); - p.fd = b->fd; + p.fd = b->output_fd; p.events = POLLOUT; r = poll(&p, 1, 0); @@ -934,7 +984,7 @@ int bus_socket_process_opening(sd_bus *b) { if (!(p.revents & (POLLOUT|POLLERR|POLLHUP))) return 0; - r = getsockopt(b->fd, SOL_SOCKET, SO_ERROR, &error, &slen); + r = getsockopt(b->output_fd, SOL_SOCKET, SO_ERROR, &error, &slen); if (r < 0) b->last_connect_error = errno; else if (error != 0)