diff options
Diffstat (limited to 'keyexchange/isakmpd-20041012/monitor.c')
-rw-r--r-- | keyexchange/isakmpd-20041012/monitor.c | 1174 |
1 files changed, 0 insertions, 1174 deletions
diff --git a/keyexchange/isakmpd-20041012/monitor.c b/keyexchange/isakmpd-20041012/monitor.c deleted file mode 100644 index bd14005..0000000 --- a/keyexchange/isakmpd-20041012/monitor.c +++ /dev/null @@ -1,1174 +0,0 @@ -/* $OpenBSD: monitor.c,v 1.29 2004/08/12 11:21:07 hshoexer Exp $ */ - -/* - * Copyright (c) 2003 Håkan Olsson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <netinet/in.h> -#include <errno.h> -#include <fcntl.h> -#include <pwd.h> -#include <signal.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#if defined (USE_POLICY) -#include <regex.h> -#include <keynote.h> -#endif - -#include "sysdep.h" - -#include "conf.h" -#include "log.h" -#include "monitor.h" -#include "policy.h" -#include "ui.h" -#include "util.h" -#include "pf_key_v2.h" - -struct monitor_state { - pid_t pid; - int s; - char root[MAXPATHLEN]; -} m_state; - -volatile sig_atomic_t sigchlded = 0; -extern volatile sig_atomic_t sigtermed; -static volatile sig_atomic_t cur_state = STATE_INIT; - -/* Private functions. */ -int m_write_int32(int, int32_t); -int m_write_raw(int, char *, size_t); -int m_read_int32(int, int32_t *); -int m_read_raw(int, char *, size_t); -void m_flush(int); - -static void m_priv_getfd(int); -static void m_priv_getsocket(int); -static void m_priv_setsockopt(int); -static void m_priv_bind(int); -static int m_priv_local_sanitize_path(char *, size_t, int); -static int m_priv_check_sockopt(int, int); -static int m_priv_check_bind(const struct sockaddr *, socklen_t); -static void m_priv_increase_state(int); -static void m_priv_test_state(int); - -static void m_priv_ui_init(int); -static void m_priv_pfkey_open(int); - -/* - * Public functions, unprivileged. - */ - -/* Setup monitor context, fork, drop child privs. */ -pid_t -monitor_init(int debug) -{ - struct passwd *pw; - int p[2]; - - memset(&m_state, 0, sizeof m_state); - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, p) != 0) - log_fatal("monitor_init: socketpair() failed"); - - pw = getpwnam(ISAKMPD_PRIVSEP_USER); - if (pw == NULL) - log_fatal("monitor_init: getpwnam(\"%s\") failed", - ISAKMPD_PRIVSEP_USER); - - m_state.pid = fork(); - m_state.s = p[m_state.pid ? 1 : 0]; - strlcpy(m_state.root, pw->pw_dir, sizeof m_state.root); - - LOG_DBG((LOG_SYSDEP, 30, "monitor_init: pid %d my fd %d", m_state.pid, - m_state.s)); - - /* The child process should drop privileges now. */ - if (!m_state.pid) { - if (chroot(pw->pw_dir) != 0 || chdir("/") != 0) - log_fatal("monitor_init: chroot failed"); - - if (setgid(pw->pw_gid) != 0) - log_fatal("monitor_init: setgid(%d) failed", - pw->pw_gid); - - if (setuid(pw->pw_uid) != 0) - log_fatal("monitor_init: setuid(%d) failed", - pw->pw_uid); - - LOG_DBG((LOG_MISC, 10, - "monitor_init: privileges dropped for child process")); - } else { - setproctitle("monitor [priv]"); - } - - - /* With "-dd", stop and wait here. For gdb "attach" etc. */ - if (debug > 1) { - log_print("monitor_init: stopped %s PID %d fd %d%s", - m_state.pid ? "priv" : "child", getpid(), m_state.s, - m_state.pid ? ", waiting for SIGCONT" : ""); - kill(getpid(), SIGSTOP); /* Wait here for SIGCONT. */ - if (m_state.pid) - kill(m_state.pid, SIGCONT); /* Continue child. */ - } - - return m_state.pid; -} - -void -monitor_exit(int code) -{ - if (m_state.pid != 0) - kill(m_state.pid, SIGKILL); - - exit(code); -} - -void -monitor_ui_init(void) -{ - int32_t err; - - if (m_write_int32(m_state.s, MONITOR_UI_INIT)) - goto errout; - - if (m_read_int32(m_state.s, &err)) - goto errout; - - if (err != 0) { - log_fatal("monitor_ui_init: parent could not create FIFO " - "\"%s\"", ui_fifo); - exit(1); - } - - ui_socket = mm_receive_fd(m_state.s); - if (ui_socket < 0) - log_fatal("monitor_ui_init: parent could not create FIFO " - "\"%s\"", ui_fifo); - - return; - -errout: - log_error("monitor_ui_init: problem talking to privileged process"); - return; -} - -int -monitor_pf_key_v2_open(void) -{ - int32_t err; - - if (m_write_int32(m_state.s, MONITOR_PFKEY_OPEN)) - goto errout; - - if (m_read_int32(m_state.s, &err)) - goto errout; - - if (err < 0) { - log_error("monitor_pf_key_v2_open: parent could not create " - "PF_KEY socket"); - return -1; - } - - pf_key_v2_socket = mm_receive_fd(m_state.s); - if (pf_key_v2_socket < 0) { - log_error("monitor_pf_key_v2_open: mm_receive_fd() failed: %s", - strerror(errno)); - return -1; - } - return pf_key_v2_socket; - -errout: - log_error("monitor_pf_key_v2_open: problem talking to privileged " - "process"); - return -1; -} - -int -monitor_open(const char *path, int flags, mode_t mode) -{ - int fd, mode32 = (int32_t) mode; - int32_t err; - char realpath[MAXPATHLEN]; - - if (path[0] == '/') - strlcpy(realpath, path, sizeof realpath); - else - snprintf(realpath, sizeof realpath, "%s/%s", m_state.root, - path); - - /* Write data to priv process. */ - if (m_write_int32(m_state.s, MONITOR_GET_FD)) - goto errout; - - if (m_write_raw(m_state.s, realpath, strlen(realpath) + 1)) - goto errout; - - if (m_write_int32(m_state.s, flags)) - goto errout; - - if (m_write_int32(m_state.s, mode32)) - goto errout; - - if (m_read_int32(m_state.s, &err)) - goto errout; - - if (err != 0) { - errno = (int) err; - return -1; - } - /* Wait for response. */ - fd = mm_receive_fd(m_state.s); - if (fd < 0) { - log_error("monitor_open: mm_receive_fd () failed: %s", - strerror(errno)); - return -1; - } - return fd; - -errout: - log_error("monitor_open: problem talking to privileged process"); - return -1; -} - -FILE * -monitor_fopen(const char *path, const char *mode) -{ - FILE *fp; - int fd, flags = 0, saved_errno; - mode_t mask, cur_umask; - - /* Only the child process is supposed to run this. */ - if (m_state.pid) - log_fatal("[priv] bad call to monitor_fopen"); - - switch (mode[0]) { - case 'r': - flags = (mode[1] == '+' ? O_RDWR : O_RDONLY); - break; - case 'w': - flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT | - O_TRUNC; - break; - case 'a': - flags = (mode[1] == '+' ? O_RDWR : O_WRONLY) | O_CREAT | - O_APPEND; - break; - default: - log_fatal("monitor_fopen: bad call"); - } - - cur_umask = umask(0); - (void)umask(cur_umask); - mask = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; - mask &= ~cur_umask; - - fd = monitor_open(path, flags, mask); - if (fd < 0) - return NULL; - - /* Got the fd, attach a FILE * to it. */ - fp = fdopen(fd, mode); - if (!fp) { - log_error("monitor_fopen: fdopen() failed"); - saved_errno = errno; - close(fd); - errno = saved_errno; - return NULL; - } - return fp; -} - -int -monitor_stat(const char *path, struct stat *sb) -{ - int fd, r, saved_errno; - - /* O_NONBLOCK is needed for stat'ing fifos. */ - fd = monitor_open(path, O_RDONLY | O_NONBLOCK, 0); - if (fd < 0) - return -1; - - r = fstat(fd, sb); - saved_errno = errno; - close(fd); - errno = saved_errno; - return r; -} - -int -monitor_socket(int domain, int type, int protocol) -{ - int s; - int32_t err; - - if (m_write_int32(m_state.s, MONITOR_GET_SOCKET)) - goto errout; - - if (m_write_int32(m_state.s, (int32_t)domain)) - goto errout; - - if (m_write_int32(m_state.s, (int32_t)type)) - goto errout; - - if (m_write_int32(m_state.s, (int32_t)protocol)) - goto errout; - - if (m_read_int32(m_state.s, &err)) - goto errout; - - if (err != 0) { - errno = (int)err; - return -1; - } - /* Read result. */ - s = mm_receive_fd(m_state.s); - if (s < 0) { - log_error("monitor_socket: mm_receive_fd () failed: %s", - strerror(errno)); - return -1; - } - return s; - -errout: - log_error("monitor_socket: problem talking to privileged process"); - return -1; -} - -int -monitor_setsockopt(int s, int level, int optname, const void *optval, - socklen_t optlen) -{ - int32_t ret, err; - - if (m_write_int32(m_state.s, MONITOR_SETSOCKOPT)) - goto errout; - if (mm_send_fd(m_state.s, s)) - goto errout; - - if (m_write_int32(m_state.s, (int32_t)level)) - goto errout; - if (m_write_int32(m_state.s, (int32_t)optname)) - goto errout; - if (m_write_int32(m_state.s, (int32_t)optlen)) - goto errout; - if (m_write_raw(m_state.s, (char *)optval, (size_t)optlen)) - goto errout; - - if (m_read_int32(m_state.s, &err)) - goto errout; - - if (err != 0) - errno = (int)err; - - if (m_read_int32(m_state.s, &ret)) - goto errout; - - return (int)ret; - -errout: - log_print("monitor_setsockopt: read/write error"); - return -1; -} - -int -monitor_bind(int s, const struct sockaddr *name, socklen_t namelen) -{ - int32_t ret, err; - - if (m_write_int32(m_state.s, MONITOR_BIND)) - goto errout; - if (mm_send_fd(m_state.s, s)) - goto errout; - - if (m_write_int32(m_state.s, (int32_t)namelen)) - goto errout; - if (m_write_raw(m_state.s, (char *)name, (size_t)namelen)) - goto errout; - - if (m_read_int32(m_state.s, &err)) - goto errout; - - if (err != 0) - errno = (int)err; - - if (m_read_int32(m_state.s, &ret)) - goto errout; - - return (int)ret; - -errout: - log_print("monitor_bind: read/write error"); - return -1; -} - -struct monitor_dirents * -monitor_opendir(const char *path) -{ - char *buf, *cp; - size_t bufsize; - int fd, nbytes, entries; - long base; - struct stat sb; - struct dirent *dp; - struct monitor_dirents *direntries; - - fd = monitor_open(path, 0, O_RDONLY); - if (fd < 0) { - log_error("monitor_opendir: opendir(\"%s\") failed", path); - return NULL; - } - /* Now build a list with all dirents from fd. */ - if (fstat(fd, &sb) < 0) { - (void)close(fd); - return NULL; - } - if (!S_ISDIR(sb.st_mode)) { - (void)close(fd); - errno = EACCES; - return NULL; - } - bufsize = sb.st_size; - if (bufsize < sb.st_blksize) - bufsize = sb.st_blksize; - - buf = calloc(bufsize, sizeof(char)); - if (buf == NULL) { - (void)close(fd); - errno = EACCES; - return NULL; - } - nbytes = getdirentries(fd, buf, bufsize, &base); - if (nbytes <= 0) { - (void)close(fd); - free(buf); - errno = EACCES; - return NULL; - } - (void)close(fd); - - for (entries = 0, cp = buf; cp < buf + nbytes;) { - dp = (struct dirent *)cp; - cp += dp->d_reclen; - entries++; - } - - direntries = calloc(1, sizeof(struct monitor_dirents)); - if (direntries == NULL) { - free(buf); - errno = EACCES; - return NULL; - } - direntries->dirents = calloc(entries + 1, sizeof(struct dirent *)); - if (direntries->dirents == NULL) { - free(buf); - free(direntries); - errno = EACCES; - return NULL; - } - direntries->current = 0; - - for (entries = 0, cp = buf; cp < buf + nbytes;) { - dp = (struct dirent *)cp; - direntries->dirents[entries++] = dp; - cp += dp->d_reclen; - } - direntries->dirents[entries] = NULL; - - return direntries; -} - -struct dirent * -monitor_readdir(struct monitor_dirents *direntries) -{ - if (direntries->dirents[direntries->current] != NULL) - return direntries->dirents[direntries->current++]; - - return NULL; -} - -int -monitor_closedir(struct monitor_dirents *direntries) -{ - free(direntries->dirents); - free(direntries); - - return 0; -} - -void -monitor_init_done(void) -{ - if (m_write_int32(m_state.s, MONITOR_INIT_DONE)) - log_print("monitor_init_done: read/write error"); - - return; -} - -/* - * Start of code running with privileges (the monitor process). - */ - -/* Help functions for monitor_loop(). */ -static void -monitor_got_sigchld(int sig) -{ - sigchlded = 1; -} - -static void -sig_pass_to_chld(int sig) -{ - int oerrno = errno; - - if (m_state.pid != -1) - kill(m_state.pid, sig); - errno = oerrno; -} - -/* This function is where the privileged process waits(loops) indefinitely. */ -void -monitor_loop(int debug) -{ - pid_t pid; - fd_set *fds; - size_t fdsn; - int status, n, maxfd; - - if (!debug) - log_to(0); - - maxfd = m_state.s + 1; - - fdsn = howmany(maxfd, NFDBITS) * sizeof(fd_mask); - fds = (fd_set *)malloc(fdsn); - if (!fds) { - kill(m_state.pid, SIGTERM); - log_fatal("monitor_loop: malloc (%lu) failed", - (unsigned long)fdsn); - return; - } - /* If the child dies, we should shutdown also. */ - signal(SIGCHLD, monitor_got_sigchld); - - /* SIGHUP, SIGUSR1 and SIGUSR2 will be forwarded to child. */ - signal(SIGHUP, sig_pass_to_chld); - signal(SIGUSR1, sig_pass_to_chld); - signal(SIGUSR2, sig_pass_to_chld); - - while (cur_state < STATE_QUIT) { - /* - * Currently, there is no need for us to hang around if the - * child is in the process of shutting down. - */ - if (sigtermed) { - m_priv_increase_state(STATE_QUIT); - kill(m_state.pid, SIGTERM); - break; - } - - if (sigchlded) { - do { - pid = waitpid(m_state.pid, &status, WNOHANG); - } while (pid == -1 && errno == EINTR); - - if (pid == m_state.pid && (WIFEXITED(status) || - WIFSIGNALED(status))) { - m_priv_increase_state(STATE_QUIT); - break; - } - } - - memset(fds, 0, fdsn); - FD_SET(m_state.s, fds); - - n = select(maxfd, fds, NULL, NULL, NULL); - if (n == -1) { - if (errno != EINTR) { - log_error("select"); - sleep(1); - } - } else if (n) - if (FD_ISSET(m_state.s, fds)) { - int32_t msgcode; - if (m_read_int32(m_state.s, &msgcode)) - m_flush(m_state.s); - else - switch (msgcode) { - case MONITOR_GET_FD: - m_priv_getfd(m_state.s); - break; - - case MONITOR_UI_INIT: - LOG_DBG((LOG_MISC, 80, - "%s: MONITOR_UI_INIT", - __func__)); - m_priv_test_state(STATE_INIT); - m_priv_ui_init(m_state.s); - break; - - case MONITOR_PFKEY_OPEN: - LOG_DBG((LOG_MISC, 80, - "%s: MONITOR_PFKEY_OPEN", - __func__)); - m_priv_test_state(STATE_INIT); - m_priv_pfkey_open(m_state.s); - break; - - case MONITOR_GET_SOCKET: - LOG_DBG((LOG_MISC, 80, - "%s: MONITOR_GET_SOCKET", - __func__)); - m_priv_test_state(STATE_INIT); - m_priv_getsocket(m_state.s); - break; - - case MONITOR_SETSOCKOPT: - LOG_DBG((LOG_MISC, 80, - "%s: MONITOR_SETSOCKOPT", - __func__)); - m_priv_test_state(STATE_INIT); - m_priv_setsockopt(m_state.s); - break; - - case MONITOR_BIND: - LOG_DBG((LOG_MISC, 80, - "%s: MONITOR_BIND", - __func__)); - m_priv_test_state(STATE_INIT); - m_priv_bind(m_state.s); - break; - - case MONITOR_INIT_DONE: - LOG_DBG((LOG_MISC, 80, - "%s: MONITOR_INIT_DONE", - __func__)); - m_priv_test_state(STATE_INIT); - m_priv_increase_state( - STATE_RUNNING); - break; - - case MONITOR_SHUTDOWN: - LOG_DBG((LOG_MISC, 80, - "%s: MONITOR_SHUTDOWN", - __func__)); - m_priv_increase_state( - STATE_QUIT); - break; - - default: - log_print("monitor_loop: " - "got unknown code %d", - msgcode); - } - } - } - - free(fds); - exit(0); -} - - -/* Privileged: called by monitor_loop. */ -static void -m_priv_ui_init(int s) -{ - int32_t err; - - ui_init(); - - if (ui_socket >= 0) - err = 0; - else - err = -1; - - if (m_write_int32(s, err)) - goto errout; - - if (ui_socket >= 0 && mm_send_fd(s, ui_socket)) { - close(ui_socket); - goto errout; - } - - /* In case of stdin, we do not close the socket. */ - if (ui_socket > 0) - close(ui_socket); - return; - -errout: - log_error("m_priv_ui_init: read/write operation failed"); - return; -} - -/* Privileged: called by monitor_loop. */ -static void -m_priv_pfkey_open(int s) -{ - int fd; - int32_t err; - - fd = pf_key_v2_open(); - - if (fd < 0) - err = -1; - else - err = 0; - - if (m_write_int32(s, err)) - goto errout; - - if (fd > 0 && mm_send_fd(s, fd)) { - close(fd); - goto errout; - } - close(fd); - - return; - -errout: - log_error("m_priv_pfkey_open: read/write operation failed"); - return; -} - -/* Privileged: called by monitor_loop. */ -static void -m_priv_getfd(int s) -{ - char path[MAXPATHLEN]; - int32_t v, err; - int flags; - mode_t mode; - - /* - * We expect the following data on the socket: - * u_int32_t pathlen - * <variable> path - * u_int32_t flags - * u_int32_t mode - */ - - if (m_read_raw(s, path, MAXPATHLEN)) - goto errout; - - if (m_read_int32(s, &v)) - goto errout; - flags = (int)v; - - if (m_read_int32(s, &v)) - goto errout; - mode = (mode_t) v; - - if (m_priv_local_sanitize_path(path, sizeof path, flags) != 0) { - err = EACCES; - v = -1; - } else { - err = 0; - v = (int32_t)open(path, flags, mode); - if (v < 0) - err = (int32_t)errno; - } - - if (m_write_int32(s, err)) - goto errout; - - if (v > 0 && mm_send_fd(s, v)) { - close(v); - goto errout; - } - close(v); - return; - -errout: - log_error("m_priv_getfd: read/write operation failed"); - return; -} - -/* Privileged: called by monitor_loop. */ -static void -m_priv_getsocket(int s) -{ - int domain, type, protocol; - int32_t v, err; - - if (m_read_int32(s, &v)) - goto errout; - domain = (int)v; - - if (m_read_int32(s, &v)) - goto errout; - type = (int)v; - - if (m_read_int32(s, &v)) - goto errout; - protocol = (int)v; - - err = 0; - v = (int32_t)socket(domain, type, protocol); - if (v < 0) - err = (int32_t)errno; - - if (m_write_int32(s, err)) - goto errout; - - if (v > 0 && mm_send_fd(s, v)) { - close(v); - goto errout; - } - close(v); - return; - -errout: - log_error("m_priv_getsocket: read/write operation failed"); - return; -} - -/* Privileged: called by monitor_loop. */ -static void -m_priv_setsockopt(int s) -{ - int sock, level, optname; - char *optval = 0; - socklen_t optlen; - int32_t v, err; - - sock = mm_receive_fd(s); - if (sock < 0) - goto errout; - - if (m_read_int32(s, &level)) - goto errout; - - if (m_read_int32(s, &optname)) - goto errout; - - if (m_read_int32(s, &optlen)) - goto errout; - - optval = (char *)malloc(optlen); - if (!optval) - goto errout; - - if (m_read_raw(s, optval, optlen)) - goto errout; - - if (m_priv_check_sockopt(level, optname) != 0) { - err = EACCES; - v = -1; - } else { - err = 0; - v = (int32_t)setsockopt(sock, level, optname, optval, optlen); - if (v < 0) - err = (int32_t)errno; - } - - close(sock); - sock = -1; - - if (m_write_int32(s, err)) - goto errout; - - if (m_write_int32(s, v)) - goto errout; - - free(optval); - return; - -errout: - log_print("m_priv_setsockopt: read/write error"); - if (optval) - free(optval); - if (sock >= 0) - close(sock); - return; -} - -/* Privileged: called by monitor_loop. */ -static void -m_priv_bind(int s) -{ - int sock; - struct sockaddr *name = 0; - socklen_t namelen; - int32_t v, err; - - sock = mm_receive_fd(s); - if (sock < 0) - goto errout; - - if (m_read_int32(s, &v)) - goto errout; - namelen = (socklen_t) v; - - name = (struct sockaddr *)malloc(namelen); - if (!name) - goto errout; - - if (m_read_raw(s, (char *)name, (size_t)namelen)) - goto errout; - - if (m_priv_check_bind(name, namelen) != 0) { - err = EACCES; - v = -1; - } else { - err = 0; - v = (int32_t)bind(sock, name, namelen); - if (v < 0) { - log_error("m_priv_bind: bind(%d,%p,%d) returned %d", - sock, name, namelen, v); - err = (int32_t)errno; - } - } - - close(sock); - sock = -1; - - if (m_write_int32(s, err)) - goto errout; - - if (m_write_int32(s, v)) - goto errout; - - free(name); - return; - -errout: - log_print("m_priv_bind: read/write error"); - if (name) - free(name); - if (sock >= 0) - close(sock); - return; -} - -/* - * Help functions, used by both privileged and unprivileged code - */ - -/* Write a 32-bit value to a socket. */ -int -m_write_int32(int s, int32_t value) -{ - u_int32_t v; - - memcpy(&v, &value, sizeof v); - return (write(s, &v, sizeof v) == -1); -} - -/* Write a number of bytes of data to a socket. */ -int -m_write_raw(int s, char *data, size_t dlen) -{ - if (m_write_int32(s, (int32_t) dlen)) - return 1; - return (write(s, data, dlen) == -1); -} - -int -m_read_int32(int s, int32_t *value) -{ - u_int32_t v; - - if (read(s, &v, sizeof v) != sizeof v) - return 1; - memcpy(value, &v, sizeof v); - return 0; -} - -int -m_read_raw(int s, char *data, size_t maxlen) -{ - u_int32_t v; - int r; - - if (m_read_int32(s, &v)) - return 1; - if (v > maxlen) - return 1; - r = read(s, data, v); - return (r == -1); -} - -/* Drain all available input on a socket. */ -void -m_flush(int s) -{ - u_int8_t tmp; - int one = 1; - - ioctl(s, FIONBIO, &one);/* Non-blocking */ - while (read(s, &tmp, 1) > 0); - ioctl(s, FIONBIO, 0); /* Blocking */ -} - -/* Check that path/mode is permitted. */ -static int -m_priv_local_sanitize_path(char *path, size_t pmax, int flags) -{ - char *p; - - /* - * We only permit paths starting with - * /etc/isakmpd/ (read only) - * /var/run/ (rw) - */ - - if (strlen(path) < strlen("/var/run/")) - goto bad_path; - - /* Any path containing '..' is invalid. */ - for (p = path; *p && (p - path) < (int)pmax; p++) - if (*p == '.' && *(p + 1) == '.') - goto bad_path; - - /* For any write-mode, only a few paths are permitted. */ - if ((flags & O_ACCMODE) != O_RDONLY) { - if (strncmp("/var/run/", path, strlen("/var/run/")) == 0) - return 0; - goto bad_path; - } - /* Any other path is read-only. */ - if (strncmp(ISAKMPD_ROOT, path, strlen(ISAKMPD_ROOT)) == 0 || - strncmp("/var/run/", path, strlen("/var/run/")) == 0) - return 0; - -bad_path: - log_print("m_priv_local_sanitize_path: illegal path \"%.1023s\", " - "replaced with \"/dev/null\"", path); - strlcpy(path, "/dev/null", pmax); - return 1; -} - -/* Check setsockopt */ -static int -m_priv_check_sockopt(int level, int name) -{ - switch (level) { - /* These are allowed */ - case SOL_SOCKET: - case IPPROTO_IP: - case IPPROTO_IPV6: - break; - - default: - log_print("m_priv_check_sockopt: Illegal level %d", level); - return 1; - } - - switch (name) { - /* These are allowed */ - case SO_REUSEPORT: - case SO_REUSEADDR: - case IP_AUTH_LEVEL: - case IP_ESP_TRANS_LEVEL: - case IP_ESP_NETWORK_LEVEL: - case IP_IPCOMP_LEVEL: - case IPV6_AUTH_LEVEL: - case IPV6_ESP_TRANS_LEVEL: - case IPV6_ESP_NETWORK_LEVEL: - case IPV6_IPCOMP_LEVEL: - break; - - default: - log_print("m_priv_check_sockopt: Illegal option name %d", - name); - return 1; - } - - return 0; -} - -/* Check bind */ -static int -m_priv_check_bind(const struct sockaddr *sa, socklen_t salen) -{ - in_port_t port; - - if (sa == NULL) { - log_print("NULL address"); - return 1; - } - if (sysdep_sa_len((struct sockaddr *)sa) != salen) { - log_print("Length mismatch: %d %d", - (int)sysdep_sa_len((struct sockaddr *)sa), (int)salen); - return 1; - } - switch (sa->sa_family) { - case AF_INET: - if (salen != sizeof(struct sockaddr_in)) { - log_print("Invalid inet address length"); - return 1; - } - port = ((const struct sockaddr_in *)sa)->sin_port; - break; - case AF_INET6: - if (salen != sizeof(struct sockaddr_in6)) { - log_print("Invalid inet6 address length"); - return 1; - } - port = ((const struct sockaddr_in6 *)sa)->sin6_port; - break; - default: - log_print("Unknown address family"); - return 1; - } - - port = ntohs(port); - - if (port != ISAKMP_PORT_DEFAULT && port < 1024) { - log_print("Disallowed port %u", port); - return 1; - } - return 0; -} - -/* Increase state into less permissive mode */ -static void -m_priv_increase_state(int state) -{ - if (state <= cur_state) - log_print("m_priv_increase_state: attempt to decrase state " - "or match current state"); - if (state < STATE_INIT || state > STATE_QUIT) - log_print("m_priv_increase_state: attempt to switch to " - "invalid state"); - cur_state = state; -} - -static void -m_priv_test_state(int state) -{ - if (cur_state != state) - log_print("m_priv_test_state: Illegal state: %d != %d", - (int)cur_state, state); - return; -} |