]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blame - src/misc-progs/openvpnctrl.c
openvpnctrl: Fix SEGV in sprintf() call.
[people/teissler/ipfire-2.x.git] / src / misc-progs / openvpnctrl.c
CommitLineData
39877197 1#include <signal.h>
6e13d0a5
MT
2#include <stdio.h>
3#include <string.h>
4#include <unistd.h>
5#include <stdlib.h>
6#include <sys/types.h>
7#include <fcntl.h>
8#include "setuid.h"
9#include "libsmooth.h"
10
6e13d0a5
MT
11#define noovpndebug
12
13// global vars
14 struct keyvalue *kv = NULL;
15 FILE *ifacefile = NULL;
16
17char redif[STRING_SIZE];
18char blueif[STRING_SIZE];
19char orangeif[STRING_SIZE];
20char enablered[STRING_SIZE] = "off";
21char enableblue[STRING_SIZE] = "off";
22char enableorange[STRING_SIZE] = "off";
23
24// consts
25char OVPNRED[STRING_SIZE] = "OVPN";
26char OVPNBLUE[STRING_SIZE] = "OVPN_BLUE_";
27char OVPNORANGE[STRING_SIZE] = "OVPN_ORANGE_";
39877197 28char WRAPPERVERSION[STRING_SIZE] = "ipfire-2.1.2";
6925b8ef
AF
29
30struct connection_struct {
31 char name[STRING_SIZE];
32 char proto[STRING_SIZE];
33 int port;
34 struct connection_struct *next;
35};
36
37typedef struct connection_struct connection;
6e13d0a5
MT
38
39void exithandler(void)
40{
41 if(kv)
42 freekeyvalues(kv);
43 if (ifacefile)
44 fclose(ifacefile);
45}
46
47void usage(void)
48{
49#ifdef ovpndebug
07081137 50 printf("Wrapper for OpenVPN %s-debug\n", WRAPPERVERSION);
6e13d0a5 51#else
07081137 52 printf("Wrapper for OpenVPN %s\n", WRAPPERVERSION);
6e13d0a5
MT
53#endif
54 printf("openvpnctrl <option>\n");
55 printf(" Valid options are:\n");
56 printf(" -s --start\n");
57 printf(" starts OpenVPN (implicitly creates chains and firewall rules)\n");
58 printf(" -k --kill\n");
59 printf(" kills/stops OpenVPN\n");
60 printf(" -r --restart\n");
61 printf(" restarts OpenVPN (implicitly creates chains and firewall rules)\n");
62 printf(" -d --display\n");
63 printf(" displays OpenVPN status to syslog\n");
64 printf(" -fwr --firewall-rules\n");
65 printf(" removes current OpenVPN chains and rules and resets them according to the config\n");
66 printf(" -sdo --start-daemon-only\n");
afabe9f7 67 printf(" starts OpenVPN daemon only\n");
6e13d0a5
MT
68 printf(" -ccr --create-chains-and-rules\n");
69 printf(" creates chains and rules for OpenVPN\n");
70 printf(" -dcr --delete-chains-and-rules\n");
71 printf(" removes all chains for OpenVPN\n");
72 exit(1);
73}
74
6925b8ef
AF
75connection *getConnections() {
76 FILE *fp = NULL;
77
78 if (!(fp = fopen(CONFIG_ROOT "/ovpn/ovpnconfig", "r"))) {
79 fprintf(stderr, "Could not open openvpn n2n configuration file.\n");
80 exit(1);
81 }
82
83 char line[STRING_SIZE] = "";
84 char *result;
85 int count;
86 connection *conn_first = NULL;
87 connection *conn_last = NULL;
88 connection *conn_curr;
89
90 while ((fgets(line, STRING_SIZE, fp) != NULL)) {
91 if (line[strlen(line) - 1] == '\n')
92 line[strlen(line) - 1] = '\0';
93
94 conn_curr = (connection *)malloc(sizeof(connection));
95 memset(conn_curr, 0, sizeof(connection));
96
97 if (conn_first == NULL) {
98 conn_first = conn_curr;
99 } else {
100 conn_last->next = conn_curr;
101 }
102 conn_last = conn_curr;
103
104 count = 0;
105 result = strtok(line, ",");
106 while (result) {
107 if (count == 2) {
108 strcpy(conn_curr->name, result);
109 } else if (count == 12) {
110 strcpy(conn_curr->proto, result);
111 } else if (count == 13) {
112 conn_curr->port = atoi(result);
113 }
114
115 result = strtok(NULL, ",");
116 count++;
117 }
118 }
119
120 fclose(fp);
121
122 return conn_first;
123}
124
80ca8bd0
MT
125int readPidFile(const char *pidfile) {
126 FILE *fp = fopen(pidfile, "r");
127 if (fp == NULL) {
128 fprintf(stderr, "PID file not found: '%s'\n", pidfile);
129 exit(1);
130 }
131
132 int pid = 0;
133 fscanf(fp, "%d", &pid);
134 fclose(fp);
135
136 return pid;
137}
138
6e13d0a5
MT
139void ovpnInit(void) {
140
141 // Read OpenVPN configuration
142 kv = initkeyvalues();
143 if (!readkeyvalues(kv, CONFIG_ROOT "/ovpn/settings")) {
144 fprintf(stderr, "Cannot read ovpn settings\n");
145 exit(1);
146 }
147
148 if (!findkey(kv, "ENABLED", enablered)) {
149 fprintf(stderr, "Cannot read ENABLED\n");
150 exit(1);
151 }
152
153 if (!findkey(kv, "ENABLED_BLUE", enableblue)){
154 fprintf(stderr, "Cannot read ENABLED_BLUE\n");
155 exit(1);
156 }
157
158 if (!findkey(kv, "ENABLED_ORANGE", enableorange)){
159 fprintf(stderr, "Cannot read ENABLED_ORANGE\n");
160 exit(1);
161 }
162 freekeyvalues(kv);
163
164 // read interface settings
165
166 // details for the red int
167 memset(redif, 0, STRING_SIZE);
168 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r")))
169 {
170 if (fgets(redif, STRING_SIZE, ifacefile))
171 {
172 if (redif[strlen(redif) - 1] == '\n')
173 redif[strlen(redif) - 1] = '\0';
174 }
175 fclose (ifacefile);
176 ifacefile = NULL;
177
178 if (!VALID_DEVICE(redif))
179 {
180 memset(redif, 0, STRING_SIZE);
181 }
182 }
183
184 kv=initkeyvalues();
185 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
186 {
187 fprintf(stderr, "Cannot read ethernet settings\n");
188 exit(1);
189 }
190
191 if (strcmp(enableblue, "on")==0){
192 if (!findkey(kv, "BLUE_DEV", blueif)){
193 fprintf(stderr, "Cannot read BLUE_DEV\n");
194 exit(1);
195 }
196 }
197 if (strcmp(enableorange, "on")==0){
198 if (!findkey(kv, "ORANGE_DEV", orangeif)){
199 fprintf(stderr, "Cannot read ORNAGE_DEV\n");
200 exit(1);
201 }
202 }
203 freekeyvalues(kv);
204}
205
206void executeCommand(char *command) {
207#ifdef ovpndebug
208 printf(strncat(command, "\n", 2));
209#endif
210 safe_system(strncat(command, " >/dev/null 2>&1", 17));
211}
212
213void setChainRules(char *chain, char *interface, char *protocol, char *port)
214{
215 char str[STRING_SIZE];
07081137 216
6e13d0a5
MT
217 sprintf(str, "/sbin/iptables -A %sINPUT -i %s -p %s --dport %s -j ACCEPT", chain, interface, protocol, port);
218 executeCommand(str);
219 sprintf(str, "/sbin/iptables -A %sINPUT -i tun+ -j ACCEPT", chain);
220 executeCommand(str);
221 sprintf(str, "/sbin/iptables -A %sFORWARD -i tun+ -j ACCEPT", chain);
222 executeCommand(str);
223}
224
225void flushChain(char *chain) {
226 char str[STRING_SIZE];
227
228 sprintf(str, "/sbin/iptables -F %sINPUT", chain);
229 executeCommand(str);
230 sprintf(str, "/sbin/iptables -F %sFORWARD", chain);
231 executeCommand(str);
232 safe_system(str);
233}
234
235void deleteChainReference(char *chain) {
236 char str[STRING_SIZE];
237
238 sprintf(str, "/sbin/iptables -D INPUT -j %sINPUT", chain);
239 executeCommand(str);
240 safe_system(str);
241 sprintf(str, "/sbin/iptables -D FORWARD -j %sFORWARD", chain);
242 executeCommand(str);
243 safe_system(str);
244}
245
246void deleteChain(char *chain) {
247 char str[STRING_SIZE];
248
249 sprintf(str, "/sbin/iptables -X %sINPUT", chain);
250 executeCommand(str);
251 sprintf(str, "/sbin/iptables -X %sFORWARD", chain);
252 executeCommand(str);
253}
254
255void deleteAllChains(void) {
256 // not an elegant solution, but to avoid timing problems with undeleted chain references
257 deleteChainReference(OVPNRED);
258 deleteChainReference(OVPNBLUE);
259 deleteChainReference(OVPNORANGE);
260 flushChain(OVPNRED);
261 flushChain(OVPNBLUE);
262 flushChain(OVPNORANGE);
263 deleteChain(OVPNRED);
264 deleteChain(OVPNBLUE);
265 deleteChain(OVPNORANGE);
266}
267
268void createChainReference(char *chain) {
269 char str[STRING_SIZE];
270 sprintf(str, "/sbin/iptables -I INPUT %s -j %sINPUT", "14", chain);
271 executeCommand(str);
272 sprintf(str, "/sbin/iptables -I FORWARD %s -j %sFORWARD", "12", chain);
273 executeCommand(str);
274}
275
276void createChain(char *chain) {
277 char str[STRING_SIZE];
278 sprintf(str, "/sbin/iptables -N %sINPUT", chain);
279 executeCommand(str);
280 sprintf(str, "/sbin/iptables -N %sFORWARD", chain);
281 executeCommand(str);
282}
283
284void createAllChains(void) {
858d8d90
MT
285 // create chain and chain references
286 if (!strcmp(enableorange, "on")) {
287 if (strlen(orangeif)) {
288 createChain(OVPNORANGE);
289 createChainReference(OVPNORANGE);
290 } else {
291 fprintf(stderr, "OpenVPN enabled on orange but no orange interface found\n");
292 //exit(1);
6e13d0a5 293 }
858d8d90
MT
294 }
295
296 if (!strcmp(enableblue, "on")) {
297 if (strlen(blueif)) {
298 createChain(OVPNBLUE);
299 createChainReference(OVPNBLUE);
300 } else {
301 fprintf(stderr, "OpenVPN enabled on blue but no blue interface found\n");
302 //exit(1);
6e13d0a5 303 }
858d8d90
MT
304 }
305
306 if (!strcmp(enablered, "on")) {
307 if (strlen(redif)) {
308 createChain(OVPNRED);
309 createChainReference(OVPNRED);
310 } else {
311 fprintf(stderr, "OpenVPN enabled on red but no red interface found\n");
312 //exit(1);
6e13d0a5
MT
313 }
314 }
315}
316
317void setFirewallRules(void) {
318 char protocol[STRING_SIZE] = "";
319 char dport[STRING_SIZE] = "";
320 char dovpnip[STRING_SIZE] = "";
321
6e13d0a5
MT
322 kv = initkeyvalues();
323 if (!readkeyvalues(kv, CONFIG_ROOT "/ovpn/settings"))
324 {
325 fprintf(stderr, "Cannot read ovpn settings\n");
326 exit(1);
327 }
328
329 /* we got one device, so lets proceed further */
330 if (!findkey(kv, "DDEST_PORT", dport)){
331 fprintf(stderr, "Cannot read DDEST_PORT\n");
332 exit(1);
333 }
334
335 if (!findkey(kv, "DPROTOCOL", protocol)){
336 fprintf(stderr, "Cannot read DPROTOCOL\n");
337 exit(1);
338 }
339
340 if (!findkey(kv, "VPN_IP", dovpnip)){
341 fprintf(stderr, "Cannot read VPN_IP\n");
342// exit(1); step further as we don't need an ip
343 }
344 freekeyvalues(kv);
345
6925b8ef
AF
346 // read connection configuration
347 connection *conn = getConnections();
348
07081137
MT
349 // Flush all chains.
350 flushChain(OVPNRED);
351 flushChain(OVPNBLUE);
352 flushChain(OVPNORANGE);
353
6e13d0a5
MT
354 // set firewall rules
355 if (!strcmp(enablered, "on") && strlen(redif))
356 setChainRules(OVPNRED, redif, protocol, dport);
357 if (!strcmp(enableblue, "on") && strlen(blueif))
358 setChainRules(OVPNBLUE, blueif, protocol, dport);
359 if (!strcmp(enableorange, "on") && strlen(orangeif))
360 setChainRules(OVPNORANGE, orangeif, protocol, dport);
6925b8ef
AF
361
362 // set firewall rules for n2n connections
1129c37a 363 char port[STRING_SIZE];
7d653d51 364 while (conn != NULL) {
6925b8ef 365 sprintf(port, "%d", conn->port);
07081137 366 setChainRules(OVPNRED, redif, conn->proto, port);
6925b8ef
AF
367 conn = conn->next;
368 }
6e13d0a5
MT
369}
370
371void stopDaemon(void) {
372 char command[STRING_SIZE];
373
2bcff894 374 int pid = readPidFile("/var/run/openvpn.pid");
80ca8bd0 375 if (!pid > 0) {
2bcff894
MT
376 exit(1);
377 }
378
379 fprintf(stderr, "Killing PID %d.\n", pid);
380 kill(pid, SIGTERM);
381
6e13d0a5
MT
382 snprintf(command, STRING_SIZE - 1, "/bin/rm -f /var/run/openvpn.pid");
383 executeCommand(command);
384}
385
386void startDaemon(void) {
387 char command[STRING_SIZE];
388
389 if (!((strcmp(enablered, "on")==0) || (strcmp(enableblue, "on")==0) || (strcmp(enableorange, "on")==0))){
390 fprintf(stderr, "OpenVPN is not enabled on any interface\n");
391 exit(1);
392 } else {
7d3af7f7
MT
393 snprintf(command, STRING_SIZE-1, "/sbin/modprobe tun");
394 executeCommand(command);
072cd997 395 snprintf(command, STRING_SIZE-1, "/usr/sbin/openvpn --config /var/ipfire/ovpn/server.conf");
6e13d0a5
MT
396 executeCommand(command);
397 }
398}
399
6925b8ef
AF
400void startNet2Net(char *name) {
401 connection *conn = NULL;
402 connection *conn_iter;
403
404 conn_iter = getConnections();
405
406 while (conn_iter) {
407 if (strcmp(conn_iter->name, name) == 0) {
408 conn = conn_iter;
409 break;
410 }
411 conn_iter = conn_iter->next;
412 }
413
414 if (conn == NULL) {
415 fprintf(stderr, "Connection not found.\n");
416 exit(1);
417 }
418
39877197
MT
419 char configfile[STRING_SIZE];
420 snprintf(configfile, STRING_SIZE - 1, CONFIG_ROOT "/ovpn/n2nconf/%s/%s.conf",
421 conn->name, conn->name);
422
423 FILE *fp = fopen(configfile, "r");
424 if (fp == NULL) {
425 fprintf(stderr, "Could not find configuration file for connection '%s' at '%s'.\n",
426 conn->name, configfile);
427 exit(2);
428 }
429 fclose(fp);
430
07081137
MT
431 // Make sure all firewall rules are up to date.
432 setFirewallRules();
433
6925b8ef 434 char command[STRING_SIZE];
39877197 435 sprintf(command, "/usr/sbin/openvpn --config %s", configfile);
6925b8ef
AF
436 executeCommand(command);
437}
438
39877197
MT
439void killNet2Net(char *name) {
440 connection *conn = NULL;
441 connection *conn_iter;
442
443 conn_iter = getConnections();
444
445 while (conn_iter) {
446 if (strcmp(conn_iter->name, name) == 0) {
447 conn = conn_iter;
448 break;
449 }
450 conn_iter = conn_iter->next;
451 }
452
453 if (conn == NULL) {
454 fprintf(stderr, "Connection not found.\n");
455 exit(1);
456 }
457
458 char pidfile[STRING_SIZE];
80ca8bd0 459 snprintf(pidfile, STRING_SIZE - 1, "/var/run/%sn2n.pid", conn->name);
39877197 460
2bcff894 461 int pid = readPidFile(pidfile);
80ca8bd0 462 if (!pid > 0) {
39877197
MT
463 exit(1);
464 }
465
39877197
MT
466 fprintf(stderr, "Killing PID %d.\n", pid);
467 kill(pid, SIGTERM);
468
d4c8b6be
MT
469 char command[STRING_SIZE];
470 snprintf(command, STRING_SIZE - 1, "/bin/rm -f %s", pidfile);
471 executeCommand(command);
472
39877197 473 exit(0);
6925b8ef
AF
474}
475
6e13d0a5
MT
476void displayopenvpn(void) {
477 char command[STRING_SIZE];
478
479 snprintf(command, STRING_SIZE - 1, "/bin/killall -sSIGUSR2 openvpn");
480 executeCommand(command);
481}
482
483int main(int argc, char *argv[]) {
484 if (!(initsetuid()))
485 exit(1);
486 if(argc < 2)
487 usage();
6925b8ef
AF
488
489 if(argc == 3) {
490 if( (strcmp(argv[1], "-sn2n") == 0) || (strcmp(argv[1], "--start-net-2-net") == 0) ) {
491 startNet2Net(argv[2]);
492 return 0;
493 }
494 else if( (strcmp(argv[1], "-kn2n") == 0) || (strcmp(argv[1], "--kill-net-2-net") == 0) ) {
495 killNet2Net(argv[2]);
496 return 0;
497 } else {
498 usage();
499 return 1;
500 }
501 }
502 else if(argc == 2) {
6e13d0a5
MT
503 if( (strcmp(argv[1], "-k") == 0) || (strcmp(argv[1], "--kill") == 0) ) {
504 stopDaemon();
505 return 0;
506 }
507 else if( (strcmp(argv[1], "-d") == 0) || (strcmp(argv[1], "--display") == 0) ) {
508 displayopenvpn();
509 return 0;
510 }
511 else if( (strcmp(argv[1], "-dcr") == 0) || (strcmp(argv[1], "--delete-chains-and-rules") == 0) ) {
512 deleteAllChains();
513 return 0;
514 }
515 else {
516 ovpnInit();
517
518 if( (strcmp(argv[1], "-s") == 0) || (strcmp(argv[1], "--start") == 0) ) {
519 deleteAllChains();
520 createAllChains();
521 setFirewallRules();
522 startDaemon();
523 return 0;
524 }
525 else if( (strcmp(argv[1], "-sdo") == 0) || (strcmp(argv[1], "--start-daemon-only") == 0) ) {
526 startDaemon();
527 return 0;
528 }
529 else if( (strcmp(argv[1], "-r") == 0) || (strcmp(argv[1], "--restart") == 0) ) {
530 stopDaemon();
531 deleteAllChains();
532 createAllChains();
533 setFirewallRules();
534 startDaemon();
535 return 0;
536 }
537 else if( (strcmp(argv[1], "-fwr") == 0) || (strcmp(argv[1], "--firewall-rules") == 0) ) {
538 deleteAllChains();
539 createAllChains();
540 setFirewallRules();
541 return 0;
542 }
543 else if( (strcmp(argv[1], "-ccr") == 0) || (strcmp(argv[1], "--create-chains-and-rules") == 0) ) {
544 createAllChains();
545 setFirewallRules();
546 return 0;
547 }
548 else {
549 usage();
550 return 0;
551 }
552 }
553 }
554 else {
555 usage();
556 return 0;
557 }
558return 0;
559}
560