diff --git a/trunk/configure.in b/trunk/configure.in index c4c7206..3f9db62 100644 --- a/trunk/configure.in +++ b/trunk/configure.in @@ -835,8 +835,9 @@ fi SJ3SYSCONFDIR=$sj3sysconf_dir AC_SUBST(SJ3SYSCONFDIR) -AC_DEFINE_UNQUOTED(SJ3CONFDIR, "$sj3sysconf_dir", [server config dir]) -AC_DEFINE_UNQUOTED(RUNCMDFILE, "$sj3sysconf_dir/sj3serv.lua", [server config file]) +AC_DEFINE_UNQUOTED(SJ3CONFDIR, "$sj3sysconf_dir", [server config dir]) +AC_DEFINE_UNQUOTED(RUNCMDFILE, "$sj3sysconf_dir/sj3serv.lua", [server config file]) +AC_DEFINE_UNQUOTED(SJ3PROXYCFG, "$sj3sysconf_dir/sj3proxy.lua", [proxy config file]) dnl configure config directory sj3var_dir=`echo $localstatedir | grep prefix` @@ -855,6 +856,8 @@ fi SJ3VARDIR="$sj3var_dir" AC_SUBST(SJ3VARDIR) AC_DEFINE_UNQUOTED(CHROOTDIR, "$sj3var_dir/spool/sj3", [chrooted dir]) +AC_DEFINE_UNQUOTED(SOCKDIR, "$sj3var_dir/run", [socket dir]) +AC_DEFINE_UNQUOTED(SOCKETFILE, "/sj3serv.socket", [socket file]) AC_DEFINE_UNQUOTED(SOCKETNAME, "$sj3var_dir/run/sj3serv.socket", [socket file]) SJ3DICTDIR="$sj3var_dir/spool/sj3" @@ -894,6 +897,7 @@ AC_CONFIG_FILES([ src/sj3demo/Makefile src/sj3dic/Makefile src/sj3mkdic/Makefile + src/sj3proxy/Makefile src/sj3serv/Makefile src/sj3stat/Makefile ]) diff --git a/trunk/include/sj3common/Const.h b/trunk/include/sj3common/Const.h index 9ef6f42..6d94e54 100644 --- a/trunk/include/sj3common/Const.h +++ b/trunk/include/sj3common/Const.h @@ -66,7 +66,7 @@ #define PORTNAME "sj3" #define LOCALHOST "localhost" #define CHROOTFLAG 1 - +#define STRICTAUTHFLAG 1 #define MAINDICTIONARY "sj3main.dic" #define USERDICTIONARY "private.dic" #define STUDYFILE "study.dat" diff --git a/trunk/include/sj3lua/sj3lua.h b/trunk/include/sj3lua/sj3lua.h index 217e376..a2d397e 100644 --- a/trunk/include/sj3lua/sj3lua.h +++ b/trunk/include/sj3lua/sj3lua.h @@ -17,9 +17,6 @@ #ifndef SJ3LUA_H #define SJ3LUA_H -#include -#include - int sj3lua_check_table(lua_State *); int lua2sj_boolean(lua_State *, char *, int, int, int *); int lua2sj_integer(lua_State *, char *, int, int, int *); @@ -27,6 +24,7 @@ char *lua2sj_string(lua_State *, char *, int, char *, char *, size_t); void sj2lua_boolean(lua_State *, char *, int); void sj2lua_integer(lua_State *, char *, int); void sj2lua_string(lua_State *, char *, char *); +void set_luafunction(lua_State *, char *, lua_CFunction); #endif diff --git a/trunk/lib/sj3lua/sj3lua.c b/trunk/lib/sj3lua/sj3lua.c index 41ab8ae..8c667fc 100644 --- a/trunk/lib/sj3lua/sj3lua.c +++ b/trunk/lib/sj3lua/sj3lua.c @@ -119,3 +119,11 @@ sj2lua_string(lua_State *lstate, char *name, char *s) lua_pushstring(lstate, s); lua_settable(lstate, -3); } + +void +set_luafunction(lua_State *lstate, char *name, lua_CFunction fun) +{ + lua_pushstring(lstate, name); + lua_pushcfunction(lstate, fun); + lua_settable(lstate, -3); +} diff --git a/trunk/src/Makefile.am b/trunk/src/Makefile.am index a56e9c0..462ba1c 100644 --- a/trunk/src/Makefile.am +++ b/trunk/src/Makefile.am @@ -2,5 +2,6 @@ SUBDIRS = \ sj3mkdic \ sj3serv \ sj3dic \ + sj3proxy \ sj3stat \ sj3demo diff --git a/trunk/src/sj3proxy/atomicio.c b/trunk/src/sj3proxy/atomicio.c new file mode 100644 index 0000000..3fa1ab8 --- /dev/null +++ b/trunk/src/sj3proxy/atomicio.c @@ -0,0 +1,71 @@ +/* $OpenBSD: atomicio.c,v 1.9 2007/09/07 14:50:44 tobias Exp $ */ +/* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 2005 Anil Madhavapeddy. All rights reserved. + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * 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 + +#include + +#include +#include +#include + +#include "atomicio.h" + +/* + * ensure all of data on socket comes through. f==read || f==vwrite + */ +size_t +atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) +{ + char *s = _s; + size_t pos = 0; + ssize_t res; + struct pollfd pfd; + + pfd.fd = fd; + pfd.events = f == read ? POLLIN : POLLOUT; + while (n > pos) { + res = (f) (fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR) + continue; + if (errno == EAGAIN) { + (void)poll(&pfd, 1, -1); + continue; + } + return 0; + case 0: + errno = EPIPE; + return pos; + default: + pos += (size_t)res; + } + } + return (pos); +} diff --git a/trunk/src/sj3proxy/atomicio.h b/trunk/src/sj3proxy/atomicio.h new file mode 100644 index 0000000..7bf5b25 --- /dev/null +++ b/trunk/src/sj3proxy/atomicio.h @@ -0,0 +1,39 @@ +/* $OpenBSD: atomicio.h,v 1.2 2007/09/07 14:50:44 tobias Exp $ */ + +/* + * Copyright (c) 2006 Damien Miller. All rights reserved. + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * 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. + */ + +#ifndef _ATOMICIO_H +#define _ATOMICIO_H + +/* + * Ensure all of data on socket comes through. f==read || f==vwrite + */ +size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t); + +#define vwrite (ssize_t (*)(int, void *, size_t))write + +#endif /* _ATOMICIO_H */ diff --git a/trunk/src/sj3proxy/freebsd-sj3proxy.sh.in b/trunk/src/sj3proxy/freebsd-sj3proxy.sh.in new file mode 100755 index 0000000..b161b61 --- /dev/null +++ b/trunk/src/sj3proxy/freebsd-sj3proxy.sh.in @@ -0,0 +1,26 @@ +#!/bin/sh +# + +# PROVIDE: sj3proxy +# REQUIRE: DAEMON +# BEFORE: LOGIN +# KEYWORD: shutdown + +# Define these sj3_* variables in one of these files: +# /etc/rc.conf +# /etc/rc.conf.local +# /etc/rc.conf.d/sj3 +# +# DO NOT CHANGE THESE DEFAULT VALUES HERE +# +sj3proxy_enable=${sj3proxy_enable:-"NO"} # Enable sj3proxy +#sj3_program="%%PREFIX%%/sbin/sj3proxy" # Location of sj3proxy + +. %%RC_SUBR%% + +name="sj3proxy" +rcvar=`set_rcvar` +command="%%PREFIX%%/sbin/sj3proxy" + +load_rc_config $name +run_rc_command "$1" diff --git a/trunk/src/sj3proxy/priv.c b/trunk/src/sj3proxy/priv.c new file mode 100644 index 0000000..96383f4 --- /dev/null +++ b/trunk/src/sj3proxy/priv.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2004 Iwata + * + * 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 "sj3proxy.h" + +void +set_priv(const char *title) +{ + struct passwd *pw; + + if (!chroot_enable) + return; + + if ((pw = getpwnam(chuser_name)) == NULL) { + fprintf(stderr, "failed to get user \"%s\"\n", chuser_name); + fflush(stderr); + exit(255); + } + if (chroot(chroot_dir) != 0) { + fprintf(stderr, "can't chroot\n"); + fflush(stderr); + exit(255); + } + if (chdir("/") != 0) { + fprintf(stderr, "can't change directory '/'\n"); + fflush(stderr); + exit(255); + } + + if (title != NULL) + setproctitle("%s %s", pw->pw_name, title); + + /* + * Drop privileges and clear the group access list + */ + if (setgroups(1, &pw->pw_gid) == -1 || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) { + fprintf(stderr, "can't drop privileges\n"); + fflush(stderr); + exit(255); + } +} diff --git a/trunk/src/sj3proxy/sj3proxy.c b/trunk/src/sj3proxy/sj3proxy.c new file mode 100644 index 0000000..ef5262f --- /dev/null +++ b/trunk/src/sj3proxy/sj3proxy.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2004 Iwata + * + * 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 +#include +#include +#include +#include +#include "sys-queue.h" + +#include +#include +#include + +#include "Const.h" +#include "sj3proxy.h" +#include "sj3lua.h" +#include "atomicio.h" + +int chroot_enable = -1; +char address_family_str[256]; +int address_family = AF_UNSPEC; +char chuser_name[BUFSIZ]; +char chroot_dir[MAXPATHLEN]; +char socket_file[MAXPATHLEN]; +char host_name[NI_MAXHOST]; +char service_name[NI_MAXSERV]; + +struct listen_addr { + TAILQ_ENTRY(listen_addr) entry; + struct sockaddr_storage sa; + int fd; +} *listen_addrs_ptr; +TAILQ_HEAD(listen_addrs, listen_addr) listen_addrs; + +static void +close_listen_socks(void) +{ + struct listen_addr *np = listen_addrs_ptr; + + while ((np = TAILQ_FIRST(&listen_addrs)) != NULL) { + close(np->fd); + TAILQ_REMOVE(&listen_addrs, np, entry); + } +} + +/* + * SIGCHLD handler. This is called whenever a child dies. This will then + * reap any zombies left by exited children. + */ +static void +main_sigchld_handler(int sig) +{ + int save_errno = errno; + pid_t pid; + int status; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || + (pid < 0 && errno == EINTR)) + ; + + signal(SIGCHLD, main_sigchld_handler); + errno = save_errno; +} + +static void +readwrite(int inet_fd) +{ + struct sockaddr_un sunix; + int sj3_fd; + char buf[BUFSIZ]; + struct pollfd pfd[2]; + int nfds; + ssize_t readlen; + + if (access(socket_file, R_OK | W_OK) == -1) { + fprintf(stderr, "Can't find AF_UNIX socket\n"); + return; + } + + memset((char *)&sunix, 0, sizeof(sunix)); + sunix.sun_family = AF_UNIX; + strlcpy(sunix.sun_path, socket_file, sizeof(sunix.sun_path)); + + if ((sj3_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + fprintf(stderr, "Can't create AF_UNIX socket\n"); + return; + } + fcntl(sj3_fd, F_SETFD, 1); + if (connect(sj3_fd, (struct sockaddr *)&sunix, SUN_LEN(&sunix)) < 0) { + fprintf(stderr, "Can't connect AF_UNIX socket\n"); + close(sj3_fd); + return; + } + + pfd[0].fd = inet_fd; + pfd[0].events = POLLIN; + + pfd[1].fd = sj3_fd; + pfd[1].events = POLLIN; + + for ( ; ; ){ + if ((nfds = poll(pfd, 2, -1)) < 0) { + close(inet_fd); + close(sj3_fd); + fprintf(stderr, "Polling Error"); + return; + } + + if (nfds == 0) + return; + + if (pfd[0].revents & POLLIN) { + memset(buf, 0, sizeof(buf)); + if ((readlen = read(inet_fd, buf, sizeof(buf))) == -1) { + close(sj3_fd); + return; + } else if (readlen == 0) { + shutdown(inet_fd, SHUT_RD); + return; + } else { + if (atomicio(vwrite, sj3_fd, buf, readlen) != readlen) + return; + } + } + if (pfd[1].revents & POLLIN) { + memset(buf, 0, sizeof(buf)); + if ((readlen = read(sj3_fd, buf, BUFSIZ)) == -1) { + close(sj3_fd); + return; + } else if (readlen == 0) { + shutdown(inet_fd, SHUT_WR); + return; + } else { + if (atomicio(vwrite, inet_fd, buf, readlen) != readlen) + return; + } + } + } +} + +static int +set_server(lua_State *lstate) +{ + if (!sj3lua_check_table(lstate)) + return 0; + lua2sj_string(lstate, "user", 1, SJ3OWNER, chuser_name, sizeof(chuser_name)); + lua2sj_boolean(lstate, "chroot", 1, CHROOTFLAG, &chroot_enable); + lua2sj_string(lstate, "chroot_dir", 1, SOCKDIR, chroot_dir, sizeof(chroot_dir)); + lua2sj_string(lstate, "socket_file", 1, SOCKETFILE, socket_file, sizeof(socket_file)); + lua2sj_string(lstate, "host_name", 1, LOCALHOST, host_name, sizeof(host_name)); + lua2sj_string(lstate, "address_famiy", 1, ADDRESSFAMILY, address_family_str, sizeof(address_family_str)); + lua2sj_string(lstate, "service_name", 1, PORTNUMBER, service_name, sizeof(service_name)); + + return 0; +} + +static int +get_server(lua_State *lstate) +{ + sj2lua_string(lstate, "user", chuser_name); + sj2lua_boolean(lstate, "chroot", chroot_enable); + sj2lua_string(lstate, "chroot_dir", chroot_dir); + sj2lua_string(lstate, "socket_file", socket_file); + sj2lua_string(lstate, "host_name", host_name); + sj2lua_string(lstate, "address_famiy", address_family_str); + sj2lua_string(lstate, "service_name", service_name); + + return 1; +} + +int +main(int argc, char *argv[]) +{ + struct sockaddr *sa; + struct addrinfo hints; + struct addrinfo *res, *res0; + int listen_sock, maxfd; + socklen_t fromlen; + int inet_fd = -1; + int error; + u_int8_t salen; + char ntop[NI_MAXHOST], strport[NI_MAXSERV]; + int fdsetsz; + int on = 1; + fd_set *fdset; + struct sockaddr_storage from; + int pid; + int errflg = 0; + int c; + int daemon_disable = 0; + lua_State *lua_state = NULL; + int opt_inet4 = 0, opt_inet6 = 0; + + if ((lua_state = luaL_newstate()) == NULL) { + fprintf(stderr, "Can't setup lua"); + exit(1); + } + + luaL_openlibs(lua_state); + + /* sj3.functions */ + lua_newtable(lua_state); + set_luafunction(lua_state, "set_server", set_server); + set_luafunction(lua_state, "get_server", get_server); + lua_setglobal(lua_state, "sj3proxy"); + + if (luaL_dofile(lua_state, SJ3PROXYCFG) != 0) { + fprintf(stderr, "%s\n", lua_tostring(lua_state, -1)); + exit(255); + } + + while ((c = getopt(argc, argv, "46d")) != EOF) { + switch (c) { + case '4': + opt_inet4 = 1; + break; + case '6': + opt_inet6 = 1; + break; + case 'd': + daemon_disable = 1; + break; + case '?': + default: + errflg++; + break; + } + } + + if (errflg || optind < argc) { + fprintf(stderr, "Usage: sj3_proxy [-46d]\n"); + exit(1); + } + + if (strcmp(address_family_str, "unspec") == 0) + address_family = AF_UNSPEC; + if (opt_inet4 || strcmp(address_family_str, "inet") == 0) + address_family = AF_INET; + else if (opt_inet6 || strcmp(address_family_str, "inet6") == 0) + address_family = AF_INET6; + + if (!daemon_disable) + daemon(0, 1); + + + TAILQ_INIT(&listen_addrs); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = address_family; + hints.ai_flags = AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + + error = getaddrinfo(host_name, service_name, &hints, &res); + if (error) { + perror(gai_strerror(error)); + exit(1); + } + + res0 = res; + + for ( ; res; res = res->ai_next) { + sa = res->ai_addr; + salen = res->ai_addrlen; + + if (res->ai_family != AF_INET && res->ai_family != AF_INET6) + continue; + + if (getnameinfo(sa, salen, + ntop, sizeof(ntop), strport, sizeof(strport), + NI_NUMERICHOST|NI_NUMERICSERV) != 0) { + fprintf(stderr, "getnameinfo failed\n"); + continue; + } + /* Create socket for listening. */ + listen_sock = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (listen_sock < 0) { + /* kernel may not support ipv6 */ + fprintf(stderr, "socket: %.100s\n", strerror(errno)); + continue; + } + + /* + * Set socket options. + * Allow local port reuse in TIME_WAIT. + */ + if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, + &on, sizeof(on)) == -1) + fprintf(stderr, "setsockopt SO_REUSEADDR: %s\n", strerror(errno)); + + if (bind(listen_sock, sa, salen) < 0) { + fprintf(stderr, "Bind to port %s on %s failed: %.200s.\n", + strport, ntop, strerror(errno)); + close(listen_sock); + continue; + } + + /* Start listening on the port. */ + if (listen(listen_sock, 127) < 0) { + fprintf(stderr, "listen: %.100s\n", strerror(errno)); + exit(1); + } + + if ((listen_addrs_ptr = calloc(1, sizeof(struct listen_addr))) == + NULL) { + fprintf(stderr, "setup_listeners calloc"); + exit(1); + } + + memcpy(&listen_addrs_ptr->sa, sa, SA_LEN(sa)); + listen_addrs_ptr->fd = listen_sock; + TAILQ_INSERT_TAIL(&listen_addrs, listen_addrs_ptr, entry); + } + + freeaddrinfo(res0); + + /* drop privilege */ + set_priv(NULL); + + /* Arrange SIGCHLD to be caught. */ + signal(SIGCHLD, main_sigchld_handler); + + /* setup fd set for listen */ + fdset = NULL; + maxfd = 0; + TAILQ_FOREACH(listen_addrs_ptr, &listen_addrs, entry) { + if (listen_addrs_ptr->fd > maxfd) + maxfd = listen_addrs_ptr->fd; + } + + /* + * Stay listening for connections until the system crashes or + * the daemon is killed with a signal. + */ + for ( ; ; ) { + int ret; + + if (fdset != NULL) + free(fdset); + fdsetsz = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask); + fdset = (fd_set *)malloc(fdsetsz); + memset(fdset, 0, fdsetsz); + + TAILQ_FOREACH(listen_addrs_ptr, &listen_addrs, entry) + FD_SET(listen_addrs_ptr->fd, fdset); + + /* Wait in select until there is a connection. */ + ret = select(maxfd + 1, fdset, NULL, NULL, NULL); + if (ret < 0 && errno != EINTR) + fprintf(stderr, "select: %.100s\n", strerror(errno)); + if (ret < 0) + continue; + TAILQ_FOREACH(listen_addrs_ptr, &listen_addrs, entry) { + if (!FD_ISSET(listen_addrs_ptr->fd, fdset)) + continue; + fromlen = sizeof(from); + inet_fd = accept(listen_addrs_ptr->fd, (struct sockaddr *)&from, + &fromlen); + if (inet_fd < 0) { + if (errno != EINTR && errno != EWOULDBLOCK) + fprintf(stderr, "accept: %.100s\n", strerror(errno)); + continue; + } + /* + * Normal production daemon. Fork, and have + * the child process the connection. The + * parent continues listening. + */ + if ((pid = fork()) == 0) { + /* + * Child. Close the listening and max_startup + * sockets. Start using the accepted socket. + * Reinitialize logging (since our pid has + * changed). We break out of the loop to handle + * the connection. + */ + close_listen_socks(); + break; + } + /* Parent. Stay in the loop. */ + if (pid < 0) { + fprintf(stderr, "fork: %.100s\n", strerror(errno)); + exit(1); + } + + /* Close the new socket (the child is now taking care of it). */ + close(inet_fd); + } + if (TAILQ_EMPTY(&listen_addrs)) + break; + } + + readwrite(inet_fd); + + close(inet_fd); + close_listen_socks(); + + _exit(0); +} diff --git a/trunk/src/sj3proxy/sj3proxy.h b/trunk/src/sj3proxy/sj3proxy.h new file mode 100644 index 0000000..e47a27a --- /dev/null +++ b/trunk/src/sj3proxy/sj3proxy.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004 Iwata + * + * 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. + */ + +#ifndef SJ3PROXY_H +#define SJ3PROXY_H + +#include +#include +#include + +extern int chroot_enable; +extern char address_family_str[256]; +extern int address_family; +extern char chuser_name[BUFSIZ]; +extern char chroot_dir[MAXPATHLEN]; +extern char socket_file[MAXPATHLEN]; +extern char host_name[NI_MAXHOST]; +extern char service_name[NI_MAXSERV]; + +void set_priv(const char *); + +#endif + diff --git a/trunk/src/sj3proxy/sj3proxy.lua.example.in b/trunk/src/sj3proxy/sj3proxy.lua.example.in new file mode 100644 index 0000000..f12cfda --- /dev/null +++ b/trunk/src/sj3proxy/sj3proxy.lua.example.in @@ -0,0 +1,49 @@ +--[[ -- -*- lua -*- + Copyright (c) 2004 Iwata + + 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. +--]] + +local prefix = "%%SJ3VARDIR%%" + +sj3proxy.set_server { + -- user: String + -- run as user name + user = "%%SJ3OWNER%%", + + -- chroot: Boolean + -- sj3serv is chrooted or not + chroot = true, + + -- chroot_dir: String + -- chrooted path + chroot_dir = prefix .. "/run", + + -- socket_file: String + -- unix domain socket file name + -- Note: this file is opened after chroot + socket_file = "/sj3serv.socket", + + -- address_famiy: String (unspec or inet4 or inet6) + -- listening address family + address_famiy = "unspec", + + -- listen: String + -- listening address + listen = "localhost", + + -- port: String + -- listening service name + port = "3086", +} + diff --git a/trunk/src/sj3serv/execute.c b/trunk/src/sj3serv/execute.c index 1d008e0..e2e1d7c 100644 --- a/trunk/src/sj3serv/execute.c +++ b/trunk/src/sj3serv/execute.c @@ -204,13 +204,12 @@ exec_connect() if (getsockname(cur_client->fd, &addr, &len) < 0) perror("getsockname"); - if (addr.sa_family == AF_UNIX) { + if (strict_auth_enable) { getpeereid(cur_client->fd, &euid, &egid); if (ugid.uid != euid || ugid.gid != egid) { longjmp(error_ret, SJ3_NotAllowedUser); } } - cur_cli -> uid = ugid.uid; } else longjmp(error_ret, SJ3_NotAllowedUser); diff --git a/trunk/src/sj3serv/setup.c b/trunk/src/sj3serv/setup.c index 8b7a240..08b2148 100644 --- a/trunk/src/sj3serv/setup.c +++ b/trunk/src/sj3serv/setup.c @@ -80,6 +80,8 @@ char chuser_name[BUFSIZ]; int chroot_enable = -1; char chroot_dir[MAXPATHLEN]; +int strict_auth_enable = -1; + char log_file[MAXPATHLEN]; char debug_file[MAXPATHLEN]; @@ -115,11 +117,12 @@ set_server(lua_State *lstate) { if (!sj3lua_check_table(lstate)) return 0; - lua2sj_integer(lstate, "max_client", 1, MAXCLIENTNUM, &max_client); - lua2sj_string(lstate, "dict_dir", 1, DICTROOTDIR, dict_dir, sizeof(dict_dir)); - lua2sj_string(lstate, "user", 1, SJ3OWNER, chuser_name, sizeof(chuser_name)); - lua2sj_boolean(lstate, "chroot", 1, CHROOTFLAG, &chroot_enable); - lua2sj_string(lstate, "chroot_dir", 1, CHROOTDIR, chroot_dir, sizeof(dict_dir)); + lua2sj_integer(lstate, "max_client", 1, MAXCLIENTNUM, &max_client); + lua2sj_string(lstate, "dict_dir", 1, DICTROOTDIR, dict_dir, sizeof(dict_dir)); + lua2sj_string(lstate, "user", 1, SJ3OWNER, chuser_name, sizeof(chuser_name)); + lua2sj_boolean(lstate, "chroot", 1, CHROOTFLAG, &chroot_enable); + lua2sj_string(lstate, "chroot_dir", 1, CHROOTDIR, chroot_dir, sizeof(dict_dir)); + lua2sj_boolean(lstate, "strict_auth", 1, STRICTAUTHFLAG, &strict_auth_enable); return 0; } @@ -264,14 +267,6 @@ get_error(lua_State *lstate) return 0; } -void -set_luafunction(lua_State *lstate, char *name, lua_CFunction fun) -{ - lua_pushstring(lstate, name); - lua_pushcfunction(lstate, fun); - lua_settable(lstate, -3); -} - void read_runcmd() { diff --git a/trunk/src/sj3serv/sj3serv.h b/trunk/src/sj3serv/sj3serv.h index f3c7dbf..b928554 100644 --- a/trunk/src/sj3serv/sj3serv.h +++ b/trunk/src/sj3serv/sj3serv.h @@ -118,6 +118,7 @@ extern char pid_file[MAXPATHLEN]; extern char chuser_name[BUFSIZ]; extern int chroot_enable; extern char chroot_dir[MAXPATHLEN]; +extern int strict_auth_enable; extern char domain_socket_name[MAXPATHLEN]; extern char dict_dir[MAXPATHLEN]; extern char dict_file[FILENAME_MAX]; diff --git a/trunk/src/sj3serv/sj3serv.lua.example.in b/trunk/src/sj3serv/sj3serv.lua.example.in index 5e21791..92eda10 100644 --- a/trunk/src/sj3serv/sj3serv.lua.example.in +++ b/trunk/src/sj3serv/sj3serv.lua.example.in @@ -37,6 +37,11 @@ sj3.set_server { -- dictionary name -- Note: this directory is opened after chroot dict_dir = "/spool/sj3", + + -- strict_auth: Boolean + -- check always peer userid for security. + -- Note: if you want to run sj3serv with sj3proxy, set false + strict_auth = true, } sj3.set_domain {