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