diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2018-04-24 23:33:59 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2018-04-24 23:33:59 +0200 |
commit | 6e7b5102c33a510f93b7b418d0bfc082ae2595f7 (patch) | |
tree | 86f08ae3138d6be89cad0a4cc05fd19ea78d2648 | |
parent | b14059ea3a1f2e0a41d90ababf27473c026042d0 (diff) |
POTD skeleton #27.
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | src/jail.c | 192 | ||||
-rw-r--r-- | src/jail.h | 5 | ||||
-rw-r--r-- | src/main.c | 25 | ||||
-rw-r--r-- | src/server.c | 22 | ||||
-rw-r--r-- | src/utils.h | 4 |
5 files changed, 189 insertions, 59 deletions
@@ -8,22 +8,35 @@ #include "jail.h" #include "socket.h" +#include "server.h" #include "utils.h" #include "log.h" -static int jail_daemonfn(jail_ctx *ctx); +typedef struct jail_prisoner_process { + pid_t prisoner_pid; + psocket client_psock; + char host_buf[NI_MAXHOST], service_buf[NI_MAXSERV]; +} jail_prisoner_process; + +static int jail_daemonfn_epoll(int epoll_fd, jail_ctx *ctx[], size_t siz); +static int jail_accept_client(jail_ctx *ctx[], + size_t siz, struct epoll_event *event); static int jail_childfn(void *arg); void jail_init_ctx(jail_ctx **ctx, size_t stacksize) { assert(ctx); - if (stacksize > BUFSIZ) - stacksize = BUFSIZ; + if (stacksize > MAX_STACKSIZE || + stacksize < MIN_STACKSIZE) + { + stacksize = MAX_STACKSIZE; + } if (!*ctx) - *ctx = (jail_ctx *) calloc(1, sizeof(**ctx)); + *ctx = (jail_ctx *) malloc(sizeof(**ctx)); assert(*ctx); + memset(*ctx, 0, sizeof(**ctx)); (*ctx)->stacksize = stacksize; (*ctx)->stack_ptr = calloc(1, (*ctx)->stacksize); (*ctx)->stack_beg = @@ -68,64 +81,165 @@ int jail_validate_ctx(const jail_ctx *ctx) return 0; } -void jail_free(jail_ctx **ctx) +int jail_setup_epoll(jail_ctx *ctx[], size_t siz) { - free((*ctx)->stack_ptr); - free(*ctx); - *ctx = NULL; + int s, fd = epoll_create1(0); /* flags == 0 -> obsolete size arg is dropped */ + struct epoll_event ev; + + assert(ctx); + assert(siz > 0 && siz < POTD_MAXFD); + if (fd < 0) + return -1; + + for (size_t i = 0; i < siz; ++i) { + memset(&ev, 0, sizeof(ev)); + ev.data.fd = ctx[i]->sock.fd; + ev.events = EPOLLIN | EPOLLET; + + s = socket_addrtostr_in(&ctx[i]->sock, + ctx[i]->host_buf, ctx[i]->service_buf); + if (s) { + 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]->sock.fd, &ev); + if (s) { + close(fd); + return -3; + } + } + + return fd; } -int jail_daemonize(jail_ctx *ctx) +int jail_daemonize_epoll(int epoll_fd, jail_ctx *ctx[], size_t siz) { int s; + size_t i; assert(ctx); - s = socket_addrtostr_in(&ctx->sock, - ctx->host_buf, ctx->service_buf); - if (s) { - E_GAIERR(s, "Could not initialise jail daemon socket"); - return 1; - } - ctx->jail_pid = fork(); - switch (ctx->jail_pid) { - case -1: - W_STRERR("Jail daemonize"); + for (i = 0; i < siz; ++i) { + assert(ctx[i]); + s = socket_addrtostr_in(&ctx[i]->sock, + ctx[i]->host_buf, ctx[i]->service_buf); + if (s) { + E_GAIERR(s, "Could not initialise jail daemon socket"); return 1; - case 0: - N("%s", "Jail daemon mainloop"); - jail_daemonfn(ctx); - break; - } - D2("Jail daemon pid: %d", ctx->jail_pid); + } + + ctx[i]->jail_pid = fork(); + switch (ctx[i]->jail_pid) { + case -1: + W_STRERR("Jail daemonize"); + return 1; + case 0: + N("%s", "Jail daemon mainloop"); + jail_daemonfn_epoll(epoll_fd, ctx, siz); + break; + } + D2("Jail daemon pid: %d", ctx[i]->jail_pid); + } return 0; } -static int jail_daemonfn(jail_ctx *ctx) +static int jail_daemonfn_epoll(int epoll_fd, jail_ctx *ctx[], size_t siz) { - int clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC| - CLONE_NEWNS|CLONE_NEWNET; - int fd; + 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); + set_procname("[potd] jaild"); assert( set_child_sighandler() == 0 ); assert( signal(SIGCHLD, SIG_IGN) != SIG_ERR ); + assert( signal(SIGPIPE, SIG_IGN) != SIG_ERR ); + sigemptyset(&eset); - fd = epoll_create1(0); - if (fd < 0) { - E_STRERR("Jail epoll create"); - exit(EXIT_FAILURE); - } + D2("Epoll fd: %d", epoll_fd); while (1) { - ctx->jail_pid = clone(jail_childfn, ctx->stack_beg, - SIGCHLD|clone_flags, NULL); - sleep(1); - printf("---\n"); + int n, i; + + n = epoll_pwait(epoll_fd, events, POTD_MAXEVENTS, -1, &eset); + if (n < 0) + goto error; + + for (i = 0; i < n; ++i) { + if ((events[i].events & EPOLLERR) || + (events[i].events & EPOLLHUP) || + (!(events[i].events & EPOLLIN))) + { + E("Epoll for descriptor %d failed", events[i].data.fd); + E_STRERR("epoll_wait"); + 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); +} + +static int jail_accept_client(jail_ctx *ctx[], + size_t siz, struct epoll_event *event) +{ + int clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC| + CLONE_NEWNS|CLONE_NEWNET; + size_t i, rc = 0; + int s; + jail_prisoner_process *args; + + for (i = 0; i < siz; ++i) { + if (ctx[i]->sock.fd == event->data.fd) { + args = (jail_prisoner_process *) calloc(1, sizeof(*args)); + assert(args); + + if (socket_accept_in(&ctx[i]->sock, &args->client_psock)) { + E_STRERR("Could not accept client connection"); + goto error; + } + + s = socket_addrtostr_in(&args->client_psock, + args->host_buf, args->service_buf); + if (s) { + E_GAIERR(s, "Convert socket address to string"); + goto error; + } + N2("New connection from %s:%s to %s:%s: %d", + args->host_buf, args->service_buf, + ctx[i]->host_buf, ctx[i]->service_buf, + args->client_psock.fd); + + args->prisoner_pid = clone(jail_childfn, ctx[i]->stack_beg, + SIGCHLD|clone_flags, NULL); + + rc = 1; +error: + free(args); + return rc; + } + } + + return rc; } static int jail_childfn(void *arg) @@ -134,7 +248,7 @@ static int jail_childfn(void *arg) if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) { E_STRERR("Jail child prctl"); - return 1; + exit(EXIT_FAILURE); } printf("----> CHILD FN <----\n"); sleep(10); @@ -6,6 +6,7 @@ #include "socket.h" +#define MIN_STACKSIZE 2048 #define MAX_STACKSIZE BUFSIZ typedef struct jail_ctx { @@ -25,8 +26,8 @@ int jail_setup(jail_ctx *ctx, int jail_validate_ctx(const jail_ctx *ctx); -void jail_free(jail_ctx **ctx); +int jail_setup_epoll(jail_ctx *ctx[], size_t siz); -int jail_daemonize(jail_ctx *ctx); +int jail_daemonize_epoll(int epoll_fd, jail_ctx *ctx[], size_t siz); #endif @@ -15,10 +15,12 @@ int main(int argc, char *argv[]) { const size_t srv_siz = 3; + const size_t jail_siz = 2; const char *ssh_ports[srv_siz]; + const char *jail_ports[jail_siz]; server_ctx *srv[srv_siz]; + jail_ctx *jail[jail_siz]; forward_ctx *ssh_fwd = NULL; - jail_ctx *jail = NULL; int epoll_fd; pid_t daemon_pid; @@ -41,16 +43,25 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - { - jail_init_ctx(&jail, MAX_STACKSIZE); - ABORT_ON_FATAL( jail_setup(jail, "127.0.0.1", "33333"), + memset(jail, 0, sizeof(jail)); + jail_ports[0] = "33333"; + jail_ports[1] = "33334"; + + for (size_t i = 0; i < jail_siz; ++i) { + jail_init_ctx(&jail[i], MAX_STACKSIZE); + ABORT_ON_FATAL( jail_setup(jail[i], "127.0.0.1", jail_ports[i]), "Jail daemon setup" ); - ABORT_ON_FATAL( jail_validate_ctx(jail), + ABORT_ON_FATAL( jail_validate_ctx(jail[i]), "Jail validation" ); - ABORT_ON_FATAL( jail_daemonize(jail), - "Jail daemon startup" ); } + D2("%s", "Jail daemon epoll setup"); + epoll_fd = jail_setup_epoll( jail, jail_siz ); + D2("epoll_fd: %d", epoll_fd); + ABORT_ON_FATAL( epoll_fd < 0, "Jail daemon epoll setup" ); + ABORT_ON_FATAL( jail_daemonize_epoll(epoll_fd, jail, jail_siz), + "Jail daemon startup" ); + { ABORT_ON_FATAL( fwd_init_ctx(&ssh_fwd, ssh_init_cb), "Forwarder initialisation" ); diff --git a/src/server.c b/src/server.c index 49837e6..073229c 100644 --- a/src/server.c +++ b/src/server.c @@ -99,8 +99,8 @@ int server_setup_epoll(server_ctx *ctx[], size_t siz) E_GAIERR(s, "Convert socket address to string"); return -2; } - N("Redirector service listening on %s:%s", - ctx[i]->host_buf, ctx[i]->service_buf); + N("Redirector 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]->sock.fd, &ev); if (s) { @@ -124,8 +124,9 @@ int server_mainloop_epoll(int epoll_fd, server_ctx *ctx[], size_t siz) assert(ctx); assert(siz > 0 && siz < POTD_MAXFD); - signal(SIGPIPE, SIG_IGN); + assert( signal(SIGPIPE, SIG_IGN) != SIG_ERR ); sigemptyset(&eset); + while (1) { int n, i; @@ -152,10 +153,8 @@ int server_mainloop_epoll(int epoll_fd, server_ctx *ctx[], size_t siz) } } - free(events); return 0; error: - free(events); return 1; } @@ -168,11 +167,12 @@ static int server_accept_client(server_ctx *ctx[], for (i = 0; i < siz; ++i) { if (ctx[i]->sock.fd == event->data.fd) { - args = (client_thread_args *) calloc(1, sizeof(client_thread_args)); + args = (client_thread_args *) calloc(1, sizeof(*args)); + assert(args); if (socket_accept_in(&ctx[i]->sock, &args->client_psock)) { E_STRERR("Could not accept client connection"); - return 0; + goto error; } args->server_ctx = ctx[i]; @@ -182,10 +182,10 @@ static int server_accept_client(server_ctx *ctx[], E_GAIERR(s, "Convert socket address to string"); goto error; } - N("New connection from %s:%s to %s:%s: %d", - args->host_buf, args->service_buf, - ctx[i]->host_buf, ctx[i]->service_buf, - args->client_psock.fd); + N2("New connection from %s:%s to %s:%s: %d", + args->host_buf, args->service_buf, + ctx[i]->host_buf, ctx[i]->service_buf, + args->client_psock.fd); if (pthread_create(&args->self, NULL, client_mainloop_epoll, args)) diff --git a/src/utils.h b/src/utils.h index 65ff5fb..da5be32 100644 --- a/src/utils.h +++ b/src/utils.h @@ -14,4 +14,8 @@ void set_procname(const char *new_arg0); pid_t daemonize(int stay_foreground); +int close_fds_except(int fd, ...); + +int change_user_group(const char *user, const char *group); + #endif |