diff --git a/trunk/src/sj3serv/Makefile.am b/trunk/src/sj3serv/Makefile.am index 077ccdb..b853f51 100644 --- a/trunk/src/sj3serv/Makefile.am +++ b/trunk/src/sj3serv/Makefile.am @@ -32,7 +32,6 @@ exampledir = $(datadir)/examples/sj3 sj3serv_SOURCES = \ sj_string.h \ sj3serv.h \ - auth.c \ comuni.c \ error.c \ execute.c \ diff --git a/trunk/src/sj3serv/auth.c b/trunk/src/sj3serv/auth.c deleted file mode 100644 index 0932827..0000000 --- a/trunk/src/sj3serv/auth.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2003 Anil Madhavapeddy - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sj3serv.h" - -enum cmd_types { - AUTH_GETUGID, - AUTH_EXIT -}; - -static int auth_fd = -1; - -static int may_read(int, void *, size_t); -static void must_read(int, void *, size_t); -static void must_write(int, void *, size_t); - - -int -exec_auth() -{ - int socks[2]; - int i; - pid_t child_pid = -1; - struct sigaction sa; - - if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) { - fprintf(stderr, "socketpair() failed"); - exit(255); - } - - child_pid = fork(); - if (child_pid < 0) { - fprintf(stderr, "fork() failed\n"); - exit(255); - } - - if (!child_pid) { - auth_fd = socks[1]; - return 0; - } - - memset(&sa, 0, sizeof(sa)); - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = SIG_DFL; - for (i = 1; i < NSIG; i++) - sigaction(i, &sa, NULL); - - strlcpy(chroot_dir, "/", sizeof(chroot_dir)); - set_priv("[auth]"); - - while (1) { - int cmd; - size_t username_len; - char username[BUFSIZ]; - int ret; - struct passwd *pw; - - if (may_read(socks[0], &cmd, sizeof(int))) - break; - switch (cmd) { - case AUTH_GETUGID: - /* length, user name */ - must_read(socks[0], &username_len, sizeof(size_t)); - if (username_len == 0 || username_len > sizeof(username)) - _exit(0); - must_read(socks[0], username, username_len); - username[username_len - 1] = '\0'; - pw = getpwnam(username); - if (pw) { - ret = 1; - must_write(socks[0], &ret, sizeof(int)); - must_write(socks[0], &pw->pw_uid, sizeof(uid_t)); - must_write(socks[0], &pw->pw_gid, sizeof(gid_t)); - } else { - ret = 0; - must_write(socks[0], &ret, sizeof(int)); - } - endpwent(); - break; - case AUTH_EXIT: - close(socks[0]); - _exit(1); - default: - fprintf(stderr, "auth unknown command %d\n", cmd); - close(socks[0]); - _exit(255); - } - } - fprintf(stderr, "auth fatal error\n"); - - close(socks[0]); - _exit(1); -} - -/* Read all data or return 1 for error. */ -static int -may_read(int fd, void *buf, size_t n) -{ - char *s = buf; - ssize_t res, pos = 0; - - while (n > pos) { - res = read(fd, s + pos, n - pos); - switch (res) { - case -1: - if (errno == EINTR || errno == EAGAIN) - continue; - case 0: - return (1); - default: - pos += res; - } - } - return (0); -} - -/* Read data with the assertion that it all must come through, or - * else abort the process. Based on atomicio() from openssh. */ -static void -must_read(int fd, void *buf, size_t n) -{ - char *s = buf; - ssize_t res, pos = 0; - - while (n > pos) { - res = read(fd, s + pos, n - pos); - switch (res) { - case -1: - if (errno == EINTR || errno == EAGAIN) - continue; - case 0: - fprintf(stderr, "must_read: internal protocol error\n"); - fflush(stderr); - _exit(0); - default: - pos += res; - } - } -} - -/* Write data with the assertion that it all has to be written, or - * else abort the process. Based on atomicio() from openssh. */ -static void -must_write(int fd, void *buf, size_t n) -{ - char *s = buf; - ssize_t res, pos = 0; - - while (n > pos) { - res = write(fd, s + pos, n - pos); - switch (res) { - case -1: - if (errno == EINTR || errno == EAGAIN) - continue; - case 0: - fprintf(stderr, "must_write: internal protocol error\n"); - fflush(stderr); - _exit(0); - default: - pos += res; - } - } -} - -int -auth_getugid(char *username, sj3_ugid *ugid) -{ - size_t len; - int cmd = AUTH_GETUGID; - int ret; - uid_t uid; - gid_t gid; - - if (auth_fd < 0) { - fprintf(stderr, "%s called from privileged portion", "auth_getpwnam"); - exit(255); - } - - len = strlen(username) + 1; - if (len == 0 || BUFSIZ < len) - return NULL; - - must_write(auth_fd, &cmd, sizeof(int)); - must_write(auth_fd, &len, sizeof(size_t)); - must_write(auth_fd, username, len); - must_read(auth_fd, &ret, sizeof(int)); - if (ret) { - must_read(auth_fd, &uid, sizeof(uid_t)); - must_read(auth_fd, &gid, sizeof(gid_t)); - ugid->uid = uid; - ugid->gid = gid; - return 1; - } else { - return 0; - } -} - -void -exit_auth() -{ - int cmd = AUTH_EXIT; - - must_write(auth_fd, &cmd, sizeof(int)); - - return; -} - diff --git a/trunk/src/sj3serv/execute.c b/trunk/src/sj3serv/execute.c index 8e19a25..3b7cbe1 100644 --- a/trunk/src/sj3serv/execute.c +++ b/trunk/src/sj3serv/execute.c @@ -194,7 +194,7 @@ exec_connect() if (!(wp = alloc_workarea())) longjmp(error_ret, SJ3_NotEnoughMemory); - if (auth_getugid(username, &ugid)) { + if (priv_getugid(username, &ugid)) { struct sockaddr addr; uid_t euid; gid_t egid; diff --git a/trunk/src/sj3serv/main.c b/trunk/src/sj3serv/main.c index 9e0572a..ef556ee 100644 --- a/trunk/src/sj3serv/main.c +++ b/trunk/src/sj3serv/main.c @@ -93,7 +93,7 @@ server_terminate() { close_socket(); sj_closeall(); - exit_auth(); + priv_exit(); exit(0); } @@ -134,7 +134,7 @@ main(int argc, char **argv) exec_daemon(); - exec_auth(); + priv_init(); set_signals(); @@ -142,7 +142,7 @@ main(int argc, char **argv) open_socket(); if (chroot_enable == 1) - set_priv(NULL); + priv_set(NULL); preload_dict(); preopen_dict(); @@ -152,7 +152,7 @@ main(int argc, char **argv) close_socket(); sj_closeall(); - exit_auth(); + priv_exit(); exit(0); } diff --git a/trunk/src/sj3serv/priv.c b/trunk/src/sj3serv/priv.c index d4c39df..c6692ee 100644 --- a/trunk/src/sj3serv/priv.c +++ b/trunk/src/sj3serv/priv.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2004 Iwata + * Copyright (c) 2008 Iwata + * Copyright (c) 2003 Anil Madhavapeddy * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,13 +18,37 @@ #include #include #include +#include +#include #include +#include #include +#include #include #include "sj3serv.h" +enum priv_state { + STATE_INIT, /* just started up */ + STATE_QUIT /* shutting down */ +}; + +enum cmd_types { + PRIV_GETUGID, + PRIV_EXIT +}; + +static int auth_fd = -1; +static volatile pid_t child_pid = -1; +static volatile sig_atomic_t cur_state = STATE_INIT; + +static int may_read(int, void *, size_t); +static void must_read(int, void *, size_t); +static void must_write(int, void *, size_t); +static void sig_pass_to_chld(int); +static void sig_got_chld(int); + void -set_priv(const char *title) +priv_set(const char *title) { struct passwd *pw; @@ -74,3 +99,223 @@ set_priv(const char *title) exit(255); } } + +int +priv_init() +{ + int socks[2]; + int i; + struct sigaction sa; + + if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) { + fprintf(stderr, "socketpair() failed"); + exit(255); + } + + child_pid = fork(); + if (child_pid < 0) { + fprintf(stderr, "fork() failed\n"); + exit(255); + } + + if (!child_pid) { + auth_fd = socks[1]; + return 0; + } + + /* Father */ + /* Pass TERM/HUP/INT/QUIT through to child, and accept CHLD */ + sa.sa_handler = sig_pass_to_chld; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sa.sa_handler = sig_got_chld; + sa.sa_flags |= SA_NOCLDSTOP; + sigaction(SIGCHLD, &sa, NULL); + + strlcpy(chroot_dir, "/", sizeof(chroot_dir)); + priv_set("[priv]"); + + while (cur_state < STATE_QUIT) { + int cmd; + size_t username_len; + char username[BUFSIZ]; + int ret; + struct passwd *pw; + + if (may_read(socks[0], &cmd, sizeof(int))) + break; + switch (cmd) { + case PRIV_GETUGID: + /* length, user name */ + must_read(socks[0], &username_len, sizeof(size_t)); + if (username_len == 0 || username_len > sizeof(username)) + _exit(0); + must_read(socks[0], username, username_len); + username[username_len - 1] = '\0'; + pw = getpwnam(username); + if (pw) { + ret = 1; + must_write(socks[0], &ret, sizeof(int)); + must_write(socks[0], &pw->pw_uid, sizeof(uid_t)); + must_write(socks[0], &pw->pw_gid, sizeof(gid_t)); + } else { + ret = 0; + must_write(socks[0], &ret, sizeof(int)); + } + endpwent(); + break; + case PRIV_EXIT: + close(socks[0]); + _exit(1); + default: + fprintf(stderr, "auth unknown command %d\n", cmd); + close(socks[0]); + _exit(255); + } + } + fprintf(stderr, "auth fatal error\n"); + + close(socks[0]); + _exit(1); +} + +/* Read all data or return 1 for error. */ +static int +may_read(int fd, void *buf, size_t n) +{ + char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = read(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + return (1); + default: + pos += res; + } + } + return (0); +} + +/* Read data with the assertion that it all must come through, or + * else abort the process. Based on atomicio() from openssh. */ +static void +must_read(int fd, void *buf, size_t n) +{ + char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = read(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + fprintf(stderr, "must_read: internal protocol error\n"); + fflush(stderr); + _exit(0); + default: + pos += res; + } + } +} + +/* Write data with the assertion that it all has to be written, or + * else abort the process. Based on atomicio() from openssh. */ +static void +must_write(int fd, void *buf, size_t n) +{ + char *s = buf; + ssize_t res, pos = 0; + + while (n > pos) { + res = write(fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + case 0: + fprintf(stderr, "must_write: internal protocol error\n"); + fflush(stderr); + _exit(0); + default: + pos += res; + } + } +} + +/* Pass the signal through to child */ +static void +sig_pass_to_chld(int sig) +{ + int oerrno = errno; + + if (child_pid != -1) + kill(child_pid, sig); + errno = oerrno; +} + +/* When child dies, move into the shutdown state */ +/* ARGSUSED */ +static void +sig_got_chld(int sig) +{ + pid_t pid; + + do { + pid = waitpid(WAIT_ANY, NULL, WNOHANG); + if (pid == child_pid && cur_state < STATE_QUIT) + cur_state = STATE_QUIT; + } while (pid > 0 || (pid == -1 && errno == EINTR)); +} + +int +priv_getugid(char *username, sj3_ugid *ugid) +{ + size_t len; + int cmd = PRIV_GETUGID; + int ret; + uid_t uid; + gid_t gid; + + if (auth_fd < 0) { + fprintf(stderr, "%s called from privileged portion", "auth_getpwnam"); + exit(255); + } + + len = strlen(username) + 1; + if (len == 0 || BUFSIZ < len) + return NULL; + + must_write(auth_fd, &cmd, sizeof(int)); + must_write(auth_fd, &len, sizeof(size_t)); + must_write(auth_fd, username, len); + must_read(auth_fd, &ret, sizeof(int)); + if (ret) { + must_read(auth_fd, &uid, sizeof(uid_t)); + must_read(auth_fd, &gid, sizeof(gid_t)); + ugid->uid = uid; + ugid->gid = gid; + return 1; + } else { + return 0; + } +} + +void +priv_exit() +{ + int cmd = PRIV_EXIT; + + must_write(auth_fd, &cmd, sizeof(int)); + + return; +} + diff --git a/trunk/src/sj3serv/sj3serv.h b/trunk/src/sj3serv/sj3serv.h index 76f6a19..7243d42 100644 --- a/trunk/src/sj3serv/sj3serv.h +++ b/trunk/src/sj3serv/sj3serv.h @@ -28,10 +28,10 @@ typedef struct { /* auth.c */ -int exec_auth(); -void exit_auth(); +int priv_init(); +void priv_exit(); -int auth_getugid(char *, sj3_ugid *); +int priv_getugid(char *, sj3_ugid *); /* comuni.c */ extern int client_num;