diff options
Diffstat (limited to '')
-rw-r--r-- | libsbusd.c | 75 | ||||
-rw-r--r-- | libsbusd.h | 19 | ||||
-rw-r--r-- | sbusd.c | 67 |
3 files changed, 103 insertions, 58 deletions
@@ -41,6 +41,81 @@ libsbusd_weprintf(const char *fmt, ...) } int +libsbusd_who(int fd, char *buf, const char *prefix) +{ + struct ucred cred; + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &(socklen_t){sizeof(cred)}) < 0) { + weprintf("getsockopt <client> SOL_SOCKET SO_PEERCRED:"); + return -1; + } + return sprintf(buf, "%s!/cred/%lli/%lli/%lli", + prefix, + (long long int)cred.gid, + (long long int)cred.uid, + (long long int)cred.pid); +} + +int +libsbusd_iscredok(int fd, const char *key, const char *prefix) +{ + struct ucred cred; + long long int tmp; + const char *p; + size_t n = strlen(prefix); + if (strncmp(key, prefix, n)) + return 0; + key = &key[n]; + if (strncmp(key, "!/cred/", sizeof("!/cred/") - 1)) + return 0; + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &(socklen_t){sizeof(cred)}) < 0) { + weprintf("getsockopt <client> SOL_SOCKET SO_PEERCRED:"); + return -1; + } + errno = 0; + p = &key[sizeof("!/cred/") - 1]; +#define TEST_CRED(ID)\ + if (!*p) {\ + return 0;\ + } else if (*p++ != '/') {\ + if (!isdigit(*p))\ + return 0;\ + tmp = strtoll(p, (void *)&p, 10);\ + if (errno || (*p && *p != '/') || (ID##_t)tmp != cred.ID)\ + return 0;\ + } + TEST_CRED(gid); + TEST_CRED(uid); + TEST_CRED(pid); +#undef TEST_CRED + return 1; +} + +int +libsbusd_checkuser(int fd, uid_t *users, size_t nusers) +{ + struct ucred cred; + size_t i; + if (fd < 0) { + weprintf("accept <server>:"); + return -1; + } + if (nusers) { + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &(socklen_t){sizeof(cred)}) < 0) { + weprintf("getsockopt <client> SOL_SOCKET SO_PEERCRED:"); + close(fd); + return -1; + } + for (i = nusers; i--;) + if (users[i] == cred.uid) + return 0; + weprintf("rejected connection from user %li\n", (long int)cred.uid); + close(fd); + return -1; + } + return 0; +} + +int libsbusd_doessubmatch(const char *sub, const char *key) { const char *sub_start = sub; @@ -12,6 +12,22 @@ enum { LIBSBUS_AFUNIX_CONCRETE }; +#define DLLIST_ADD_BEFORE(NEW, OLD)\ + ((NEW)->next = (OLD),\ + (NEW)->prev = (OLD)->prev,\ + (OLD)->prev->next = (NEW),\ + (OLD)->prev = (NEW)) + +#define DLLIST_ADD_AFTER(NEW, OLD)\ + ((NEW)->next = (OLD)->next,\ + (NEW)->prev = (OLD),\ + (OLD)->next->prev = (NEW),\ + (OLD)->next = (NEW)) + +#define DLLIST_REMOVE(NODE)\ + ((NODE)->prev->next = (NODE)->next,\ + (NODE)->next->prev = (NODE)->prev) + #ifndef eprintf # define eprintf(...) (libsbusd_weprintf(__VA_ARGS__), exit(1)) #endif @@ -21,6 +37,9 @@ void libsbusd_weprintf(const char *, ...); # define weprintf libsbusd_weprintf #endif +int libsbusd_who(int, char *, const char *); +int libsbusd_iscredok(int, const char *, const char *); +int libsbusd_checkuser(int, uid_t *, size_t); int libsbusd_doessubmatch(const char *, const char *); int libsbusd_issubed(char *const *, size_t, const char *); void libsbusd_adduser(uid_t *, size_t *, const char *); @@ -84,10 +84,7 @@ add_client(int fd) cl->subs = NULL; cl->nsubs = 0; cl->subs_siz = 0; - cl->next = &tail; - cl->prev = tail.prev; - tail.prev->next = cl; - tail.prev = cl; + DLLIST_ADD_BEFORE(cl, &tail); return cl; } @@ -95,8 +92,7 @@ static void remove_client(struct client *cl) { close(cl->fd); - cl->prev->next = cl->next; - cl->next->prev = cl->prev; + DLLIST_REMOVE(cl); while (cl->nsubs--) free(cl->subs[cl->nsubs]); free(cl->subs); @@ -106,27 +102,9 @@ remove_client(struct client *cl) static void accept_client(int fd) { - struct ucred cred; struct epoll_event ev; - size_t i; - if (fd < 0) { - weprintf("accept <server>:"); + if (libsbusd_checkuser(fd, users, nusers)) return; - } - if (nusers) { - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &(socklen_t){sizeof(cred)}) < 0) { - weprintf("getsockopt <client> SOL_SOCKET SO_PEERCRED:"); - close(fd); - return; - } - for (i = nusers; i--;) - if (users[i] == cred.uid) - goto cred_ok; - weprintf("rejected connection from user %li\n", (long int)cred.uid); - close(fd); - return; - } -cred_ok: ev.events = EPOLLIN | EPOLLRDHUP; ev.data.ptr = add_client(fd); if (!ev.data.ptr) { @@ -142,31 +120,8 @@ cred_ok: static int is_subscription_acceptable(struct client *cl, const char *key) { - struct ucred cred; - long long int tmp; - const char *p; - if (!strncmp(key, "!/cred/", sizeof("!/cred/") - 1)) { - if (getsockopt(cl->fd, SOL_SOCKET, SO_PEERCRED, &cred, &(socklen_t){sizeof(cred)}) < 0) { - weprintf("getsockopt <client> SOL_SOCKET SO_PEERCRED:"); - return -1; - } - errno = 0; - p = &key[sizeof("!/cred/") - 1]; -#define TEST_CRED(ID)\ - if (!*p) {\ - return 0;\ - } else if (*p++ != '/') {\ - if (!isdigit(*p))\ - return 0;\ - tmp = strtoll(p, (void *)&p, 10);\ - if (errno || (*p && *p != '/') || (ID##_t)tmp != cred.ID)\ - return 0;\ - } - TEST_CRED(gid); - TEST_CRED(uid); - TEST_CRED(pid); -#undef TEST_CRED - } + if (!strncmp(key, "!/cred/", sizeof("!/cred/") - 1)) + return libsbusd_iscredok(cl->fd, key, ""); return 1; } @@ -237,18 +192,14 @@ send_packet(struct client *cl, const char *buf, size_t n) static void handle_cmsg(struct client *cl, char *buf, size_t n) { - struct ucred cred; + int r; if (!strcmp(buf, "CMSG !/cred/whoami")) { - if (getsockopt(cl->fd, SOL_SOCKET, SO_PEERCRED, &cred, &(socklen_t){sizeof(cred)}) < 0) { - weprintf("getsockopt <client> SOL_SOCKET SO_PEERCRED:"); + n = sizeof("CMSG !/cred/whoami"); + n += (size_t)(r = libsbusd_who(cl->fd, &buf[n], "")); + if (r < 0) { remove_client(cl); return; } - n = sizeof("CMSG !/cred/whoami"); - n += (size_t)sprintf(&buf[n], "!/cred/%lli/%lli/%lli", - (long long int)cred.gid, - (long long int)cred.uid, - (long long int)cred.pid); if (send_packet(cl, buf, n)) { weprintf("send <client>:"); remove_client(cl); |