From 3145df792e44939c34b506b015e12a4c5235c9fa Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Mon, 6 Nov 2017 23:43:22 +0100 Subject: Fix two errors and move reuseable code from sbusd to libsbusd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 3 +- libsbusd.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ libsbusd.h | 32 ++++++ sbusd.c | 309 ++----------------------------------------------------- 4 files changed, 385 insertions(+), 301 deletions(-) create mode 100644 libsbusd.c create mode 100644 libsbusd.h diff --git a/Makefile b/Makefile index 5c112a2..4998caf 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,11 @@ include $(CONFIGFILE) all: sbusd libsbus.so libsbus.a test -sbusd.o: arg.h +sbusd.o: arg.h libsbusd.h libsbus.o: libsbus.h test.o: libsbus.h test: test.o libsbus.a +sbusd: sbusd.o libsbusd.o libsbus.so: libsbus.o $(CC) -shared -Wl,-soname,libsbus.so.$(LIB_MAJOR) -o $@ $^ $(LDFLAGS) diff --git a/libsbusd.c b/libsbusd.c new file mode 100644 index 0000000..7c0596e --- /dev/null +++ b/libsbusd.c @@ -0,0 +1,342 @@ +/* See LICENSE file for copyright and license details. */ +#include "libsbusd.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define STYPE_MAX(T) (long long int)((1ULL << (8 * sizeof(T) - 1)) - 1) + + +extern char *argv0; + + +void +libsbusd_weprintf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "%s: ", argv0); + vfprintf(stderr, fmt, args); + if (strchr(fmt, '\0')[-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } + va_end(args); +} + +int +libsbusd_doessubmatch(const char *sub, const char *key) +{ + const char *sub_start = sub; + for (;;) { + while (*sub && *sub == *key) { + sub++; + key++; + } + if (!*key) + return !*sub; + if (!*sub) + return sub == sub_start || sub[-1] == '/'; + if (*sub == '*') { + sub++; + while (*key && *key != '/') + key++; + continue; + } + return 0; + } +} + +int +libsbusd_issubed(char *const *subs, size_t nsubs, const char *key) +{ + while (nsubs--) + if (libsbusd_doessubmatch(subs[nsubs], key)) + return 1; + return 0; +} + +void +libsbusd_adduser(uid_t *users, size_t *nusers, const char *arg) +{ + struct passwd *user; + long long int tmp; + if (!isdigit(*arg)) + goto user_by_name; + errno = 0; + tmp = strtoll(arg, (void *)&arg, 10); + if (errno || *arg || tmp < 0 || tmp > STYPE_MAX(uid_t)) + goto user_by_name; + users[(*nusers)++] = (uid_t)tmp; + return; +user_by_name: + user = getpwnam(arg); + if (!user) + eprintf("getpwnam %s:", arg); + users[(*nusers)++] = user->pw_uid; +} + +static void +randomise(void *buf, size_t n) +{ + char *p = buf; + while (n--) + *p++ = rand(); +} + +static void +print_address(struct sockaddr_un *addr) +{ + char buf[2 * sizeof(addr->sun_path) + 1]; + char *p = buf; + const unsigned char *a = (const unsigned char *)addr->sun_path; + size_t n = sizeof(addr->sun_path); + + for (; n--; p += 2, a += 1) { + p[0] = "0123456789abcdef"[(int)*a >> 4]; + p[1] = "0123456789abcdef"[(int)*a & 15]; + } + *p = '\0'; + + printf("/dev/unix/abstract/%s\n", buf); + if (fflush(stdout) || ferror(stdout)) + eprintf("failed print generated address:"); +} + +int +libsbusd_afunix(struct sockaddr_un *addr, int *fdp, const char *address) +{ + const char *p, *q; + long int tmp; + int hi, lo; + size_t n; + char *a; + + memset(addr, 0, sizeof(*addr)); + addr->sun_family = AF_UNIX; + + if (strstr(address, "/dev/fd/") == address) { + p = &address[sizeof("/dev/fd/") - 1]; + if (!isdigit(*p)) + goto def; + errno = 0; + tmp = strtol(p, &a, 10); + if (errno || *a || tmp < 0) { + errno = 0; + goto def; + } + if (tmp > INT_MAX) { + errno = EBADF; + return -1; + } + *fdp = (int)tmp; + return LIBSBUS_AFUNIX_FD; + } else if (!strcmp(address, "/dev/unix/abstract")) { + return LIBSBUS_AFUNIX_RANDOM; + } else if (strstr(address, "/dev/unix/abstract/") == address) { + p = &address[sizeof("/dev/unix/abstract/") - 1]; + n = strlen(p); + if (n & 1) + goto def; + for (q = p; *q; q++) + if (!isxdigit(*q)) + goto def; + if (n > sizeof(addr->sun_path) * 2) { + errno = ENAMETOOLONG; + return -1; + } + a = addr->sun_path; + for (; *p; p += 2) { + hi = (p[0] & 15) + 9 * !isdigit(p[0]); + lo = (p[1] & 15) + 9 * !isdigit(p[1]); + *a++ = (hi << 4) | lo; + } + return LIBSBUS_AFUNIX_ABSTRACT; + } else { + def: + if (strlen(address) >= sizeof(addr->sun_path)) { + errno = ENAMETOOLONG; + return -1; + } + strcpy(addr->sun_path, address); + return LIBSBUS_AFUNIX_CONCRETE; + } +} + +int +libsbusd_mksocket(struct sockaddr_un *addr, const char *address, int reuse, mode_t mode) +{ + int fd, randaddr = 0, listening = 0; + + switch (libsbusd_afunix(addr, &fd, address)) { + case LIBSBUS_AFUNIX_FD: + reuse = 0; + break; + case LIBSBUS_AFUNIX_RANDOM: + randaddr = 1; + reuse = 0; + fd = -1; + break; + case LIBSBUS_AFUNIX_ABSTRACT: + reuse = 0; + fd = -1; + break; + case LIBSBUS_AFUNIX_CONCRETE: + fd = -1; + break; + default: + eprintf("bad unix socket address:"); + exit(1); + } + + if (reuse) + unlink(addr->sun_path); + + if (fd < 0) { + fd = socket(PF_UNIX, SOCK_SEQPACKET, 0); + if (fd < 0) + eprintf("socket PF_UNIX SOCK_SEQPACKET:"); + if (fchmod(fd, mode)) + eprintf("fchmod %o:", mode); + if (randaddr) { + srand((unsigned)time(NULL)); + for (;;) { + randomise(&addr->sun_path[1], sizeof(addr->sun_path) - 1); + if (!bind(fd, (void *)addr, sizeof(*addr))) + break; + else if (errno != EADDRINUSE) + eprintf("bind :"); + } + print_address(addr); + } else { + if (bind(fd, (void *)addr, sizeof(*addr))) { + if (*addr->sun_path) + eprintf("bind %s:", addr->sun_path); + else + eprintf("bind :", &address[sizeof("/dev/unix/abstract/") - 1]); + } + } + } else { + if (mode & 0070) + weprintf("ignoring -g due to using passed down socket\n"); + if (mode & 0007) + weprintf("ignoring -o due to using passed down socket\n"); + if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &(socklen_t){sizeof(listening)})) + eprintf("getsockopt SOL_SOCKET SO_ACCEPTCONN:"); + } + + if (!listening && listen(fd, SOMAXCONN)) + eprintf("listen:"); + + return fd; +} + +void +libsbusd_daemonise(const char *pidfile, void (*sigexit)(int)) +{ + pid_t pid; + int rw[2], status = 0, fd; + FILE *fp; + + if (pipe(rw)) + eprintf("pipe:"); + + switch ((pid = fork())) { + case -1: + eprintf("fork:"); + + case 0: + close(rw[0]); + setsid(); + switch (fork()) { + case -1: + eprintf("fork:"); + + case 0: + if (signal(SIGHUP, SIG_IGN) == SIG_ERR) + weprintf("signal SIGHUP SIG_IGN:"); + if (signal(SIGINT, sigexit) == SIG_ERR) + weprintf("signal SIGINT :"); + if (pidfile) { + pid = getpid(); + fd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644); + if (fd < 0) + eprintf("open %s O_WRONLY O_CREAT O_EXCL:", pidfile); + fp = fdopen(fd, "w"); + fprintf(fp, "%li\n", (long int)pid); + if (fflush(fp) || ferror(fp)) + eprintf("fprintf %s:", pidfile); + fclose(fp); + } + if (chdir("/")) + eprintf("chdir /:"); + close(STDIN_FILENO); + close(STDOUT_FILENO); + if (isatty(STDERR_FILENO)) { + fd = open("/dev/null", O_WRONLY); + if (fd) + eprintf("open /dev/null O_WRONLY:"); + if (dup2(fd, STDERR_FILENO) != STDERR_FILENO) + eprintf("dup2 /dev/null /dev/stderr:"); + close(fd); + } + if (write(rw[1], &status, 1) < 1) + eprintf("write :"); + close(rw[1]); + break; + + default: + exit(0); + } + break; + + default: + close(rw[1]); + if (waitpid(pid, &status, 0) != pid) + eprintf("waitpid:"); + if (status) + exit(1); + switch (read(rw[0], &status, 1)) { + case -1: + eprintf("read :"); + case 0: + exit(1); + default: + exit(0); + } + } +} + +void +libsbusd_initalise(int foreground, const char **pidfilep, void (*sigexit)(int)) +{ + if (foreground) { + close(STDIN_FILENO); + close(STDOUT_FILENO); + if (signal(SIGHUP, sigexit) == SIG_ERR) + weprintf("signal SIGHUP :"); + if (signal(SIGINT, sigexit) == SIG_ERR) + weprintf("signal SIGINT :"); + *pidfilep = NULL; + } else { + if (!strcmp(*pidfilep, "/dev/null")) + *pidfilep = NULL; + libsbusd_daemonise(*pidfilep, sigexit); + } +} diff --git a/libsbusd.h b/libsbusd.h new file mode 100644 index 0000000..535c1d3 --- /dev/null +++ b/libsbusd.h @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBSBUSD_H +#define LIBSBUSD_H + +#include +#include + +enum { + LIBSBUS_AFUNIX_FD, + LIBSBUS_AFUNIX_RANDOM, + LIBSBUS_AFUNIX_ABSTRACT, + LIBSBUS_AFUNIX_CONCRETE +}; + +#ifndef eprintf +# define eprintf(...) (libsbusd_weprintf(__VA_ARGS__), exit(1)) +#endif + +void libsbusd_weprintf(const char *, ...); +#ifndef weprintf +# define weprintf libsbusd_weprintf +#endif + +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 *); +void libsbusd_daemonise(const char *, void (*)(int)); +int libsbusd_afunix(struct sockaddr_un *, int *, const char *); +int libsbusd_mksocket(struct sockaddr_un *, const char *, int, mode_t); +void libsbusd_initalise(int, const char **, void (*)(int)); + +#endif diff --git a/sbusd.c b/sbusd.c index 1f26a2c..ecafa55 100644 --- a/sbusd.c +++ b/sbusd.c @@ -3,24 +3,15 @@ #include #include #include -#include #include #include #include -#include -#include -#include -#include #include #include -#include -#include #include #include "arg.h" - -#define STYPE_MAX(T) (long long int)((1ULL << (8 * sizeof(T) - 1)) - 1) -#define eprintf(...) (weprintf(__VA_ARGS__), exit(1)) +#include "libsbusd.h" enum blocking_mode { BLOCKING_QUEUE, @@ -56,7 +47,7 @@ static int epfd; static int had_client = 0; static struct sockaddr_un addr; static uid_t *users; -static size_t nusers; +static size_t nusers = 0; static const char *pidfile = "/run/sbus.pid"; static void @@ -66,19 +57,6 @@ usage(void) exit(1); } -static void -weprintf(const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - if (strchr(fmt, '\0')[-1] == ':') { - fputc(' ', stderr); - perror(NULL); - } - va_end(args); -} - static void sigexit(int signo) { @@ -161,39 +139,6 @@ cred_ok: } } -static int -is_subscription_match(const char *sub, const char *key) -{ - const char *sub_start = sub; - for (;;) { - while (*sub && *sub == *key) { - sub++; - key++; - } - if (!*key) - return !*sub; - if (!*sub) - return sub == sub_start || sub[-1] == '/'; - if (*sub == '*') { - sub++; - while (*key && *key != '/') - key++; - continue; - } - return 0; - } -} - -static int -is_subscribed(const struct client *cl, const char *key) -{ - size_t i = cl->nsubs; - while (i--) - if (is_subscription_match(cl->subs[i], key)) - return 1; - return 0; -} - static int is_subscription_acceptable(struct client *cl, const char *key) { @@ -235,7 +180,7 @@ add_subscription(struct client *cl, const char *key) remove_client(cl); return; case 0: - weprintf("client subscribed unacceptable routing key\n"); + weprintf("client subscribed to unacceptable routing key\n"); remove_client(cl); return; default: @@ -303,7 +248,7 @@ handle_cmsg(struct client *cl, char *buf, size_t n) n += (size_t)sprintf(&buf[n], "!/cred/%lli/%lli/%lli", (long long int)cred.gid, (long long int)cred.uid, - (long long int)cred.gid); + (long long int)cred.pid); if (send_packet(cl, buf, n)) { weprintf("send :"); remove_client(cl); @@ -336,7 +281,7 @@ broadcast(const char *msg, size_t n) { struct client *cl = head.next, *tmp; for (; cl->next; cl = cl->next) { - if (!is_subscribed(cl, &msg[4])) + if (!libsbusd_issubed(cl->subs, cl->nsubs, &msg[4])) continue; if (send_packet(cl, msg, n)) { cl = (tmp = cl)->prev; @@ -375,214 +320,6 @@ handle_message(struct client *cl) } } -static void -randomise(void *buf, size_t n) -{ - char *p = buf; - while (n--) - *p++ = rand(); -} - -static void -print_address(void) -{ - char buf[2 * sizeof(addr.sun_path) + 1]; - char *p = buf; - const unsigned char *a = (const unsigned char *)addr.sun_path; - size_t n = sizeof(addr.sun_path); - - for (; n--; p += 2, a += 1) { - p[0] = "0123456789abcdef"[(int)*a >> 4]; - p[1] = "0123456789abcdef"[(int)*a & 15]; - } - *p = '\0'; - - printf("/dev/unix/abstract/%s\n", buf); - if (fflush(stdout) || ferror(stdout)) - eprintf("failed print generated address:"); -} - -static int -make_socket(const char *address, int reuse, mode_t mode) -{ - int fd = -1, randaddr = 0, hi, lo, listening = 0; - long int tmp; - size_t n; - const char *p, *q; - char *a; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - - if (strstr(address, "/dev/fd/") == address) { - p = &address[sizeof("/dev/fd/") - 1]; - if (!isdigit(*p)) - goto def; - errno = 0; - tmp = strtol(p, &a, 10); - if (errno || *a || tmp < 0) { - errno = 0; - goto def; - } - if (tmp > INT_MAX) { - errno = EBADF; - goto bad_address; - } - fd = (int)tmp; - reuse = 0; - } else if (!strcmp(address, "/dev/unix/abstract")) { - randaddr = 1; - reuse = 0; - } else if (strstr(address, "/dev/unix/abstract/") == address) { - p = &address[sizeof("/dev/unix/abstract/") - 1]; - n = strlen(p); - if (n & 1) - goto def; - for (q = p; *q; q++) - if (!isxdigit(*q)) - goto def; - if (n > sizeof(addr.sun_path) * 2) { - errno = ENAMETOOLONG; - goto bad_address; - } - a = addr.sun_path; - for (; *p; p += 2) { - hi = (p[0] & 15) + 9 * !isdigit(p[0]); - lo = (p[1] & 15) + 9 * !isdigit(p[1]); - *a++ = (hi << 4) | lo; - } - reuse = 0; - } else { - def: - if (strlen(address) >= sizeof(addr.sun_path)) { - errno = ENAMETOOLONG; - goto bad_address; - } - strcpy(addr.sun_path, address); - } - - if (reuse) - unlink(addr.sun_path); - - if (fd < 0) { - fd = socket(PF_UNIX, SOCK_SEQPACKET, 0); - if (fd < 0) - eprintf("socket PF_UNIX SOCK_SEQPACKET:"); - if (fchmod(fd, mode)) - eprintf("fchmod %o:", mode); - if (randaddr) { - srand((unsigned)time(NULL)); - for (;;) { - randomise(&addr.sun_path[1], sizeof(addr.sun_path) - 1); - if (!bind(fd, (void *)&addr, sizeof(addr))) - break; - else if (errno != EADDRINUSE) - eprintf("bind :"); - } - print_address(); - } else { - if (bind(fd, (void *)&addr, sizeof(addr))) { - if (*addr.sun_path) - eprintf("bind %s:", addr.sun_path); - else - eprintf("bind :", &address[sizeof("/dev/unix/abstract/") - 1]); - } - } - } else { - if (mode & 0070) - weprintf("ignoring -g due to using passed down socket\n"); - if (mode & 0007) - weprintf("ignoring -o due to using passed down socket\n"); - if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &listening, &(socklen_t){sizeof(listening)})) - eprintf("getsockopt SOL_SOCKET SO_ACCEPTCONN:"); - } - - if (!listening && listen(fd, SOMAXCONN)) - eprintf("listen:"); - - return fd; - -bad_address: - eprintf("bad unix socket address:"); - exit(1); -} - -static void -daemonise(void) -{ - pid_t pid; - int rw[2], status = 0, fd; - FILE *fp; - - if (pipe(rw)) - eprintf("pipe:"); - - switch ((pid = fork())) { - case -1: - eprintf("fork:"); - - case 0: - close(rw[0]); - setsid(); - switch (fork()) { - case -1: - eprintf("fork:"); - - case 0: - if (signal(SIGHUP, SIG_IGN) == SIG_ERR) - weprintf("signal SIGHUP SIG_IGN:"); - if (signal(SIGINT, sigexit) == SIG_ERR) - weprintf("signal SIGINT :"); - if (pidfile) { - pid = getpid(); - fd = open(pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644); - if (fd < 0) - eprintf("open %s O_WRONLY O_CREAT O_EXCL:", pidfile); - fp = fdopen(fd, "w"); - fprintf(fp, "%li\n", (long int)pid); - if (fflush(fp) || ferror(fp)) - eprintf("fprintf %s:", pidfile); - fclose(fp); - } - if (chdir("/")) - eprintf("chdir /:"); - close(STDIN_FILENO); - close(STDOUT_FILENO); - if (isatty(STDERR_FILENO)) { - fd = open("/dev/null", O_WRONLY); - if (fd) - eprintf("open /dev/null O_WRONLY:"); - if (dup2(fd, STDERR_FILENO) != STDERR_FILENO) - eprintf("dup2 /dev/null /dev/stderr:"); - close(fd); - } - if (write(rw[1], &status, 1) < 1) - eprintf("write :"); - close(rw[1]); - break; - - default: - exit(0); - } - break; - - default: - close(rw[1]); - if (waitpid(pid, &status, 0) != pid) - eprintf("waitpid:"); - if (status) - exit(1); - switch (read(rw[0], &status, 1)) { - case -1: - eprintf("read :"); - case 0: - exit(1); - default: - exit(0); - } - } -} - int main(int argc, char *argv[]) { @@ -592,10 +329,7 @@ main(int argc, char *argv[]) int foreground = 0; mode_t mode = 0700; int reuse_address = 0; - struct passwd *user; int server, n; - long long int tmp; - char *arg; users = alloca(argc * sizeof(*users)); @@ -622,19 +356,7 @@ main(int argc, char *argv[]) reuse_address = 1; break; case 'u': - arg = EARGF(); - if (!isdigit(*arg)) - goto user_by_name; - errno = 0; - tmp = strtoll(arg, &arg, 10); - if (errno || *arg || tmp < 0 || tmp > STYPE_MAX(uid_t)) - goto user_by_name; - users[nusers++] = (uid_t)tmp; - user_by_name: - user = getpwnam(arg); - if (!user) - eprintf("getpwnam %s:", arg); - users[nusers++] = user->pw_uid; + libsbusd_adduser(users, &nusers, EARGF()); break; default: usage(); @@ -643,24 +365,11 @@ main(int argc, char *argv[]) usage(); umask(0); - server = make_socket(address, reuse_address, mode); - if (foreground) { - close(STDIN_FILENO); - close(STDOUT_FILENO); - if (signal(SIGHUP, sigexit) == SIG_ERR) - weprintf("signal SIGHUP :"); - if (signal(SIGINT, sigexit) == SIG_ERR) - weprintf("signal SIGINT :"); - pidfile = NULL; - } else { - if (!strcmp(pidfile, "/dev/null")) - pidfile = NULL; - daemonise(); - } - + server = libsbusd_mksocket(&addr, address, reuse_address, mode); + libsbusd_initalise(foreground, &pidfile, sigexit); if (nusers) users[nusers++] = getuid(); - + head.next = &tail; tail.prev = &head; -- cgit v1.2.3-70-g09d2