chiark / gitweb /
Various nips and tucks.
[tripe] / tripe.c
1 /* -*-c-*-
2  *
3  * $Id: tripe.c,v 1.9 2003/04/15 14:11:09 mdw Exp $
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 $
32  * Revision 1.9  2003/04/15 14:11:09  mdw
33  * Rationalize the behaviour of the `-G' and `-U' options.
34  *
35  * Revision 1.8  2002/01/13 17:28:29  mdw
36  * Don't turn tracing on if tracing is turned off (!).
37  *
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  *
41  * Revision 1.6  2001/06/19 22:08:37  mdw
42  * Moved buffers to peer.c.
43  *
44  * Revision 1.5  2001/02/16 21:43:12  mdw
45  * Provide a more helpful usage message.
46  *
47  * Revision 1.4  2001/02/16 21:41:31  mdw
48  * Add a new buffer.
49  *
50  * Revision 1.3  2001/02/04 17:10:40  mdw
51  * Remove a debugging @abort@ call.
52  *
53  * Revision 1.2  2001/02/03 22:33:00  mdw
54  * Stuff more randomness into the pool in the interval timer.
55  *
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
67 sel_state sel;
68
69 /*----- Static variables --------------------------------------------------*/
70
71 static 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
86 void interval(struct timeval *tv, void *v)
87 {
88   struct timeval tvv;
89   T( trace(T_PEER, "peer: interval timer"); )
90   rand_seed(RAND_GLOBAL, HASHSZ);
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
107 static void usage(FILE *fp)
108 {
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");
112 }
113
114 static void version(FILE *fp)
115 {
116   pquis(fp, "$, version " VERSION "\n");
117 }
118
119 static void help(FILE *fp)
120 {
121   version(fp);
122   fputc('\n', fp);
123   usage(fp);
124   fputs("\n\
125 Options:\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\
134 -u, --setuid=USER       Set uid to USER after initialization.\n\
135 -g, --setgid=GROUP      Set gid to GROUP after initialization.\n\
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\
140 " T( "\
141 -T, --trace=OPTIONS     Turn on tracing options.\n\
142 " ) "\
143 ", fp);
144 }
145
146 int 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]);
162   T( trace_on(stderr, 0); )
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': {
210         struct passwd *pw;
211         char *p;
212         unsigned long i = strtoul(optarg, &p, 0);
213         if (!*p)
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;
222       } break;
223       case 'G': {
224         struct group *gr;
225         char *p;
226         unsigned long i = strtoul(optarg, &p, 0);
227         if (!*p)
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;
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);
295   if (g != (gid_t)-1) {
296     if (setgid(g) || (getuid() == 0 && setgroups(1, &g))) {
297       die(EXIT_FAILURE, "couldn't setgid to %u: %s",
298           (unsigned)g, strerror(errno));
299     }
300   }
301   if (u != (uid_t)-1) {
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) {
310     if (u_daemon())
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));
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 -------------------------------------------------*/