From 1e07eccace7c50fd0e7fa3b217eda85add5a6630 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Sun, 16 Dec 2012 13:11:29 +0100 Subject: privsep-server: use libev and unix sockets for the server --- bin/Makefile | 15 ++++-- bin/conn.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++ bin/conn.h | 8 +++ bin/list.h | 112 +++++++++++++++++++++++++++++++++++++++ bin/lua-privsep.c | 7 ++- bin/lua-privsep.h | 6 +++ bin/privsep-server.c | 35 +++++++++++++ 7 files changed, 319 insertions(+), 8 deletions(-) create mode 100644 bin/conn.c create mode 100644 bin/conn.h create mode 100644 bin/list.h create mode 100644 bin/lua-privsep.h create mode 100644 bin/privsep-server.c diff --git a/bin/Makefile b/bin/Makefile index e0e03cb..de61268 100644 --- a/bin/Makefile +++ b/bin/Makefile @@ -1,5 +1,5 @@ -COMPILE_PROG = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $($@_objs) $($@_libs) +COMPILE_PROG = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $($@-objs) $($@-libs) PKGCONF ?= pkg-config @@ -8,9 +8,16 @@ LUA_PKG ?= lua LUA_CFLAGS := $(shell $(PKGCONF) --cflags $(LUA_PKG)) LUA_LIBS := $(shell $(PKGCONF) --libs $(LUA_PKG)) -lua-privsep_objs = lua-privsep.o -lua-privsep_libs = $(LUA_LIBS) +LIBEV_LIBS := -lev -lua-privsep: $(lua-privsep_objs) +privsep-server-objs = privsep-server.o lua-privsep.o conn.o +privsep-server-libs = $(LUA_LIBS) $(LIBEV_LIBS) + +all: privsep-server + +privsep-server: $(privsep-server-objs) $(COMPILE_PROG) +clean: + rm -f $(privsep-server-objs) privsep-server + diff --git a/bin/conn.c b/bin/conn.c new file mode 100644 index 0000000..90777ba --- /dev/null +++ b/bin/conn.c @@ -0,0 +1,144 @@ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include "list.h" +#include "conn.h" + +#ifndef DEBUG +#define log_debug(x) printf("%s\n", x) +#define log_perror(x) perror(x) +#endif + +#ifndef MSG_MAX_SIZE +#define MSG_MAX_SIZE 16386 +#endif + +static struct ev_io accept_io; + +struct conn { + struct ev_io io; + struct ev_timer timeout; + size_t num_read; + char msg[MSG_MAX_SIZE]; +}; + +static void conn_free(struct ev_loop *loop, struct conn *rm) +{ + int fd = rm->io.fd; + + ev_io_stop(loop, &rm->io); + ev_timer_stop(loop, &rm->timeout); + close(fd); + free(rm); + log_debug("Connection closed"); +} + +static void conn_recv_cb (struct ev_loop *loop, struct ev_io *w, + int revents) +{ + struct conn *conn = container_of(w, struct conn, io); + int len, i; + char *args; + + len = recv(conn->io.fd, conn->msg, sizeof(conn->msg) - conn->num_read, + MSG_DONTWAIT); + if (len < 0 && errno == EAGAIN) + return; + if (len <= 0) + goto err; + + conn->num_read += len; + if (conn->num_read >= sizeof(conn->msg)) + goto err; + + call_lua(conn->num_read, conn->msg); + return; + +err: + conn_free(loop, conn); +} + +static void conn_timeout_cb (struct ev_loop *loop, struct ev_timer *t, + int revents) +{ + log_debug("Connection timed out"); + conn_free(loop, container_of(t, struct conn, timeout)); +} + +static void conn_accept_cb(struct ev_loop *loop, struct ev_io *w, + int revents) +{ + struct conn *conn; + struct sockaddr_storage from; + socklen_t fromlen = sizeof(from); + int fd; + + fd = accept(w->fd, (struct sockaddr *) &from, &fromlen); + if (fd < 0) { + log_perror("accept"); + return; + } + log_debug("New connection"); + fcntl(fd, F_SETFD, FD_CLOEXEC); + conn = calloc(1, sizeof(struct conn)); + + ev_io_init(&conn->io, conn_recv_cb, fd, EV_READ); + ev_io_start(loop, &conn->io); + ev_timer_init(&conn->timeout, conn_timeout_cb, 10.0, 0.); + ev_timer_start(loop, &conn->timeout); +} + + +int conn_init(struct ev_loop *loop, const char *socket_path) +{ + struct sockaddr_un sun; + char *p; + int fd; + + memset(&sun, 0, sizeof(sun)); + sun.sun_family = AF_UNIX; + strncpy(sun.sun_path, socket_path, sizeof(sun.sun_path)); + + /* create the dir */ + p = strrchr(sun.sun_path, '/'); + if (p) { + *p = '\0'; + mkdir(sun.sun_path, 0755); + *p = '/'; + } + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + log_perror("socket"); + return -1; + } + + fcntl(fd, F_SETFD, FD_CLOEXEC); + unlink(socket_path); + if (bind(fd, (struct sockaddr *) &sun, sizeof(sun)) < 0) + goto perr_close; + + if (listen(fd, 5) < 0) + goto perr_close; + + ev_io_init(&accept_io, conn_accept_cb, fd, EV_READ); + ev_io_start(loop, &accept_io); + return 0; + +perr_close: + log_perror(socket_path); + close(fd); + return -1; + +} diff --git a/bin/conn.h b/bin/conn.h new file mode 100644 index 0000000..f5b33a9 --- /dev/null +++ b/bin/conn.h @@ -0,0 +1,8 @@ +#ifndef CONN_H +#define CONN_H + +#include + +int conn_init(struct ev_loop *loop, const char *socket_path); + +#endif diff --git a/bin/list.h b/bin/list.h new file mode 100644 index 0000000..1fca5e7 --- /dev/null +++ b/bin/list.h @@ -0,0 +1,112 @@ +/* list.h - Single and double linked list macros + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 or later as + * published by the Free Software Foundation. + * + * See http://www.gnu.org/ for details. + * + * This is more or less based on the code in the linux kernel. There are + * minor differences and this is only a subset of the kernel version. + */ + +#ifndef LIST_H +#define LIST_H + +#ifndef NULL +#define NULL 0L +#endif + +#ifndef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#endif + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_INITIALIZER(l) { .next = &l, .prev = &l } + +static inline void list_init(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = NULL; + entry->prev = NULL; +} + +static inline int list_hashed(const struct list_head *n) +{ + return n->next != n && n->next != NULL; +} + +static inline int list_empty(const struct list_head *n) +{ + return !list_hashed(n); +} + +#define list_next(ptr, type, member) \ + (list_hashed(ptr) ? container_of((ptr)->next,type,member) : NULL) + +#define list_entry(ptr, type, member) container_of(ptr,type,member) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.next, typeof(*n), member)) + +#endif diff --git a/bin/lua-privsep.c b/bin/lua-privsep.c index 1e165e1..0307d7c 100644 --- a/bin/lua-privsep.c +++ b/bin/lua-privsep.c @@ -32,7 +32,7 @@ static int traceback (lua_State *L) { return 1; } -int main(int argc, char *argv[]) +int call_lua(const char *msg, size_t msglen) { const char *luamain = PRIVSEP_PATH "privileged-main.lua"; int i, traceback_index; @@ -46,10 +46,9 @@ int main(int argc, char *argv[]) if (luaL_loadfile(L, luamain)) return luaL_error(L, "%s", luamain); - for (i = 1; i < argc; i++) - lua_pushstring(L, argv[i]); + lua_pushlstring(L, msg, msglen); - if (lua_pcall(L, argc-1, 0, traceback_index)) + if (lua_pcall(L, 1, 0, traceback_index)) return luaL_error(L, "error"); diff --git a/bin/lua-privsep.h b/bin/lua-privsep.h new file mode 100644 index 0000000..fae8fcc --- /dev/null +++ b/bin/lua-privsep.h @@ -0,0 +1,6 @@ +#ifndef LUA_PRIVSEP_H +#define LUA_PRIVSEP_H + +int call_lua(const char *msg size_t msglen); + +#endif diff --git a/bin/privsep-server.c b/bin/privsep-server.c new file mode 100644 index 0000000..76d3f4c --- /dev/null +++ b/bin/privsep-server.c @@ -0,0 +1,35 @@ + +#include +#include +#include + +#ifndef DEFAULT_SOCKET_PATH +#define DEFAULT_SOCKET_PATH "/var/run/privsep/root.sock" +#endif + +static void sigint_cb(struct ev_loop *loop, ev_signal *w, int revents) +{ + ev_break(loop, EVBREAK_ALL); +} + +int main(int argc, char *argv[]) +{ + int c; + const char *socket_path = DEFAULT_SOCKET_PATH; + static struct ev_loop *loop; + static struct ev_signal signal_watcher; + + loop = ev_default_loop(0); + + if (conn_init(loop, socket_path) < 0) + return 1; + + ev_signal_init(&signal_watcher, sigint_cb, SIGINT); + ev_signal_start(loop, &signal_watcher); + + ev_run(loop, 0); + printf("%s\n", "Shutting down."); + ev_loop_destroy(loop); + return 0; +} + -- cgit v1.2.3