e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik/* gcc -Wall -fPIC -shared -o getsockopt_wrapper.so getsockopt_wrapper.c -ldl */
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik/* for RTLD_NEXT */
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#define _GNU_SOURCE 1
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#include <string.h>
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#include <stdbool.h>
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#include <sys/types.h>
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#include <sys/socket.h>
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#include <sys/un.h>
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#include <dlfcn.h>
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnikstatic bool is_dbus_socket(int fd)
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik{
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik int ret;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik struct sockaddr_storage addr = { 0 };
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik socklen_t addrlen = sizeof(addr);
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik struct sockaddr_un *unix_socket;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik ret = getsockname(fd, (struct sockaddr *)&addr, &addrlen);
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik if (ret != 0) return false;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik if (addr.ss_family != AF_UNIX) return false;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik unix_socket = (struct sockaddr_un *)&addr;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik return NULL != strstr(unix_socket->sun_path, "system_bus_socket");
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik}
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodniktypedef typeof(getsockopt) getsockopt_fn_t;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnikstatic getsockopt_fn_t *orig_getsockopt = NULL;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnikint getsockopt(int sockfd, int level, int optname,
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik void *optval, socklen_t *optlen)
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik{
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik int ret;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#ifdef __OpenBSD__
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik struct sockpeercred *cr;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#else
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik struct ucred *cr;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik#endif
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik if (orig_getsockopt == NULL) {
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik orig_getsockopt = (getsockopt_fn_t *)dlsym(RTLD_NEXT, "getsockopt");
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik }
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik ret = orig_getsockopt(sockfd, level, optname, optval, optlen);
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik if (ret == 0 && level == SOL_SOCKET && optname == SO_PEERCRED
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik && *optlen == sizeof(*cr)) {
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik cr = optval;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik if (cr->uid != 0 && is_dbus_socket(sockfd)) {
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik cr->uid = 0;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik }
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik }
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik return ret;
e64696e1fab85c42aaeda65ddf49ee1b7e3f07e1Lukas Slebodnik}