initscripts: Don't create tmp dirs for pluto anymore.
[people/teissler/ipfire-2.x.git] / src / misc-progs / ipsecctrl.c
CommitLineData
05207d69
MT
1/*
2 *
3 * File originally from the Smoothwall project
4 * (c) 2001 Smoothwall Team
5 *
05207d69
MT
6 */
7
8#include "libsmooth.h"
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <signal.h>
16#include "setuid.h"
17
5fd30232
MT
18/*
19 This module is responsible for start stop of the vpn system.
20
21 1) it allows AH & ESP to get in from interface where a vpn is mounted
69dcc425 22 The NAT traversal is used on the udp 4500 port.
5fd30232
MT
23
24 2) it starts the ipsec daemon
69dcc425
CS
25 The RED interface is a problem because it can be up or down a startup.
26 Then, the state change and it must not affect other VPN mounted on
27 other interface.
28 Unfortunatly, openswan 1 cannot do that correctly. It cannot use an
29 interface without restarting everything.
5fd30232
MT
30
31*/
32
05207d69 33void usage() {
69dcc425
CS
34 fprintf (stderr, "Usage:\n");
35 fprintf (stderr, "\tipsecctrl S [connectionkey]\n");
36 fprintf (stderr, "\tipsecctrl D [connectionkey]\n");
37 fprintf (stderr, "\tipsecctrl R\n");
db073a10 38 fprintf (stderr, "\tipsecctrl I\n");
69dcc425
CS
39 fprintf (stderr, "\t\tS : Start/Restart Connection\n");
40 fprintf (stderr, "\t\tD : Stop Connection\n");
41 fprintf (stderr, "\t\tR : Reload Certificates and Secrets\n");
db073a10 42 fprintf (stderr, "\t\tI : Print Statusinfo\n");
05207d69
MT
43}
44
5fd30232 45/*
69dcc425 46 ACCEPT the ipsec protocol ah, esp & udp (for nat traversal) on the specified interface
5fd30232
MT
47*/
48void open_physical (char *interface, int nat_traversal_port) {
69dcc425
CS
49 char str[STRING_SIZE];
50
51 // GRE ???
db073a10 52// sprintf(str, "/sbin/iptables -A " phystable " -p 47 -i %s -j ACCEPT", interface);
6652626c 53// safe_system(str);
69dcc425 54 // ESP
db073a10 55// sprintf(str, "/sbin/iptables -A " phystable " -p 50 -i %s -j ACCEPT", interface);
6652626c 56// safe_system(str);
69dcc425 57 // AH
db073a10 58// sprintf(str, "/sbin/iptables -A " phystable " -p 51 -i %s -j ACCEPT", interface);
6652626c 59// safe_system(str);
69dcc425 60 // IKE
1f324fd7 61
85cbc0a0 62 sprintf(str, "/sbin/iptables -D IPSECINPUT -p udp -i %s --dport 500 -j ACCEPT >/dev/null 2>&1", interface);
1f324fd7 63 safe_system(str);
85cbc0a0 64 sprintf(str, "/sbin/iptables -A IPSECINPUT -p udp -i %s --dport 500 -j ACCEPT", interface);
db073a10 65 safe_system(str);
69dcc425
CS
66
67 if (! nat_traversal_port)
68 return;
69
1f324fd7
AF
70 sprintf(str, "/sbin/iptables -D IPSECINPUT -p udp -i %s --dport %i -j ACCEPT >/dev/null 2>&1", interface, nat_traversal_port);
71 safe_system(str);
db073a10
AF
72 sprintf(str, "/sbin/iptables -A IPSECINPUT -p udp -i %s --dport %i -j ACCEPT", interface, nat_traversal_port);
73 safe_system(str);
5fd30232
MT
74}
75
76void ipsec_norules() {
69dcc425 77 /* clear input rules */
db073a10
AF
78 safe_system("/sbin/iptables -F IPSECINPUT");
79 safe_system("/sbin/iptables -F IPSECFORWARD");
80 safe_system("/sbin/iptables -F IPSECOUTPUT");
69dcc425 81
05207d69
MT
82}
83
5fd30232
MT
84/*
85 return values from the vpn config file or false if not 'on'
86*/
87int decode_line (char *s,
69dcc425
CS
88 char **key,
89 char **name,
90 char **type,
91 char **interface
92 ) {
93 int count = 0;
94 *key = NULL;
95 *name = NULL;
96 *type = NULL;
97
98 if (s[strlen(s) - 1] == '\n')
99 s[strlen(s) - 1] = '\0';
100
101 char *result = strsep(&s, ",");
102 while (result) {
103 if (count == 0)
104 *key = result;
105 if ((count == 1) && strcmp(result, "on") != 0)
106 return 0; // a disabled line
107 if (count == 2)
108 *name = result;
109 if (count == 4)
110 *type = result;
111 if (count == 27)
112 *interface = result;
113 count++;
114 result = strsep(&s, ",");
115 }
116
117 // check other syntax
118 if (! *name)
119 return 0;
120
121 if (strspn(*name, LETTERS_NUMBERS) != strlen(*name)) {
122 fprintf(stderr, "Bad connection name: %s\n", *name);
123 return 0;
124 }
125
126 if (! (strcmp(*type, "host") == 0 || strcmp(*type, "net") == 0)) {
127 fprintf(stderr, "Bad connection type: %s\n", *type);
128 return 0;
129 }
130
131 if (! (strcmp(*interface, "RED") == 0 || strcmp(*interface, "GREEN") == 0 ||
132 strcmp(*interface, "ORANGE") == 0 || strcmp(*interface, "BLUE") == 0)) {
133 fprintf(stderr, "Bad interface name: %s\n", *interface);
134 return 0;
135 }
136 //it's a valid & active line
137 return 1;
5fd30232
MT
138}
139
140/*
141 issue ipsec commmands to turn on connection 'name'
142*/
143void turn_connection_on (char *name, char *type) {
44b5666b 144/*
6e2ba31b
AF
145 Rename the connection and run ipsec update and rename it back to readd
146 a deleted connection. Because ipsec update ignores connection that have
147 not changed since last load.
44b5666b 148*/
6e2ba31b
AF
149 char command[STRING_SIZE];
150 memset(command, 0, STRING_SIZE);
151 snprintf(command, STRING_SIZE - 1,
152 "sed -i -e 's|^conn %s$|conn %s-renamed|g' /var/ipfire/vpn/ipsec.conf >/dev/null", name, name);
153 safe_system(command);
154
155 // Down and delete IKEv2 Tunnel before ipsec update
156 snprintf(command, STRING_SIZE - 1,
157 "/usr/sbin/ipsec stroke down %s >/dev/null", name);
158 safe_system(command);
159 snprintf(command, STRING_SIZE - 1,
160 "/usr/sbin/ipsec stroke delete %s >/dev/null", name);
161 safe_system(command);
162
163 safe_system("/etc/rc.d/init.d/ipsec update >/dev/null");
164
165 sleep(1);
166
167 // Back to original name
168 snprintf(command, STRING_SIZE - 1,
169 "sed -i -e 's|^conn %s-renamed$|conn %s|g' /var/ipfire/vpn/ipsec.conf >/dev/null", name, name);
170 safe_system(command);
171
172 // Down and delete IKEv2 Tunnel before ipsec update
173 snprintf(command, STRING_SIZE - 1,
174 "/usr/sbin/ipsec stroke down %s-renamed >/dev/null", name);
175 safe_system(command);
176 snprintf(command, STRING_SIZE - 1,
177 "/usr/sbin/ipsec stroke delete %s-renamed >/dev/null", name);
178 safe_system(command);
179
180 safe_system("/etc/rc.d/init.d/ipsec update >/dev/null");
5fd30232
MT
181}
182/*
183 issue ipsec commmands to turn off connection 'name'
184*/
185void turn_connection_off (char *name) {
69dcc425 186 char command[STRING_SIZE];
69dcc425
CS
187 memset(command, 0, STRING_SIZE);
188 snprintf(command, STRING_SIZE - 1,
98065e83 189 "/usr/sbin/ipsec whack --delete --name %s >/dev/null", name);
69dcc425 190 safe_system(command);
3e077ef3
AF
191 snprintf(command, STRING_SIZE - 1,
192 "/usr/sbin/ipsec stroke down %s >/dev/null", name);
193 safe_system(command);
194 snprintf(command, STRING_SIZE - 1,
195 "/usr/sbin/ipsec stroke delete %s >/dev/null", name);
196 safe_system(command);
6e2ba31b 197
98065e83 198 safe_system("/usr/sbin/ipsec whack --rereadall >/dev/null");
3e077ef3
AF
199 safe_system("/usr/sbin/ipsec stroke rereadall >/dev/null");
200
5fd30232
MT
201}
202
203
05207d69 204int main(int argc, char *argv[]) {
5fd30232 205
69dcc425
CS
206 char configtype[STRING_SIZE];
207 char redtype[STRING_SIZE] = "";
208 struct keyvalue *kv = NULL;
209
210 if (argc < 2) {
211 usage();
212 exit(1);
213 }
214 if (!(initsetuid()))
215 exit(1);
216
fe6cda92 217 FILE *file = NULL;
69dcc425 218
ba149d47
AF
219
220 if (strcmp(argv[1], "I") == 0) {
221 safe_system("/usr/sbin/ipsec whack --status");
0d181206 222 safe_system("/usr/sbin/ipsec stroke status");
ba149d47
AF
223 exit(0);
224 }
225
226 if (strcmp(argv[1], "R") == 0) {
227 safe_system("/usr/sbin/ipsec whack --rereadall >/dev/null");
0d181206 228 safe_system("/usr/sbin/ipsec stroke rereadall >/dev/null");
ba149d47
AF
229 exit(0);
230 }
231
dced81b2 232 /* Get vpnwatch pid */
fe6cda92 233
44b5666b
AF
234
235 if ((argc == 2) && (file = fopen("/var/run/vpn-watch.pid", "r"))) {
236 safe_system("kill -9 $(cat /var/run/vpn-watch.pid)");
237 safe_system("unlink /var/run/vpn-watch.pid");
238 close(file);
239 }
fe6cda92 240
69dcc425
CS
241 /* FIXME: workaround for pclose() issue - still no real idea why
242 * this is happening */
243 signal(SIGCHLD, SIG_DFL);
244
245 /* handle operations that doesn't need start the ipsec system */
246 if (argc == 2) {
247 if (strcmp(argv[1], "D") == 0) {
69dcc425
CS
248 /* Only shutdown pluto if it really is running */
249 /* Get pluto pid */
250 if (file = fopen("/var/run/pluto.pid", "r")) {
251 safe_system("/etc/rc.d/init.d/ipsec stop 2> /dev/null >/dev/null");
252 close(file);
253 }
1f324fd7 254 ipsec_norules();
69dcc425
CS
255 exit(0);
256 }
257
69dcc425
CS
258 }
259
69dcc425
CS
260 /* read vpn config */
261 kv=initkeyvalues();
262 if (!readkeyvalues(kv, CONFIG_ROOT "/vpn/settings"))
263 {
264 fprintf(stderr, "Cannot read vpn settings\n");
265 exit(1);
266 }
267
268 /* check is the vpn system is enabled */
269 {
270 char s[STRING_SIZE];
271 findkey(kv, "ENABLED", s);
272 freekeyvalues(kv);
273 if (strcmp (s, "on") != 0)
274 exit(0);
275 }
276
277 /* read interface settings */
278 kv=initkeyvalues();
279 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
280 {
281 fprintf(stderr, "Cannot read ethernet settings\n");
282 exit(1);
283 }
284 if (!findkey(kv, "CONFIG_TYPE", configtype))
285 {
286 fprintf(stderr, "Cannot read CONFIG_TYPE\n");
287 exit(1);
288 }
289 findkey(kv, "RED_TYPE", redtype);
290
291
292 /* Loop through the config file to find physical interface that will accept IPSEC */
293 int enable_red=0; // states 0: not used
294 int enable_green=0; // 1: error condition
295 int enable_orange=0; // 2: good
296 int enable_blue=0;
297 char if_red[STRING_SIZE] = "";
298 char if_green[STRING_SIZE] = "";
299 char if_orange[STRING_SIZE] = "";
300 char if_blue[STRING_SIZE] = "";
301 char s[STRING_SIZE];
302
303 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
304 fprintf(stderr, "Couldn't open vpn settings file");
305 exit(1);
306 }
307 while (fgets(s, STRING_SIZE, file) != NULL) {
308 char *key;
309 char *name;
310 char *type;
311 char *interface;
312 if (!decode_line(s,&key,&name,&type,&interface))
313 continue;
314 /* search interface */
315 if (!enable_red && strcmp (interface, "RED") == 0) {
316 // when RED is up, find interface name in special file
317 FILE *ifacefile = NULL;
318 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r"))) {
319 if (fgets(if_red, STRING_SIZE, ifacefile)) {
320 if (if_red[strlen(if_red) - 1] == '\n')
321 if_red[strlen(if_red) - 1] = '\0';
322 }
323 fclose (ifacefile);
324
325 if (VALID_DEVICE(if_red))
326 enable_red+=2; // present and running
327 }
328 }
329
330 if (!enable_green && strcmp (interface, "GREEN") == 0) {
331 enable_green = 1;
332 findkey(kv, "GREEN_DEV", if_green);
333 if (VALID_DEVICE(if_green))
334 enable_green++;
335 else
336 fprintf(stderr, "IPSec enabled on green but green interface is invalid or not found\n");
337 }
338
339 if (!enable_orange && strcmp (interface, "ORANGE") == 0) {
340 enable_orange = 1;
341 findkey(kv, "ORANGE_DEV", if_orange);
342 if (VALID_DEVICE(if_orange))
343 enable_orange++;
344 else
345 fprintf(stderr, "IPSec enabled on orange but orange interface is invalid or not found\n");
346 }
347
348 if (!enable_blue && strcmp (interface, "BLUE") == 0) {
349 enable_blue++;
350 findkey(kv, "BLUE_DEV", if_blue);
351 if (VALID_DEVICE(if_blue))
352 enable_blue++;
353 else
354 fprintf(stderr, "IPSec enabled on blue but blue interface is invalid or not found\n");
355
356 }
357 }
358 fclose(file);
359 freekeyvalues(kv);
360
361 // do nothing if something is in error condition
362 if ((enable_red==1) || (enable_green==1) || (enable_orange==1) || (enable_blue==1) )
363 exit(1);
364
365 // exit if nothing to do
366 if ( (enable_red+enable_green+enable_orange+enable_blue) == 0 )
367 exit(0);
368
369 // open needed ports
370 // todo: read a nat_t indicator to allow or not openning UDP/4500
371 if (enable_red==2)
372 open_physical(if_red, 4500);
373
374 if (enable_green==2)
375 open_physical(if_green, 4500);
376
377 if (enable_orange==2)
378 open_physical(if_orange, 4500);
379
380 if (enable_blue==2)
381 open_physical(if_blue, 4500);
382
69dcc425
CS
383 // start the system
384 if ((argc == 2) && strcmp(argv[1], "S") == 0) {
44b5666b
AF
385 safe_system("/etc/rc.d/init.d/ipsec restart >/dev/null");
386 safe_system("/usr/local/bin/vpn-watch &");
69dcc425
CS
387 exit(0);
388 }
389
390 // it is a selective start or stop
391 // second param is only a number 'key'
392 if ((argc == 2) || strspn(argv[2], NUMBERS) != strlen(argv[2])) {
69dcc425
CS
393 fprintf(stderr, "Bad arg\n");
394 usage();
395 exit(1);
396 }
397
398 // search the vpn pointed by 'key'
399 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
69dcc425
CS
400 fprintf(stderr, "Couldn't open vpn settings file");
401 exit(1);
402 }
403 while (fgets(s, STRING_SIZE, file) != NULL) {
404 char *key;
405 char *name;
406 char *type;
407 char *interface;
408 if (!decode_line(s,&key,&name,&type,&interface))
409 continue;
410
411 // start/stop a vpn if belonging to specified interface
412 if (strcmp(argv[1], interface) == 0 ) {
413 if (strcmp(argv[2], "0")==0)
414 turn_connection_off (name);
415 else
416 turn_connection_on (name, type);
417 continue;
418 }
419 // is it the 'key' requested ?
420 if (strcmp(argv[2], key) != 0)
421 continue;
422 // Start or Delete this Connection
423 if (strcmp(argv[1], "S") == 0)
424 turn_connection_on (name, type);
425 else
426 if (strcmp(argv[1], "D") == 0)
427 turn_connection_off (name);
428 else {
69dcc425
CS
429 fprintf(stderr, "Bad command\n");
430 exit(1);
431 }
432 }
433 fclose(file);
69dcc425 434 return 0;
05207d69 435}