X-Git-Url: https://git.distorted.org.uk/~mdw/tripe/blobdiff_plain/165efde7f48706c6b4680aa537b3467e70d6a11d..c9aded9f1c5c6eea294bf85e5e34efb9f52138c6:/server/tripe.c diff --git a/server/tripe.c b/server/tripe.c index f46e232c..b4f4cc97 100644 --- a/server/tripe.c +++ b/server/tripe.c @@ -1,7 +1,5 @@ /* -*-c-*- * - * $Id$ - * * Main program * * (c) 2001 Straylight/Edgeware @@ -11,19 +9,18 @@ * * This file is part of Trivial IP Encryption (TrIPE). * - * TrIPE is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * TrIPE is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your + * option) any later version. * - * TrIPE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * TrIPE is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. * * You should have received a copy of the GNU General Public License - * along with TrIPE; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with TrIPE. If not, see . */ /*----- Header files ------------------------------------------------------*/ @@ -39,7 +36,10 @@ sel_state sel; static sel_timer it; #define T_INTERVAL MIN(1) -/*----- Main code ---------------------------------------------------------*/ +static unsigned iv_nreasons = 0; +static struct timeval iv_next = { 0, 0 }; + +/*----- The interval timer ------------------------------------------------*/ /* --- @interval@ --- * * @@ -53,32 +53,104 @@ static sel_timer it; static void interval(struct timeval *tv, void *v) { - struct timeval tvv; T( trace(T_PEER, "peer: interval timer"); ) + iv_next = *tv; rand_seed(RAND_GLOBAL, MAXHASHSZ); p_interval(); - tvv = *tv; - tvv.tv_sec += T_INTERVAL; - sel_addtimer(&sel, &it, &tvv, interval, v); + iv_next.tv_sec += T_INTERVAL; + sel_addtimer(&sel, &it, &iv_next, interval, v); } -/* --- @mystrieq@ --- * +/* --- @iv_addreason@ --- * * - * Arguments: @const char *x, *y@ = two strings + * Arguments: --- * - * Returns: True if @x@ and @y are equal, up to case. + * Returns: --- + * + * Use: Adds an `interval timer reason'; if there are no others, the + * interval timer is engaged. */ -int mystrieq(const char *x, const char *y) +void iv_addreason(void) { + struct timeval tv; + + if (!iv_nreasons) { + gettimeofday(&tv, 0); + if (TV_CMP(&tv, >=, &iv_next)) interval(&tv, 0); + else sel_addtimer(&sel, &it, &iv_next, interval, 0); + } + iv_nreasons++; +} + +/* --- @iv_rmreason@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Removes an interval timer reason; if there are none left, the + * interval timer is disengaged. + */ + +void iv_rmreason(void) +{ + assert(iv_nreasons); iv_nreasons--; + if (!iv_nreasons) sel_rmtimer(&it); +} + +/*----- The main loop -----------------------------------------------------*/ + +/* --- @lp_init@ --- * + * + * Arguments: --- + * + * Returns: --- + * + * Use: Initializes the main loop. Most importantly, this sets up + * the select multiplexor that everything else hooks onto. + */ + +void lp_init(void) +{ + rand_noisesrc(RAND_GLOBAL, &noise_source); + rand_seed(RAND_GLOBAL, MAXHASHSZ); + gettimeofday(&iv_next, 0); iv_next.tv_sec += T_INTERVAL; + signal(SIGPIPE, SIG_IGN); + sel_init(&sel); + sig_init(&sel); +} + +/* --- @lp_run@ --- * + * + * Arguments: --- + * + * Returns: Zero on successful termination; @-1@ if things went wrong. + * + * Use: Cranks the main loop until it should be cranked no more. + */ + +int lp_run(void) +{ + int nerr = 0; + for (;;) { - if (!*x && !*y) return (1); - if (tolower((unsigned char)*x) != tolower((unsigned char)*y)) - return (0); - x++; y++; + a_preselect(); + if (!sel_select(&sel)) nerr = 0; + else if (errno != EINTR && errno != EAGAIN) { + a_warn("SERVER", "select-error", "?ERRNO", A_END); + nerr++; + if (nerr > 8) { + a_warn("ABORT", "repeated-select-errors", A_END); + abort(); + } + } } + return (0); } +/*----- Main code ---------------------------------------------------------*/ + /* --- @main@ --- * * * Arguments: @int argc@ = number of command line arguments @@ -91,8 +163,8 @@ int mystrieq(const char *x, const char *y) static void usage(FILE *fp) { - pquis(fp, "Usage: $ [-D] [-d DIR] [-b ADDR] [-p PORT] [-n TUNNEL]\n\ - [-U USER] [-G GROUP] [-a SOCKET] [-T TRACE-OPTS]\n\ + pquis(fp, "Usage: $ [-DF] [-d DIR] [-b ADDR] [-p PORT] [-n TUNNEL]\n\ + [-U USER] [-G GROUP] [-a SOCKET] [-m MODE] [-T TRACE-OPTS]\n\ [-k PRIV-KEYRING] [-K PUB-KEYRING] [-t KEY-TAG]\n"); } @@ -111,7 +183,10 @@ Options:\n\ -u, --usage Display pointless usage message.\n\ --tunnels Display IP tunnel drivers and exit.\n\ \n\ +-4, --ipv4 Transport over IPv4 only.\n\ +-6, --ipv6 Transport over IPv6 only.\n\ -D, --daemon Run in the background.\n\ +-F, --foreground Quit when stdin reports end-of-file.\n\ -d, --directory=DIR Switch to directory DIR [default " CONFIGDIR "].\n\ -b, --bind-address=ADDR Bind UDP socket to this IP ADDR.\n\ -p, --port=PORT Select UDP port to listen to " @@ -123,6 +198,7 @@ Options:\n\ -K, --pub-keyring=FILE Get public keys from FILE.\n\ -t, --tag=KEYTAG Use private key labelled TAG.\n\ -a, --admin-socket=FILE Use FILE as the adminstration socket.\n\ +-m, --admin-perms=MODE Permissions to set on admin socket [default 600].\n\ " T( "\ -T, --trace=OPTIONS Turn on tracing options.\n\ " ) "\ @@ -132,21 +208,23 @@ Options:\n\ int main(int argc, char *argv[]) { const char *kr_priv = "keyring", *kr_pub = "keyring.pub"; - const char *tag_priv = "tripe-dh"; + const char *tag_priv = 0; const char *csock = SOCKETDIR "/tripesock"; + int csockmode = 0600; const char *dir = CONFIGDIR; const char *p; - unsigned port = TRIPE_PORT; - struct in_addr baddr = { INADDR_ANY }; + const char *bindhost = 0, *bindsvc = STR(TRIPE_PORT); + struct addrinfo aihint = { 0 }, *ailist; unsigned f = 0; int i; - int selerr = 0; - struct timeval tv; + int err; + unsigned af; uid_t u = -1; gid_t g = -1; #define f_bogus 1u #define f_daemon 2u +#define f_foreground 4u ego(argv[0]); T( trace_on(stderr, 0); ) @@ -156,6 +234,7 @@ int main(int argc, char *argv[]) if ((p = getenv("TRIPESOCK")) != 0) csock = p; tun_default = tunnels[0]; + aihint.ai_family = AF_UNSPEC; for (;;) { static const struct option opts[] = { @@ -164,7 +243,10 @@ int main(int argc, char *argv[]) { "usage", 0, 0, 'u' }, { "tunnels", 0, 0, '0' }, + { "ipv4", 0, 0, '4' }, + { "ipv6", 0, 0, '6' }, { "daemon", 0, 0, 'D' }, + { "foreground", 0, 0, 'F' }, { "uid", OPTF_ARGREQ, 0, 'U' }, { "setuid", OPTF_ARGREQ, 0, 'U' }, { "gid", OPTF_ARGREQ, 0, 'G' }, @@ -177,6 +259,7 @@ int main(int argc, char *argv[]) { "pub-keyring", OPTF_ARGREQ, 0, 'K' }, { "tag", OPTF_ARGREQ, 0, 't' }, { "admin-socket", OPTF_ARGREQ, 0, 'a' }, + { "admin-perms", OPTF_ARGREQ, 0, 'm' }, #ifndef NTRACE { "trace", OPTF_ARGREQ, 0, 'T' }, #endif @@ -184,7 +267,7 @@ int main(int argc, char *argv[]) { 0, 0, 0, 0 } }; - i = mdwopt(argc, argv, "hvuDU:G:b:p:d:k:K:t:a:" T("T:"), + i = mdwopt(argc, argv, "hvu46DFU:G:b:n:p:d:k:K:t:a:m:" T("T:"), opts, 0, 0, 0); if (i < 0) break; @@ -199,55 +282,31 @@ int main(int argc, char *argv[]) usage(stdout); exit(0); + case '4': + aihint.ai_family = AF_INET; + break; + case '6': + aihint.ai_family = AF_INET6; + break; case 'D': f |= f_daemon; break; - case 'U': { - struct passwd *pw; - char *p; - unsigned long i = strtoul(optarg, &p, 0); - if (!*p) - pw = getpwuid(i); - else - pw = getpwnam(optarg); - if (!pw) - die(EXIT_FAILURE, "user `%s' not found", optarg); - u = pw->pw_uid; - if (g == -1) - g = pw->pw_gid; - } break; - case 'G': { - struct group *gr; - char *p; - unsigned long i = strtoul(optarg, &p, 0); - if (!*p) - gr = getgrgid(i); - else - gr = getgrnam(optarg); - if (!gr) - die(EXIT_FAILURE, "group `%s' not found", optarg); - g = gr->gr_gid; - } break; + case 'U': + u = u_getuser(optarg, &g); + break; + case 'G': + g = u_getgroup(optarg); + break; + case 'F': + f |= f_foreground; + break; - case 'b': { - struct hostent *h = gethostbyname(optarg); - if (!h) - die(EXIT_FAILURE, "unknown host name `%s'", optarg); - memcpy(&baddr, h->h_addr, sizeof(struct in_addr)); - } break; - case 'p': { - char *p; - unsigned long i = strtoul(optarg, &p, 0); - if (*p) { - struct servent *s = getservbyname(optarg, "udp"); - if (!s) - die(EXIT_FAILURE, "unknown service name `%s'", optarg); - i = ntohs(s->s_port); - } - if (i >= 65536) - die(EXIT_FAILURE, "bad port number %lu", i); - port = i; - } break; + case 'b': + bindhost = optarg; + break; + case 'p': + bindsvc = optarg; + break; case 'n': { int i; for (i = 0;; i++) { @@ -270,6 +329,11 @@ int main(int argc, char *argv[]) case 'a': csock = optarg; break; + case 'm': { + char *p; + csockmode = strtol(optarg, &p, 8); + if (*p) die(EXIT_FAILURE, "bad permissions: `%s'", optarg); + } break; case 't': tag_priv = optarg; break; @@ -295,65 +359,68 @@ int main(int argc, char *argv[]) usage(stderr); exit(EXIT_FAILURE); } + if (!(~f & (f_daemon | f_foreground))) + die(EXIT_FAILURE, "foreground operation for a daemon is silly"); + + aihint.ai_protocol = IPPROTO_UDP; + aihint.ai_socktype = SOCK_DGRAM; + aihint.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; + if ((err = getaddrinfo(bindhost, bindsvc, &aihint, &ailist)) != 0) { + die(EXIT_FAILURE, "couldn't resolve hostname %c%s%c, port `%s': %s", + bindhost ? '`' : '<', + bindhost ? bindhost : "nil", + bindhost ? '\'' : '>', + bindsvc, gai_strerror(err)); + } if (chdir(dir)) { die(EXIT_FAILURE, "can't set current directory to `%s': %s", dir, strerror(errno)); } - sel_init(&sel); - sig_init(&sel); - rand_noisesrc(RAND_GLOBAL, &noise_source); - rand_seed(RAND_GLOBAL, MAXHASHSZ); - signal(SIGPIPE, SIG_IGN); - for (i = 0; tunnels[i]; i++) - tunnels[i]->init(); - p_init(baddr, port); + lp_init(); + if (!(f & f_daemon)) { + af = AF_WARN; #ifndef NTRACE - a_create(STDIN_FILENO, STDOUT_FILENO, AF_TRACE | AF_WARN); -#else - a_create(STDIN_FILENO, STDOUT_FILENO, AF_WARN); + af |= AF_TRACE; #endif + if (f & f_foreground) + af |= AF_FOREGROUND; + a_create(STDIN_FILENO, STDOUT_FILENO, af); + a_switcherr(); } - if (g != (gid_t)-1) { - if (setgid(g) || (getuid() == 0 && setgroups(1, &g))) { - die(EXIT_FAILURE, "couldn't setgid to %u: %s", - (unsigned)g, strerror(errno)); - } - } - if (u != (uid_t)-1) { - if (setuid(u)) { - die(EXIT_FAILURE, "couldn't setuid to %u: %s", - (unsigned)u, strerror(errno)); + + p_init(); + for (i = 0; tunnels[i]; i++) + tunnels[i]->init(); + p_bind(ailist); freeaddrinfo(ailist); + + for (i = 0; tunnels[i]; i++) { + if (tunnels[i]->flags&TUNF_PRIVOPEN) { + ps_split(f & f_daemon); + break; } } + + a_init(); + a_signals(); + a_listen(csock, u, g, csockmode); + u_setugid(u, g); km_init(kr_priv, kr_pub, tag_priv); - a_init(csock); + kx_init(); if (f & f_daemon) { - if (daemonize()) - die(EXIT_FAILURE, "couldn't become a daemon: %s", strerror(errno)); + if (daemonize()) { + a_warn("SERVER", "daemon-error", "?ERRNO", A_END); + exit(EXIT_FAILURE); + } a_daemon(); + a_switcherr(); } - tv.tv_sec = time(0) + T_INTERVAL; - tv.tv_usec = 0; - sel_addtimer(&sel, &it, &tv, interval, 0); - - for (;;) { - a_preselect(); - if (!sel_select(&sel)) - selerr = 0; - else if (errno != EINTR && errno != EAGAIN) { - a_warn("SERVER", "select-error", "?ERRNO", A_END); - selerr++; - if (selerr > 8) { - a_warn("ABORT", "repeated-select-errors", A_END); - abort(); - } - } - } + iv_addreason(); + lp_run(); return (0); }