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