chiark / gitweb /
Handle flags on challenge timers correctly to prevent confusing the event
[tripe] / tripe.c
CommitLineData
410c8acf 1/* -*-c-*-
2 *
767b36e2 3 * $Id: tripe.c,v 1.10 2003/05/16 12:09:03 mdw Exp $
410c8acf 4 *
5 * Main program
6 *
7 * (c) 2001 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Trivial IP Encryption (TrIPE).
13 *
14 * TrIPE is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * TrIPE is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with TrIPE; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: tripe.c,v $
767b36e2 32 * Revision 1.10 2003/05/16 12:09:03 mdw
33 * Allow binding to a chosen address.
34 *
b303b584 35 * Revision 1.9 2003/04/15 14:11:09 mdw
36 * Rationalize the behaviour of the `-G' and `-U' options.
37 *
d360f042 38 * Revision 1.8 2002/01/13 17:28:29 mdw
39 * Don't turn tracing on if tracing is turned off (!).
40 *
c5a2ea9b 41 * Revision 1.7 2002/01/13 17:14:05 mdw
42 * Don't include the tracing option in the help if not compiled in.
43 *
2666d7dd 44 * Revision 1.6 2001/06/19 22:08:37 mdw
45 * Moved buffers to peer.c.
46 *
680bfcf4 47 * Revision 1.5 2001/02/16 21:43:12 mdw
48 * Provide a more helpful usage message.
49 *
37852359 50 * Revision 1.4 2001/02/16 21:41:31 mdw
51 * Add a new buffer.
52 *
efd6c9e3 53 * Revision 1.3 2001/02/04 17:10:40 mdw
54 * Remove a debugging @abort@ call.
55 *
e31c0b14 56 * Revision 1.2 2001/02/03 22:33:00 mdw
57 * Stuff more randomness into the pool in the interval timer.
58 *
410c8acf 59 * Revision 1.1 2001/02/03 20:26:37 mdw
60 * Initial checkin.
61 *
62 */
63
64/*----- Header files ------------------------------------------------------*/
65
66#include "tripe.h"
67
68/*----- Global variables --------------------------------------------------*/
69
70sel_state sel;
410c8acf 71
72/*----- Static variables --------------------------------------------------*/
73
74static sel_timer it;
75#define T_INTERVAL MIN(1)
76
77/*----- Main code ---------------------------------------------------------*/
78
79/* --- @interval@ --- *
80 *
81 * Arguments: @struct timeval *tv@ = time when called
82 * @void *v@ = boring pointer
83 *
84 * Returns: ---
85 *
86 * Use: Called periodically to do housekeeping tasks.
87 */
88
89void interval(struct timeval *tv, void *v)
90{
91 struct timeval tvv;
92 T( trace(T_PEER, "peer: interval timer"); )
37852359 93 rand_seed(RAND_GLOBAL, HASHSZ);
410c8acf 94 p_interval();
95 tvv = *tv;
96 tvv.tv_sec += T_INTERVAL;
97 sel_addtimer(&sel, &it, &tvv, interval, v);
98}
99
100/* --- @main@ --- *
101 *
102 * Arguments: @int argc@ = number of command line arguments
103 * @char *argv[]@ = vector of arguments
104 *
105 * Returns: Zero if OK, nonzero on error.
106 *
107 * Use: Main program. Provides a simple VPN.
108 */
109
110static void usage(FILE *fp)
111{
b303b584 112 pquis(fp, "Usage: $ [-D] [-d dir] [-p port] [-U user] [-G group]\n\
113 [-k priv-keyring] [-K pub-keyring] [-t key-tag]\n\
114 [-a socket] [-T trace-opts]\n");
410c8acf 115}
116
117static void version(FILE *fp)
118{
119 pquis(fp, "$, version " VERSION "\n");
120}
121
122static void help(FILE *fp)
123{
124 version(fp);
125 fputc('\n', fp);
126 usage(fp);
127 fputs("\n\
128Options:\n\
129\n\
130-h, --help Display this help text.\n\
131-v, --version Display version number.\n\
132-u, --usage Display pointless usage message.\n\
133\n\
134-D, --daemon Run in the background.\n\
135-d, --directory=DIR Switch to directory DIR (default $TRIPEDIR).\n\
136-p, --port=PORT Select UDP port to listen to.\n\
b303b584 137-u, --setuid=USER Set uid to USER after initialization.\n\
138-g, --setgid=GROUP Set gid to GROUP after initialization.\n\
410c8acf 139-k, --priv-keyring=FILE Get private key from FILE.\n\
140-K, --pub-keyring=FILE Get public keys from FILE.\n\
141-t, --tag=KEYTAG Use private key labelled TAG.\n\
142-a, --admin-socket=FILE Use FILE as the adminstration socket.\n\
c5a2ea9b 143" T( "\
410c8acf 144-T, --trace=OPTIONS Turn on tracing options.\n\
c5a2ea9b 145" ) "\
410c8acf 146", fp);
147}
148
149int main(int argc, char *argv[])
150{
151 const char *kr_priv = "keyring", *kr_pub = "keyring.pub";
152 const char *tag_priv = "tripe-dh";
153 const char *csock = "tripesock";
154 const char *dir = "/var/lib/tripe";
155 const char *p;
156 unsigned port = 0;
767b36e2 157 struct in_addr baddr = { INADDR_ANY };
410c8acf 158 unsigned f = 0;
159 uid_t u = -1;
160 gid_t g = -1;
161
162#define f_bogus 1u
163#define f_daemon 2u
164
165 ego(argv[0]);
d360f042 166 T( trace_on(stderr, 0); )
410c8acf 167
168 if ((p = getenv("TRIPEDIR")) != 0)
169 dir = p;
170
171 for (;;) {
172 static const struct option opts[] = {
173 { "help", 0, 0, 'h' },
174 { "version", 0, 0, 'v' },
175 { "usage", 0, 0, 'u' },
176
177 { "daemon", 0, 0, 'D' },
178 { "uid", OPTF_ARGREQ, 0, 'U' },
179 { "setuid", OPTF_ARGREQ, 0, 'U' },
180 { "gid", OPTF_ARGREQ, 0, 'G' },
181 { "setgid", OPTF_ARGREQ, 0, 'G' },
767b36e2 182 { "bind-address", OPTF_ARGREQ, 0, 'b' },
410c8acf 183 { "port", OPTF_ARGREQ, 0, 'p' },
184 { "directory", OPTF_ARGREQ, 0, 'd' },
185 { "priv-keyring", OPTF_ARGREQ, 0, 'k' },
186 { "pub-keyring", OPTF_ARGREQ, 0, 'K' },
187 { "tag", OPTF_ARGREQ, 0, 't' },
188 { "admin-socket", OPTF_ARGREQ, 0, 'a' },
189#ifndef NTRACE
190 { "trace", OPTF_ARGREQ, 0, 'T' },
191#endif
192
193 { 0, 0, 0, 0 }
194 };
195
767b36e2 196 int i = mdwopt(argc, argv, "hvu DU:G: b:p:d:k:K:t:a:" T("T:"),
410c8acf 197 opts, 0, 0, 0);
198 if (i < 0)
199 break;
200 switch (i) {
201 case 'h':
202 help(stdout);
203 exit(0);
204 case 'v':
205 version(stdout);
206 exit(0);
207 case 'u':
208 usage(stdout);
209 exit(0);
210
211 case 'D':
212 f |= f_daemon;
213 break;
214 case 'U': {
b303b584 215 struct passwd *pw;
410c8acf 216 char *p;
217 unsigned long i = strtoul(optarg, &p, 0);
218 if (!*p)
b303b584 219 pw = getpwuid(i);
220 else
221 pw = getpwnam(optarg);
222 if (!pw)
223 die(EXIT_FAILURE, "user `%s' not found", optarg);
224 u = pw->pw_uid;
225 if (g == -1)
226 g = pw->pw_gid;
410c8acf 227 } break;
228 case 'G': {
b303b584 229 struct group *gr;
410c8acf 230 char *p;
231 unsigned long i = strtoul(optarg, &p, 0);
232 if (!*p)
b303b584 233 gr = getgrgid(i);
234 else
235 gr = getgrnam(optarg);
236 if (!gr)
237 die(EXIT_FAILURE, "group `%s' not found", optarg);
238 g = gr->gr_gid;
410c8acf 239 } break;
767b36e2 240
241 case 'b': {
242 struct hostent *h = gethostbyname(optarg);
243 if (!h)
244 die(EXIT_FAILURE, "unknown host name `%s'", optarg);
245 memcpy(&baddr, h->h_addr, sizeof(struct in_addr));
246 } break;
410c8acf 247 case 'p': {
248 char *p;
249 unsigned long i = strtoul(optarg, &p, 0);
250 if (*p) {
251 struct servent *s = getservbyname(optarg, "udp");
252 if (!s)
253 die(EXIT_FAILURE, "unknown service name `%s'", optarg);
254 i = ntohs(s->s_port);
255 }
256 if (i == 0 || i >= 65536)
257 die(EXIT_FAILURE, "bad port number %lu", i);
258 port = i;
259 } break;
260 case 'd':
261 dir = optarg;
262 break;
263 case 'k':
264 kr_priv = optarg;
265 break;
266 case 'K':
267 kr_pub = optarg;
268 break;
269 case 'a':
270 csock = optarg;
271 break;
272 case 't':
273 tag_priv = optarg;
274 break;
275#ifndef NTRACE
276 case 'T':
277 tr_flags = traceopt(tr_opts, optarg, tr_flags, 0);
278 trace_level(tr_flags);
279 break;
280#endif
281 default:
282 f |= f_bogus;
283 break;
284 }
285 }
286
287 if (optind < argc || (f & f_bogus)) {
288 usage(stderr);
289 exit(EXIT_FAILURE);
290 }
291
292 if (chdir(dir)) {
293 die(EXIT_FAILURE, "can't set current directory to `%s': %s",
294 dir, strerror(errno));
295 }
296
297 sel_init(&sel);
298 sig_init(&sel);
299 rand_noisesrc(RAND_GLOBAL, &noise_source);
300 rand_seed(RAND_GLOBAL, RMD160_HASHSZ);
301 signal(SIGPIPE, SIG_IGN);
302 tun_init();
767b36e2 303 p_init(baddr, port);
410c8acf 304 if (!(f & f_daemon))
305 a_create(STDIN_FILENO, STDOUT_FILENO);
b303b584 306 if (g != (gid_t)-1) {
307 if (setgid(g) || (getuid() == 0 && setgroups(1, &g))) {
410c8acf 308 die(EXIT_FAILURE, "couldn't setgid to %u: %s",
309 (unsigned)g, strerror(errno));
310 }
311 }
b303b584 312 if (u != (uid_t)-1) {
410c8acf 313 if (setuid(u)) {
314 die(EXIT_FAILURE, "couldn't setuid to %u: %s",
315 (unsigned)u, strerror(errno));
316 }
317 }
318 km_init(kr_priv, kr_pub, tag_priv);
319 a_init(csock);
320 if (f & f_daemon) {
37852359 321 if (u_daemon())
410c8acf 322 die(EXIT_FAILURE, "couldn't become a daemon: %s", strerror(errno));
323 a_daemon();
324 }
325
326 {
327 struct timeval tv;
328 tv.tv_sec = time(0) + T_INTERVAL;
329 tv.tv_usec = 0;
330 sel_addtimer(&sel, &it, &tv, interval, 0);
331 }
332
333 {
334 int selerr = 0;
335 for (;;) {
336 if (!sel_select(&sel))
337 selerr = 0;
338 else if (errno != EINTR && errno != EAGAIN) {
339 a_warn("select failed: %s", strerror(errno));
410c8acf 340 selerr++;
341 if (selerr > 8) {
342 a_warn("too many select errors: bailing out");
343 a_quit();
344 }
345 }
346 }
347 }
348
349 return (0);
350}
351
352/*----- That's all, folks -------------------------------------------------*/