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