diff options
Diffstat (limited to '')
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | libsbusd.c | 342 | ||||
| -rw-r--r-- | libsbusd.h | 32 | ||||
| -rw-r--r-- | sbusd.c | 309 | 
4 files changed, 385 insertions, 301 deletions
| @@ -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 <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pwd.h> +#include <signal.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + + +#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 <socket> %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 <random abstract address>:"); +			} +			print_address(addr); +		} else { +			if (bind(fd, (void *)addr, sizeof(*addr))) { +				if (*addr->sun_path) +					eprintf("bind %s:", addr->sun_path); +				else +					eprintf("bind <abstract:%s>:", &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 <exit>:"); +			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 <pipe>:"); +			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 <pipe>:"); +		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 <exit>:"); +		if (signal(SIGINT, sigexit) == SIG_ERR) +			weprintf("signal SIGINT <exit>:"); +		*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 <sys/un.h> +#include <stdlib.h> + +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 @@ -3,24 +3,15 @@  #include <sys/socket.h>  #include <sys/stat.h>  #include <sys/un.h> -#include <sys/wait.h>  #include <alloca.h>  #include <ctype.h>  #include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <pwd.h> -#include <stdarg.h>  #include <stdio.h>  #include <stdlib.h> -#include <string.h> -#include <time.h>  #include <unistd.h>  #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 @@ -67,19 +58,6 @@ usage(void)  }  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)  {  	if (*addr.sun_path) @@ -162,39 +140,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)  {  	struct ucred cred; @@ -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 <client>:");  			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 <socket> %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 <random abstract address>:"); -			} -			print_address(); -		} else { -			if (bind(fd, (void *)&addr, sizeof(addr))) { -				if (*addr.sun_path) -					eprintf("bind %s:", addr.sun_path); -				else -					eprintf("bind <abstract:%s>:", &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 <exit>:"); -			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 <pipe>:"); -			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 <pipe>:"); -		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 <exit>:"); -		if (signal(SIGINT, sigexit) == SIG_ERR) -			weprintf("signal SIGINT <exit>:"); -		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; | 
