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