diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2018-05-08 17:19:47 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2018-05-08 17:19:47 +0200 |
commit | bc240cca7918d6e6f4f56fbe19d32eb20f07a567 (patch) | |
tree | b803bc1e6fb6446369fc063e7efdd53152745569 | |
parent | dad140b0a494c416532a546fdd034dc27ad05b8c (diff) |
POTD skeleton #46.
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | src/jail.c | 254 | ||||
-rw-r--r-- | src/jail.h | 7 | ||||
-rw-r--r-- | src/main.c | 10 | ||||
-rw-r--r-- | src/pevent.c | 1 | ||||
-rw-r--r-- | src/server.c | 29 | ||||
-rw-r--r-- | src/utils.c | 1 |
6 files changed, 154 insertions, 148 deletions
@@ -4,7 +4,6 @@ #include <signal.h> #include <pty.h> #include <sys/wait.h> -#include <sys/epoll.h> #include <sys/prctl.h> #include <sys/stat.h> #include <assert.h> @@ -15,21 +14,29 @@ #include "utils.h" #include "log.h" -typedef struct jail_prisoner_process { +typedef struct prisoner_process { psocket client_psock; char host_buf[NI_MAXHOST], service_buf[NI_MAXSERV]; char *newroot; -} jail_prisoner_process; +} prisoner_process; -static int jail_mainloop_epoll(int epoll_fd, jail_ctx *ctx[], size_t siz) +typedef struct server_event { + const jail_ctx **jail_ctx; + const size_t siz; +} server_event; + +typedef struct client_event { + const psocket *client_sock; + const int tty_fd; +} client_event; + +static int jail_mainloop(event_ctx **ev_ctx, const jail_ctx *ctx[], size_t siz) __attribute__((noreturn)); -static int jail_accept_client(jail_ctx *ctx[], - size_t siz, struct epoll_event *event); -static int jail_childfn(jail_prisoner_process *ctx) +static int jail_accept_client(event_ctx *ev_ctx, int fd, void *user_data); +static int jail_childfn(prisoner_process *ctx) __attribute__((noreturn)); -static int jail_socket_tty_epoll(jail_prisoner_process *ctx, int tty_fd); -static forward_state -jail_socket_tty_io_epoll(struct epoll_event *ev, int dest_fd); +static int jail_socket_tty(prisoner_process *ctx, int tty_fd); +static int jail_socket_tty_io(event_ctx *ev_ctx, int src_fd, void *user_data); void jail_init_ctx(jail_ctx **ctx, size_t stacksize) @@ -77,20 +84,21 @@ int jail_validate_ctx(const jail_ctx *ctx) return 0; } -int jail_setup_epoll(jail_ctx *ctx[], size_t siz) +int jail_setup_event(jail_ctx *ctx[], size_t siz, event_ctx **ev_ctx) { - int s, fd = epoll_create1(0); /* flags == 0 -> obsolete size arg is dropped */ - struct epoll_event ev; + int s; assert(ctx); assert(siz > 0 && siz < POTD_MAXFD); - if (fd < 0) - return -1; + + event_init(ev_ctx); + if (event_setup(*ev_ctx)) + return 1; for (size_t i = 0; i < siz; ++i) { - memset(&ev, 0, sizeof(ev)); - ev.data.fd = ctx[i]->fwd_ctx.sock.fd; - ev.events = EPOLLIN | EPOLLET; + if (event_add_sock(*ev_ctx, &ctx[i]->fwd_ctx.sock)) { + return 1; + } s = socket_addrtostr_in(&ctx[i]->fwd_ctx.sock, ctx[i]->host_buf, ctx[i]->service_buf); @@ -98,27 +106,21 @@ int jail_setup_epoll(jail_ctx *ctx[], size_t siz) E_GAIERR(s, "Convert socket address to string"); return -2; } - N("Jail service listening on %s:%s: %d", - ctx[i]->host_buf, ctx[i]->service_buf, ev.data.fd); - - s = epoll_ctl(fd, EPOLL_CTL_ADD, ctx[i]->fwd_ctx.sock.fd, &ev); - if (s) { - close(fd); - return -3; - } + N("Jail service listening on %s:%s", + ctx[i]->host_buf, ctx[i]->service_buf); } - return fd; + return 0; } -pid_t jail_daemonize(int epoll_fd, jail_ctx *ctx[], size_t siz) +pid_t jail_daemonize(event_ctx **ev_ctx, jail_ctx *ctx[], size_t siz) { pid_t p; int s; size_t i; - assert(ctx); - assert(siz > 0); + assert(ev_ctx && *ev_ctx && ctx); + assert(siz > 0 && siz <= POTD_MAXFD); for (i = 0; i < siz; ++i) { assert(ctx[i]); @@ -136,81 +138,54 @@ pid_t jail_daemonize(int epoll_fd, jail_ctx *ctx[], size_t siz) W_STRERR("%s", "Jail daemonize"); return -1; case 0: - N("Jail daemon mainloop on Epoll fd %d", epoll_fd); - jail_mainloop_epoll(epoll_fd, ctx, siz); + N("%s", "Jail daemon mainloop"); + jail_mainloop(ev_ctx, (const jail_ctx **) ctx, siz); } D2("Jail daemon pid: %d", p); - close(epoll_fd); + event_free(ev_ctx); for (i = 0; i < siz; ++i) socket_close(&ctx[i]->fwd_ctx.sock); return p; } -static int jail_mainloop_epoll(int epoll_fd, jail_ctx *ctx[], size_t siz) +static int jail_mainloop(event_ctx **ev_ctx, const jail_ctx *ctx[], size_t siz) { - static struct epoll_event *events = NULL; - sigset_t eset; - - if (!events) - events = (struct epoll_event *) calloc(POTD_MAXEVENTS, sizeof(*events)); - - assert(events); - assert(ctx); - assert(siz > 0 && siz < POTD_MAXFD); + int rc; + server_event ev_jail = { ctx, siz }; set_procname("[potd] jail"); assert( set_child_sighandler() == 0 ); - sigemptyset(&eset); - - while (1) { - int n, i; - n = epoll_pwait(epoll_fd, events, POTD_MAXEVENTS, -1, &eset); - if (n < 0) - goto error; + rc = event_loop(*ev_ctx, jail_accept_client, &ev_jail); + event_free(ev_ctx); - for (i = 0; i < n; ++i) { - if ((events[i].events & EPOLLERR) || - (events[i].events & EPOLLHUP) || - (!(events[i].events & EPOLLIN))) - { - E_STRERR("Epoll for descriptor %d", events[i].data.fd); - close(events[i].data.fd); - continue; - } else { - if (jail_accept_client(ctx, siz, &events[i])) { - /* new client connection, accept succeeded */ - continue; - } - W2("Jail daemon accept client failed: [fd: %d , npoll: %d]", events[i].data.fd, n); - } - } - } - - close(epoll_fd); - exit(EXIT_SUCCESS); -error: - close(epoll_fd); - exit(EXIT_FAILURE); + exit(rc); } -static int jail_accept_client(jail_ctx *ctx[], - size_t siz, struct epoll_event *event) +static int jail_accept_client(event_ctx *ev_ctx, int fd, void *user_data) { size_t i, rc = 0; int s; pid_t prisoner_pid; - static jail_prisoner_process *args; + server_event *ev_jail = (server_event *) user_data; + static prisoner_process *args; + const jail_ctx *jail_ctx; + + (void) ev_ctx; + assert(ev_jail); - for (i = 0; i < siz; ++i) { - if (ctx[i]->fwd_ctx.sock.fd == event->data.fd) { - args = (jail_prisoner_process *) calloc(1, sizeof(*args)); + for (i = 0; i < ev_jail->siz; ++i) { + jail_ctx = ev_jail->jail_ctx[i]; + if (jail_ctx->fwd_ctx.sock.fd == fd) { + args = (prisoner_process *) calloc(1, sizeof(*args)); assert(args); - args->newroot = ctx[i]->newroot; + args->newroot = jail_ctx->newroot; - if (socket_accept_in(&ctx[i]->fwd_ctx.sock, &args->client_psock)) { + if (socket_accept_in(&jail_ctx->fwd_ctx.sock, + &args->client_psock)) + { E_STRERR("Could not accept client connection for fd %d", args->client_psock.fd); goto error; @@ -224,7 +199,7 @@ static int jail_accept_client(jail_ctx *ctx[], } N2("New connection from %s:%s to %s:%s: %d", args->host_buf, args->service_buf, - ctx[i]->host_buf, ctx[i]->service_buf, + jail_ctx->host_buf, jail_ctx->service_buf, args->client_psock.fd); prisoner_pid = fork(); @@ -249,7 +224,7 @@ error: return rc; } -static int jail_childfn(jail_prisoner_process *ctx) +static int jail_childfn(prisoner_process *ctx) { const char *path_dev = "/dev"; const char *path_devpts = "/dev/pts"; @@ -262,7 +237,8 @@ static int jail_childfn(jail_prisoner_process *ctx) assert(ctx); self_pid = getpid(); - + if (setpgrp()) + FATAL("Jail set process group for pid %d", self_pid); if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) FATAL("Jail child prctl for pid %d", self_pid); if (!ctx->newroot) @@ -279,6 +255,10 @@ static int jail_childfn(jail_prisoner_process *ctx) D2("Mounting rootfs to '%s'", ctx->newroot); mount_root(); + D2("Checking Shell '%s%s'", ctx->newroot, path_shell); + if (access(path_shell, R_OK|X_OK)) + FATAL("Shell '%s%s' is not accessible", ctx->newroot, path_shell); + D2("Mounting devtmpfs to '%s%s'", ctx->newroot, path_dev); s = mkdir(path_dev, S_IRUSR|S_IWUSR|S_IXUSR| S_IRGRP|S_IXGRP| @@ -323,70 +303,92 @@ static int jail_childfn(jail_prisoner_process *ctx) self_pid); break; case 0: - D2("Executing '%s'", path_shell); if (execl(path_shell, path_shell, (char *) NULL)) - FATAL("Execute a shell for pid %d", self_pid); - break; + exit(EXIT_FAILURE); default: if (set_fd_nonblock(master_fd)) FATAL("Pty master fd nonblock for prisoner pid %d", child_pid); N("Socket to tty I/O loop for prisoner pid %d", child_pid); - if (jail_socket_tty_epoll(ctx, master_fd)) + if (jail_socket_tty(ctx, master_fd)) FATAL("Socket to tty I/O loop for prisoner pid %d", child_pid); waitpid(child_pid, &s, 0); } + close(master_fd); exit(EXIT_FAILURE); } -static int jail_socket_tty_epoll(jail_prisoner_process *ctx, int tty_fd) +static int jail_socket_tty(prisoner_process *ctx, int tty_fd) { - int s, fd; - struct epoll_event event = {0,{0}}; - struct epoll_event *events; - sigset_t eset; + client_event ev_cli = {NULL, tty_fd}; + int s, rc = 1; + event_ctx *ev_ctx = NULL; assert(ctx); - events = (struct epoll_event *) calloc(POTD_MAXEVENTS, sizeof(*events)); - assert(events); - - fd = epoll_create1(0); - if (fd < 0) - return -1; - - event.events = EPOLLIN | EPOLLET; - event.data.fd = ctx->client_psock.fd; - s = epoll_ctl(fd, EPOLL_CTL_ADD, ctx->client_psock.fd, &event); - if (s) - FATAL("Jail Socket Epoll for client %s:%s", - ctx->host_buf, ctx->service_buf); - event.data.fd = tty_fd; - s = epoll_ctl(fd, EPOLL_CTL_ADD, tty_fd, &event); - if (s) - FATAL("Jail TTY Epoll for client %s:%s", - ctx->host_buf, ctx->service_buf); - - sigemptyset(&eset); - - while (1) { - int n, i; - - n = epoll_pwait(fd, events, POTD_MAXEVENTS, -1, &eset); - if (n < 0) - break; - for (i = 0; i < n; ++i) { - } + event_init(&ev_ctx); + if (event_setup(ev_ctx)) { + E_STRERR("Jail event context creation for jail tty fd %d", + tty_fd); + goto finish; + } + s = socket_nonblock(&ctx->client_psock); + if (s) { + E_STRERR("Socket non blocking mode to client %s:%s fd %d", + ctx->host_buf, ctx->service_buf, ctx->client_psock.fd); + goto finish; + } + if (event_add_sock(ev_ctx, &ctx->client_psock)) { + E_STRERR("Jail event context for socket %s:%s", + ctx->host_buf, ctx->service_buf); + goto finish; + } + if (event_add_fd(ev_ctx, tty_fd)) { + E_STRERR("Jail event context for tty fd %d", + tty_fd); + goto finish; } - return 0; + ev_cli.client_sock = &ctx->client_psock; + rc = event_loop(ev_ctx, jail_socket_tty_io, &ev_cli); +finish: + event_free(&ev_ctx); + return rc; } -static forward_state -jail_socket_tty_io_epoll(struct epoll_event *ev, int dest_fd) +static int +jail_socket_tty_io(event_ctx *ev_ctx, int src_fd, void *user_data) { - return CON_OK; + int dest_fd; + client_event *ev_cli = (client_event *) user_data; + forward_state fwd_state; + + (void) ev_ctx; + (void) src_fd; + (void) ev_cli; + + if (src_fd == ev_cli->client_sock->fd) { + dest_fd = ev_cli->tty_fd; + } else if (src_fd == ev_cli->tty_fd) { + dest_fd = ev_cli->client_sock->fd; + } else return 0; + + fwd_state = event_forward_connection(ev_ctx, dest_fd); + + switch (fwd_state) { + case CON_IN_TERMINATED: + case CON_OUT_TERMINATED: + ev_ctx->active = 0; + case CON_OK: + return 1; + case CON_IN_ERROR: + case CON_OUT_ERROR: + ev_ctx->active = 0; + return 0; + } + + return 1; } @@ -5,6 +5,7 @@ #include <unistd.h> #include "forward.h" +#include "pevent.h" #define MIN_STACKSIZE 2048 #define MAX_STACKSIZE BUFSIZ @@ -24,10 +25,10 @@ void jail_init_ctx(jail_ctx **ctx, size_t stacksize); int jail_setup(jail_ctx *ctx, const char *listen_addr, const char *listen_port); -int jail_validate_ctx(const jail_ctx *ctx); +int jail_validate_ctx(const jail_ctx *jail_ctx); -int jail_setup_epoll(jail_ctx *ctx[], size_t siz); +int jail_setup_event(jail_ctx *ctx[], size_t siz, event_ctx **ev_ctx); -pid_t jail_daemonize(int epoll_fd, jail_ctx *ctx[], size_t siz); +pid_t jail_daemonize(event_ctx **ev_ctx, jail_ctx *ctx[], size_t siz); #endif @@ -24,7 +24,8 @@ int main(int argc, char *argv[]) jail_ctx *jail[jail_siz]; forward_ctx *ssh_fwd = NULL; event_ctx *srv_event = NULL; - int jail_epoll_fd, proc_status; + event_ctx *jail_event = NULL; + int proc_status; pid_t daemon_pid, srv_pid, jail_pid, wpid; (void) argc; @@ -60,10 +61,9 @@ int main(int argc, char *argv[]) "Jail validation" ); } - jail_epoll_fd = jail_setup_epoll( jail, jail_siz ); - D2("Jail epoll fd: %d", jail_epoll_fd); - ABORT_ON_FATAL( jail_epoll_fd < 0, "Jail daemon epoll setup" ); - jail_pid = jail_daemonize(jail_epoll_fd, jail, jail_siz); + ABORT_ON_FATAL( jail_setup_event( jail, jail_siz, &jail_event ), + "Jail daemon epoll setup" ); + jail_pid = jail_daemonize(&jail_event, jail, jail_siz); ABORT_ON_FATAL( jail_pid < 1, "Jail daemon startup" ); { diff --git a/src/pevent.c b/src/pevent.c index 053564c..f2fef01 100644 --- a/src/pevent.c +++ b/src/pevent.c @@ -33,6 +33,7 @@ int event_setup(event_ctx *ctx) assert(ctx); if (ctx->epoll_fd < 0) + /* flags == 0 -> obsolete size arg is dropped */ ctx->epoll_fd = epoll_create1(0); return ctx->epoll_fd < 0; diff --git a/src/server.c b/src/server.c index e0b8738..6df7916 100644 --- a/src/server.c +++ b/src/server.c @@ -11,12 +11,12 @@ #include "utils.h" #include "log.h" -typedef struct client_thread_args { +typedef struct client_thread { pthread_t self; psocket client_sock; char host_buf[NI_MAXHOST], service_buf[NI_MAXSERV]; const server_ctx *server_ctx; -} client_thread_args; +} client_thread; typedef struct server_event { const server_ctx **srv_ctx; @@ -25,14 +25,15 @@ typedef struct server_event { typedef struct client_event { const psocket *fwd_sock; - const client_thread_args *client_args; + const client_thread *client_args; } client_event; static forward_state -fwd_state_string(const forward_state c_state, const client_thread_args *args, +fwd_state_string(const forward_state c_state, const client_thread *args, const psocket *fwd); static int -server_mainloop(event_ctx *ev_ctx, const server_ctx *srv_ctx[], size_t siz); +server_mainloop(event_ctx *ev_ctx, const server_ctx *srv_ctx[], size_t siz) + __attribute__((noreturn)); static int server_accept_client(event_ctx *ev_ctx, int fd, void *user_data); static void * client_mainloop(void *arg); @@ -153,7 +154,7 @@ pid_t server_daemonize(event_ctx *ev_ctx, server_ctx *srv_ctx[], size_t siz) } static forward_state -fwd_state_string(const forward_state c_state, const client_thread_args *args, +fwd_state_string(const forward_state c_state, const client_thread *args, const psocket *fwd) { switch (c_state) { @@ -197,7 +198,7 @@ static int server_mainloop(event_ctx *ev_ctx, const server_ctx *srv_ctx[], size_ rc = event_loop(ev_ctx, server_accept_client, &ev_srv); event_free(&ev_ctx); - return rc; + exit(rc); } static int server_accept_client(event_ctx *ev_ctx, int fd, void *user_data) @@ -205,7 +206,7 @@ static int server_accept_client(event_ctx *ev_ctx, int fd, void *user_data) size_t i; int s; server_event *ev_srv = (server_event *) user_data; - client_thread_args *args; + client_thread *args; const server_ctx *srv_ctx; (void) ev_ctx; @@ -214,7 +215,7 @@ static int server_accept_client(event_ctx *ev_ctx, int fd, void *user_data) for (i = 0; i < ev_srv->siz; ++i) { srv_ctx = ev_srv->srv_ctx[i]; if (srv_ctx->sock.fd == fd) { - args = (client_thread_args *) calloc(1, sizeof(*args)); + args = (client_thread *) calloc(1, sizeof(*args)); assert(args); if (socket_accept_in(&srv_ctx->sock, @@ -260,19 +261,19 @@ error: static void * client_mainloop(void *arg) { - client_thread_args *args; + client_thread *args; client_event ev_cli; int s; event_ctx *ev_ctx = NULL; psocket fwd; assert(arg); - args = (client_thread_args *) arg; + args = (client_thread *) arg; pthread_detach(args->self); event_init(&ev_ctx); if (event_setup(ev_ctx)) { - E_STRERR("Client event descriptor creation for server fd %d", + E_STRERR("Client event context creation for server fd %d", args->server_ctx->sock.fd); goto finish; } @@ -289,7 +290,7 @@ client_mainloop(void *arg) args->server_ctx->fwd_ctx->service_buf, fwd.fd); if (event_add_sock(ev_ctx, &fwd)) { - E_STRERR("Forward event descriptor add to %s:%s forward fd %d", + E_STRERR("Forward event context add to %s:%s forward fd %d", args->server_ctx->fwd_ctx->host_buf, args->server_ctx->fwd_ctx->service_buf, fwd.fd); goto finish; @@ -307,7 +308,7 @@ client_mainloop(void *arg) goto finish; } if (event_add_sock(ev_ctx, &args->client_sock)) { - E_STRERR("Forward event descriptor add to %s:%s forward fd %d", + E_STRERR("Forward event context add to %s:%s forward fd %d", args->server_ctx->fwd_ctx->host_buf, args->server_ctx->fwd_ctx->service_buf, fwd.fd); goto finish; diff --git a/src/utils.c b/src/utils.c index 8d775cb..f91173a 100644 --- a/src/utils.c +++ b/src/utils.c @@ -381,6 +381,7 @@ int create_device_files(const char *mount_path) int s = 0; s |= create_device_file_checked(mount_path, "ptmx", S_IFCHR, 1, makedev(5,2)); + s |= create_device_file_checked(mount_path, "tty", S_IFCHR, 1, makedev(5,0)); return s; } |