1 /*
2 * OSConfigurator_secuwall.cpp - secunet wall OS configurator implementation
3 *
4 * Copyright (c) 2008 secunet Security Networks AG
5 * Copyright (c) 2008 Adrian-Ken Rueegsegger <rueegsegger@swiss-it.ch>
6 * Copyright (c) 2008 Reto Buerki <buerki@swiss-it.ch>
7 *
8 * This work is dual-licensed under:
9 *
10 * o The terms of the GNU General Public License as published by the Free
11 * Software Foundation, either version 2 of the License, or (at your option)
12 * any later version.
13 *
14 * o The terms of NetCitadel End User License Agreement
15 */
16
17 #include "config.h"
18
19 #include "OSConfigurator_secuwall.h"
20
21 #include "fwbuilder/InetAddr.h"
22
23 #include "fwbuilder/Firewall.h"
24 #include "fwbuilder/FWOptions.h"
25 #include "fwbuilder/InetAddr.h"
26 #include "fwbuilder/Interface.h"
27 #include "fwbuilder/IPv4.h"
28 #include "fwbuilder/Network.h"
29 #include "fwbuilder/Address.h"
30 #include "fwbuilder/Resources.h"
31 #include "fwbuilder/MultiAddress.h"
32 #include "fwbuilder/physAddress.h"
33 #include "fwbuilder/Routing.h"
34 #include "fwbuilder/Rule.h"
35 #include "fwbuilder/RuleElement.h"
36 #include "fwbuilder/FailoverClusterGroup.h"
37 #include "fwbuilder/Tools.h"
38
39 #include <errno.h>
40 #include <ctype.h>
41 #include <assert.h>
42
43 #include <iostream>
44 #include <cstring>
45
46 #include <QDir>
47 #include <QString>
48 #include <QTextStream>
49
50 using namespace libfwbuilder;
51 using namespace fwcompiler;
52 using namespace std;
53
54 static string sysconfig_dir = "sysconfig";
55 static string ssh_dir = "ssh";
56 static string networkscripts_dir = sysconfig_dir + "/network-scripts";
57 static string hosts_filename = "hosts";
58 static string dns_filename = "resolv.conf";
59 static string nsswitch_filename = "nsswitch.conf";
60 static string mgmt_filename = sysconfig_dir + "/management";
61 static string network_filename = sysconfig_dir + "/network";
62 static string iface_prefix = "ifcfg-";
63 static string iface_filename = networkscripts_dir+"/"+iface_prefix;
64
65 static string fwadmin_ssh_key = "/.ssh/id_rsa.pub";
66 static string fwadmin_known_hosts = "/.ssh/known_hosts2";
67
myPlatformName()68 string OSConfigurator_secuwall::myPlatformName()
69 {
70 return "Secuwall";
71 }
72
OSConfigurator_secuwall(FWObjectDatabase * _db,Firewall * fw,bool ipv6_policy)73 OSConfigurator_secuwall::OSConfigurator_secuwall(FWObjectDatabase *_db,
74 Firewall *fw,
75 bool ipv6_policy) :
76 OSConfigurator_linux24(_db, fw, ipv6_policy)
77 {
78 s_mapIfaceTypes["ethernet"] = ETHERNET;
79 s_mapIfaceTypes["bridge"] = BRIDGE;
80 s_mapIfaceTypes["bonding"] = BONDING;
81 s_mapIfaceTypes["vrrp"] = CLUSTER;
82 s_mapIfaceTypes["8021q"] = VLAN;
83
84 s_mapIfaceStrings[ETHERNET] = "ethernet";
85 s_mapIfaceStrings[ALIAS] = "alias";
86 s_mapIfaceStrings[BRIDGE] = "bridge";
87 s_mapIfaceStrings[BONDING] = "bonding";
88 s_mapIfaceStrings[CLUSTER] = "vrrp";
89 s_mapIfaceStrings[VLAN] = "8021q";
90
91 /* search all interfaces, this means here: IP endpoints in stack! */
92 list<FWObject *> fw_ifaces = fw->getByTypeDeep(Interface::TYPENAME);
93
94 for (list<FWObject *>::iterator it = fw_ifaces.begin(); it != fw_ifaces.end(); it++)
95 {
96 Interface *iface = Interface::cast(*it);
97 assert(NULL != iface);
98 /* Check if it is a management interface */
99 if (!iface->getName().empty() && (NULL != iface->getAddressObject()))
100 {
101 m_ifaces.push_back(iface);
102 }
103 }
104 }
105
106 /*
107 * in addition to kernel parameters and other standard things
108 * OSConfigurator_linux24 does, this class also creates configuration
109 * directories, generates ssh keys and files for sysconfig-style
110 * configuration. This method is called from CompilerDriver_ipt::run()
111 * and does not run in single rule compile mode.
112 */
processFirewallOptions()113 void OSConfigurator_secuwall::processFirewallOptions()
114 {
115 OSConfigurator_linux24::processFirewallOptions();
116
117 if (!createDirStructure())
118 abort("Unable to create directory structure");
119
120 FWOptions* options = fw->getOptionsObject();
121 assert(options != NULL);
122
123 /* Do ssh key generation if not disabled. */
124 if (!options->getBool("secuwall_no_ssh_key_generation"))
125 {
126 generateSSHKeys();
127 }
128
129 generateHostsFile();
130 generateDNSFile();
131 generateNsswitchFile();
132 generateManagementFile();
133 generateNetworkFile();
134 generateInterfaces();
135 }
136
createDirStructure() const137 bool OSConfigurator_secuwall::createDirStructure() const
138 {
139 QDir directory;
140 list<QString> dir_names;
141
142 dir_names.push_back (QString (fw->getName().c_str()));
143
144 QString tmp_name = fw->getName().c_str();
145 tmp_name.append("/");
146 tmp_name.append(ssh_dir.c_str());
147 dir_names.push_back(tmp_name);
148
149 tmp_name = fw->getName().c_str();
150 tmp_name.append("/");
151 tmp_name.append(sysconfig_dir.c_str());
152 dir_names.push_back(tmp_name);
153
154 tmp_name = fw->getName().c_str();
155 tmp_name.append("/");
156 tmp_name.append(networkscripts_dir.c_str());
157 dir_names.push_back(tmp_name);
158
159 list<QString>::const_iterator c_iter = dir_names.begin();
160 for (; c_iter != dir_names.end(); c_iter++)
161 {
162 if (!directory.mkdir(*c_iter))
163 {
164 /* Check if directory already exists */
165 if (!directory.exists())
166 {
167 cerr << "Error[" << errno << "]: " << strerror(errno);
168 cerr << " '" << c_iter->toStdString() << "'"<< endl;
169 return false;
170 }
171 }
172 }
173
174 cout << " created directory structure successfully" << endl << flush;
175
176 return true;
177 }
178
generateManagementFile()179 int OSConfigurator_secuwall::generateManagementFile()
180 {
181 FWOptions* options = fw->getOptionsObject();
182 assert(options != NULL);
183
184 QString s, mgm_ip, vrrp_secret, stream_string, snmp_ip;
185 bool vrrp_master = false;
186 vector <string> tmp_v, mgm_iface;
187
188 /* Temporary storage for management file content */
189 QTextStream stream (&stream_string);
190
191 /* search Management Interfaces, note: this can be more than one */
192 for (list<Interface *>::iterator it = m_ifaces.begin(); it != m_ifaces.end(); it++)
193 {
194 /* Check if it is a management interface */
195 if ((*it)->isManagement())
196 {
197 mgm_iface.push_back((*it)->getName());
198 }
199 }
200
201 stream << "MGM_DEV=\"";
202 stream << stringify(mgm_iface, " ").c_str();
203 stream << "\"" << endl;
204
205 /* lookup Management IP address */
206 mgm_ip = options->getStr("secuwall_mgmt_mgmtaddr").c_str();
207
208 if (mgm_ip.isEmpty())
209 {
210 /* This is only a warning, if the system is not managed online */
211 cout << " Warning: no Management IP address specified!" << endl;
212 }
213 else
214 {
215 if (mgm_iface.empty())
216 {
217 abort("At least one management interface is needed for Online Management!");
218 }
219 else
220 {
221 stream << "MGM_IP=\"";
222 tmp_v.clear();
223 tokenize(mgm_ip.toStdString(), tmp_v, ",");
224 stream << stringify(tmp_v, " ").c_str();
225 stream << s << "\"" << endl;
226 }
227 }
228
229 /* Log-Server IP address */
230 stream << "LOG_IP=\"";
231 tmp_v.clear();
232 tokenize(options->getStr("secuwall_mgmt_loggingaddr"), tmp_v, ",");
233 stream << stringify(tmp_v, " ").c_str();
234 stream << "\"" << endl;
235
236 /* SNMP-Server IP address */
237 snmp_ip = options->getStr("secuwall_mgmt_snmpaddr").c_str();
238 if (!snmp_ip.isEmpty())
239 {
240 if (mgm_iface.empty())
241 {
242 abort("At least one management interface is needed for SNMP!");
243 }
244 else
245 {
246 stream << "SNMP_IP=\"";
247 tmp_v.clear();
248 tokenize(options->getStr("secuwall_mgmt_snmpaddr"), tmp_v, ",");
249 stream << stringify(tmp_v, " ").c_str();
250 stream << "\"" << endl;
251
252 /* SNMP Community string */
253 stream << "SNMP_COM=\"";
254 stream << options->getStr("secuwall_mgmt_rosnmp").c_str();
255 stream << "\"" << endl;
256 }
257 }
258
259 /* NTP-Server IP address */
260 stream << "NTP_IP=\"";
261 tmp_v.clear();
262 tokenize(options->getStr("secuwall_mgmt_ntpaddr"), tmp_v, ",");
263 stream << stringify(tmp_v, " ").c_str();
264 stream << "\"" << endl;
265
266 /* /var partition */
267 stream << "VARPART=\"";
268 stream << options->getStr("secuwall_mgmt_varpart").c_str();
269 stream << "\"" << endl;
270
271 /* Configuration partition */
272 stream << "CFGPART=\"";
273 stream << options->getStr("secuwall_mgmt_confpart").c_str();
274 stream << "\"" << endl;
275
276 /* Activate Nagios */
277 stream << "NRPE=";
278 s.clear();
279 s = options->getStr("secuwall_mgmt_nagiosaddr").c_str();
280 if (!s.isEmpty())
281 {
282 stream << "yes" << endl;
283
284 /* Nagios-Server IP-Address */
285 stream << "NRPE_IP=\"";
286 tmp_v.clear();
287 tokenize(s.toStdString(), tmp_v, ",");
288 stream << stringify(tmp_v, " ").c_str();
289 stream << "\"" << endl;
290 }
291 else
292 {
293 stream << "no" << endl;
294 }
295
296 /* VRRP interfaces */
297
298 for (FWObjectTypedChildIterator fw_ifaces = fw->findByType(Interface::TYPENAME);
299 fw_ifaces != fw_ifaces.end(); ++fw_ifaces)
300 {
301 Interface *iface = Interface::cast(*fw_ifaces);
302 /* Check if it is a VRRP interface */
303 FWObject *failover_group =
304 iface->getFirstByType(FailoverClusterGroup::TYPENAME);
305 if (failover_group)
306 {
307 FWOptions *failover_opts =
308 FailoverClusterGroup::cast(failover_group)->getOptionsObject();
309 if (failover_group->getStr("type") == "vrrp" && failover_opts != NULL)
310 {
311 vrrp_secret = failover_opts->getStr("vrrp_secret").c_str();
312 vrrp_master = iface->getOptionsObject()->getBool("failover_master");;
313 }
314 }
315 }
316
317 /* Activate VRRP */
318 stream << "VRRPD=";
319 if (options->getBool("cluster_member"))
320 {
321 stream << "yes" << endl;
322 /* VRRP secret */
323 stream << "VRRPSECRET=\"";
324 stream << vrrp_secret;
325 stream << "\"" << endl;
326
327 /* VRRP Master/Slave */
328 stream << "MASTER=";
329 stream << (vrrp_master ? "yes" : "no");
330 stream << endl;
331 }
332 else
333 {
334 stream << "no" << endl;
335 }
336
337 /* conntrackd */
338 s.clear();
339 s = options->getStr("state_sync_interface").c_str();
340 stream << "CONNTRACKD=";
341 if (!s.isEmpty())
342 {
343 stream << "yes" << endl;
344 /* conntrack device */
345 stream << "CONN_DEV=\"";
346 stream << s;
347 stream << "\"" << endl;
348 }
349 else
350 {
351 stream << "no" << endl;
352 }
353
354 /* Write actual management file */
355 string filename = fw->getName() + "/" + mgmt_filename;
356 stringToFile(stream.string()->toStdString(), filename);
357
358 cout << " wrote " << mgmt_filename << " successfully" << endl << flush;
359
360 return 0;
361 }
362
363 /* Routes are expected to be verified & valid since this step is executed after Route policy compilation */
generateNetworkFile()364 int OSConfigurator_secuwall::generateNetworkFile()
365 {
366 FWOptions* options = fw->getOptionsObject();
367 assert(options != NULL);
368
369 FWObject *routes = fw->getFirstByType(Routing::TYPENAME);
370 assert(routes);
371
372 QString s, ifName, gwAddress, stream_string;
373
374 /* Temporary storage for file content */
375 QTextStream stream (&stream_string);
376
377 /* Default route */
378 RoutingRule* defaultRoute = NULL;
379
380 /* Prepend static content */
381 stream << "NETWORKING=yes" << endl;
382
383 /* Find default route */
384 FWObjectTypedChildIterator routing_rules = routes->findByType(RoutingRule::TYPENAME);
385 for (; routing_rules != routing_rules.end(); ++routing_rules)
386 {
387 RoutingRule* route = RoutingRule::cast(*routing_rules);
388 if (!route->isEmpty() && !route->isDisabled() && route->getRDst()->isAny())
389 {
390 defaultRoute = route;
391 /* There can only be one default route, so we are done */
392 break;
393 }
394
395 }
396
397 if (defaultRoute != NULL)
398 {
399 RuleElementRItf* itfrel = defaultRoute->getRItf();
400 RuleElementRGtw* gtwrel = defaultRoute->getRGtw();
401
402 FWObject *oRGtw = FWReference::cast(gtwrel->front())->getPointer();
403 assert(oRGtw != NULL);
404 FWObject *oRItf = FWReference::cast(itfrel->front())->getPointer();
405 assert(oRItf != NULL);
406
407 /* Extract Gateway IP address */
408 if (Host::cast(oRGtw) != NULL)
409 {
410 Host *host=Host::cast(oRGtw);
411 gwAddress = host->getAddressPtr()->toString().c_str();
412 }
413 else if (Interface::cast(oRGtw) != NULL)
414 {
415 Interface *intf=Interface::cast(oRGtw);
416 gwAddress = intf->getAddressPtr()->toString().c_str();
417 }
418 else if (Address::cast(oRGtw)->dimension()==1)
419 {
420 Address *ipv4 = Address::cast(oRGtw);
421 gwAddress = ipv4->getAddressPtr()->toString().c_str();
422 }
423 /* Extract Interface name */
424 ifName = oRItf->getName().c_str();
425 }
426
427 /* XXX: not setting gateway since default route will be set by routing rules */
428 /* Default Gateway */
429 stream << "GATEWAY=\"";
430 s = gwAddress;
431 {
432 // stream << s;
433 }
434 stream << "\"" << endl;
435
436 /* Gateway interface */
437 stream << "GATEWAYDEV=\"";
438 s = ifName;
439 {
440 // stream << s;
441 }
442 stream << "\"" << endl;
443
444 /* Hostname */
445 stream << "HOSTNAME=\"";
446 stream << fw->getName().c_str();
447 stream << "\"" << endl;
448
449 /* Routing */
450 stream << "FORWARD_IPV4=\"";
451 if (options->getBool("linux24_ip_forward"))
452 {
453 stream << "yes";
454 }
455 else
456 {
457 stream << "no";
458 }
459 stream << "\"" << endl;
460
461 /* Write actual network file */
462 string filename = fw->getName() + "/" + network_filename;
463 stringToFile(stream.string()->toStdString(), filename);
464
465 cout << " wrote " << network_filename << " successfully" << endl << flush;
466
467 return 0;
468 }
469
generateHostsFile()470 int OSConfigurator_secuwall::generateHostsFile()
471 {
472 FWOptions* options = fw->getOptionsObject();
473 assert(options != NULL);
474
475 QString s, stream_string;
476
477 /* Temporary storage for file content */
478 QTextStream stream (&stream_string);
479
480 /* Prepend static content */
481 stream << "127.0.0.1\tlocalhost\n\n# Secuwall hosts" << endl;
482
483 /* TODO: Should entries of every fw interface address be appended? */
484
485 stream << options->getStr("secuwall_dns_hosts").c_str();
486 stream << endl;
487
488 /* Write actual hosts file */
489 string filename = fw->getName() + "/" + hosts_filename;
490 stringToFile(stream.string()->toStdString(), filename);
491
492 cout << " wrote " << hosts_filename << " successfully" << endl << flush;
493
494 return 0;
495 }
496
generateDNSFile()497 int OSConfigurator_secuwall::generateDNSFile()
498 {
499 FWOptions* options = fw->getOptionsObject();
500 assert(options != NULL);
501
502 QString s, stream_string;
503
504 /* Temporary storage for file content */
505 QTextStream stream (&stream_string);
506
507 /* Search domains */
508 s = options->getStr("secuwall_dns_domains").c_str();
509 if (!s.isEmpty())
510 {
511 /* Replace \n with " " */
512 s.replace(QString("\n"), QString(" "));
513 stream << "search\t\t" << s << endl;
514 }
515
516 /* DNS-Server entries */
517 s = options->getStr("secuwall_dns_srv1").c_str();
518 if (!s.isEmpty())
519 stream << "nameserver\t" << s << endl;
520
521 s = options->getStr("secuwall_dns_srv2").c_str();
522 if (!s.isEmpty())
523 stream << "nameserver\t" << s << endl;
524
525 s = options->getStr("secuwall_dns_srv3").c_str();
526 if (!s.isEmpty())
527 stream << "nameserver\t" << s << endl;
528
529 /* Write actual DNS file */
530 string filename = fw->getName() + "/" + dns_filename;
531 stringToFile(stream.string()->toStdString(), filename);
532
533 cout << " wrote " << dns_filename << " successfully" << endl << flush;
534
535 return 0;
536 }
537
generateNsswitchFile()538 int OSConfigurator_secuwall::generateNsswitchFile()
539 {
540 FWOptions* options = fw->getOptionsObject();
541 assert(options != NULL);
542
543 QString s, stream_string;
544
545 /* Temporary storage for file content */
546 QTextStream stream(&stream_string);
547
548 /* Prepend static content */
549 stream << "passwd:\t\tfiles\nshadow:\t\tfiles\ngroup:\t\tfiles\n" << endl;
550
551 /* hosts entries */
552 stream << "hosts:\t\t";
553 s = options->getStr("secuwall_dns_reso1").c_str();
554 if (!s.isEmpty() && s != "none")
555 {
556 stream << s;
557 }
558
559 s = options->getStr("secuwall_dns_reso2").c_str();
560 if (!s.isEmpty() && s != "none")
561 {
562 stream << " " << s;
563 }
564
565 s = options->getStr("secuwall_dns_reso3").c_str();
566 if (!s.isEmpty() && s != "none")
567 {
568 stream << " " << s;
569 }
570
571 s = options->getStr("secuwall_dns_reso4").c_str();
572 if (!s.isEmpty() && s != "none")
573 {
574 stream << " " << s;
575 }
576
577 s = options->getStr("secuwall_dns_reso5").c_str();
578 if (!s.isEmpty() && s != "none")
579 {
580 stream << " " << s << endl;
581 }
582
583 stream << endl;
584
585 /* Append static content */
586 stream << "ethers:\t\tfiles\nnetmasks:\tfiles\nnetworks:\tfiles\nprotocols:\tfiles\nrpc:\t\tfiles\nservices:\tfiles\n";
587
588 /* Write actual nsswitch file */
589 string filename = fw->getName() + "/" + nsswitch_filename;
590 stringToFile(stream.string()->toStdString(), filename);
591
592 cout << " wrote " << nsswitch_filename << " successfully" << endl << flush;
593
594 return 0;
595 }
596
generateInterfaceFile(Interface * iface,string name,IPv4 * ip_address,int iface_number)597 int OSConfigurator_secuwall::generateInterfaceFile (Interface * iface, string name, IPv4 * ip_address, int iface_number)
598 {
599 FWOptions* options = NULL;
600 ifaceType itype = ifNotDefined;
601 QString s;
602
603 /* Temporary storage for file content */
604 QString stream_string;
605 QTextStream stream(&stream_string);
606
607 assert(iface != NULL);
608
609 /* fallback for name of the interface */
610 if (name.empty())
611 name = iface->getName();
612
613 if (name.empty())
614 abort("cannot get name for interface");
615
616 /* determine the type of the interface */
617 if (iface->getName().find("*") == string::npos)
618 options = iface->getOptionsObject();
619
620 if (iface_number > 0)
621 {
622 itype = ALIAS;
623 }
624 else if (options == NULL || options->getStr("type").empty())
625 {
626 itype = ETHERNET;
627 }
628 else
629 {
630 itype = s_mapIfaceTypes[options->getStr("type")];
631 }
632
633 /* shortcut: unconfigured ethernet devices just exist, they don't need a config file */
634 if ((itype == ETHERNET) && (ip_address == NULL) && (iface->getAddressObject() == NULL))
635 return 0;
636
637 /* Interface name */
638 stream << "DEVICE=\"";
639 stream << name.c_str();
640 if (iface_number > 0)
641 stream << ":" << iface_number;
642 stream << "\"" << endl;
643
644 /* Boot-Protocol */
645 stream << "BOOTPROTO=\"";
646 if (iface->isDyn())
647 {
648 stream << "dhcp";
649 }
650 else
651 {
652 stream << "none";
653 }
654 stream << "\"" << endl;
655
656 /* Address object contains host, network and broadcast address plus netmask */
657 const Address* ipAddr = NULL;
658 if (ip_address != NULL)
659 ipAddr = ip_address->getAddressObject();
660
661 if (ipAddr != NULL)
662 {
663 /* Interface IP Address */
664 stream << "IPADDR=\"";
665 stream << ipAddr->getAddressPtr()->toString().c_str();
666 stream << "\"" << endl;
667
668 /* Netmask */
669 stream << "NETMASK=\"";
670 stream << ipAddr->getNetmaskPtr()->toString().c_str();
671 stream << "\"" << endl;
672
673 /* Network IP Address */
674 stream << "NETWORK=\"";
675 stream << ipAddr->getNetworkAddressPtr()->toString().c_str();
676 stream << "\"" << endl;
677
678 /* Broadcast IP Address */
679 stream << "BROADCAST=\"";
680 stream << ipAddr->getBroadcastAddressPtr()->toString().c_str();
681 stream << "\"" << endl;
682 }
683
684 /* Activate on bootup */
685 stream << "ONBOOT=\"";
686 if (options != NULL && options->getBool("iface_disableboot"))
687 {
688 stream << "no";
689 }
690 else
691 {
692 stream << "yes";
693 }
694 stream << "\"" << endl;
695
696 /* Link */
697 stream << "LINK=\"";
698 if (options != NULL)
699 {
700 stream << options->getStr("iface_options").c_str();
701 }
702 stream << "\"" << endl;
703
704 /* MAC-Address */
705 stream << "MACADDR=\"";
706 physAddress* macAddr = iface->getPhysicalAddress();
707 if (macAddr != NULL)
708 {
709 stream << macAddr->getPhysAddress().c_str();
710 }
711 stream << "\"" << endl;
712
713 /* MTU */
714 s.clear();
715 stream << "MTU=\"";
716 if (options == NULL || (s = options->getStr("iface_mtu").c_str()).isEmpty())
717 {
718 /* TODO: Extract magic value */
719 /* Set to "sane" default: "1500" */
720 s = "1500";
721 }
722 stream << s;
723 stream << "\"" << endl;
724
725 /* Activate ARP */
726 stream << "ARP=\"";
727 if (options != NULL && options->getBool("iface_disablearp"))
728 {
729 stream << "no";
730 }
731 else
732 {
733 stream << "yes";
734 }
735 stream << "\"" << endl;
736
737 /* Interface type */
738 stream << "TYPE=\"";
739 stream << s_mapIfaceStrings[itype].c_str();
740 stream << "\"" << endl;
741
742 /* get all direct children of type interface */
743 list<FWObject *> basedevs = iface->getByType(Interface::TYPENAME);
744
745 /* Type-specific parameter handling */
746 switch (itype)
747 {
748 case BRIDGE:
749 /* Fall-through */
750 case BONDING:
751 /* Iterate over all child interfaces */
752 if (basedevs.empty())
753 {
754 abort("No base device specified for " + name);
755 }
756 else
757 {
758 vector<string> devs;
759 for (list<FWObject *>::iterator it = basedevs.begin(); it != basedevs.end(); it++)
760 {
761 Interface *iface = Interface::cast(*it);
762 assert(NULL != iface);
763 if (!(iface->getName().empty()))
764 {
765 devs.push_back(iface->getName());
766 generateInterfaceFile(iface);
767 }
768 }
769
770 /* Base Device */
771 stream << "BASEDEV=\"";
772 stream << stringify(devs," ").c_str();
773 stream << "\"" << endl;
774 }
775 break;
776
777 case VLAN:
778 if (options == NULL || options->getStr("vlan_id").empty())
779 {
780 abort("No VLAN id specified for " + name);
781 }
782
783 stream << "VLANID=\"";
784 stream << options->getStr("vlan_id").c_str();
785 stream << "\"" << endl;
786
787 if (iface->getParent() == NULL || iface->getParent()->getName().empty())
788 {
789 /* No base device provided */
790 abort("No base device specified for " + name);
791 }
792
793 stream << "BASEDEV=\"";
794 stream << iface->getParent()->getName().c_str();
795 stream << "\"" << endl;
796
797 generateInterfaceFile(Interface::cast(iface->getParent()));
798 break;
799
800 case CLUSTER:
801 if (options->getStr("base_device").empty())
802 {
803 /* No base device provided */
804 abort("No base device specified for " + name);
805 }
806
807 stream << "BASEDEV=\"";
808 stream << options->getStr("base_device").c_str();
809 stream << "\"" << endl;
810 break;
811
812 case ALIAS:
813 /* Base Device for secondary interfaces*/
814 stream << "BASEDEV=\"";
815 stream << name.c_str();
816 stream << "\"" << endl;
817 break;
818
819 default:
820 /* Don't define BASEDEV */
821 break;
822 }
823
824
825 /* Write actual interface file */
826 string filename = fw->getName() + "/" + iface_filename + name;
827 if (iface_number > 0)
828 {
829 stringstream tmp;
830 tmp << ":" << iface_number;
831 filename += tmp.str();
832 }
833 stringToFile(stream.string()->toStdString(), filename);
834
835 cout << " wrote " << filename << " successfully" << endl << flush;
836
837 return 0;
838 }
839
840 template <class T>
toString(const T & t)841 inline std::string toString (const T& t)
842 {
843 std::stringstream ss;
844 ss << t;
845 return ss.str();
846 }
847
generateInterfaces()848 int OSConfigurator_secuwall::generateInterfaces()
849 {
850 /* clean up possibly stale interface files */
851 string nwdir = fw->getName() + "/" + networkscripts_dir;
852
853 QDir d(nwdir.c_str());
854 QStringList entries = d.entryList();
855
856 for (QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry)
857 {
858 if (*entry != "." && *entry != "..")
859 {
860 d.remove(*entry);
861 }
862 }
863
864 int vrrp_count = 0;
865 /* Iterate over all top-level interfaces */
866 for (list<Interface *>::iterator it = m_ifaces.begin(); it != m_ifaces.end(); it++)
867 {
868 string ifname = (*it)->getName();
869 FWOptions *options = (*it)->getOptionsObject();
870
871 /* rename handling for our vrrp "devices" */
872 if ((options != NULL) && options->getBool("cluster_interface"))
873 {
874 ifname = "vrrp" + ::toString(vrrp_count++);
875 }
876
877 /* Iterate over all addresses */
878 FWObjectTypedChildIterator j = (*it)->findByType(IPv4::TYPENAME);
879 int count = 0;
880 for (; j != j.end(); ++j, ++count)
881 {
882 IPv4 *address = IPv4::cast(*j);
883 generateInterfaceFile (*it, ifname, address, count);
884 }
885 }
886
887 return 0;
888 }
889
stringToFile(const std::string data,const std::string filename,const QIODevice::OpenMode mode) const890 int OSConfigurator_secuwall::stringToFile(const std::string data,
891 const std::string filename,
892 const QIODevice::OpenMode mode) const
893 {
894 QFile file (QString (filename.c_str()));
895
896 if (!file.open (mode))
897 {
898 cerr << "Unable to open file " << filename << endl;
899 }
900
901 qint64 byte_count = file.write (data.c_str());
902 if (byte_count == -1)
903 {
904 cerr << "Unable to write data to file " << filename << endl;
905 }
906 if (data.length() != (unsigned int) byte_count)
907 {
908 cerr << "Unable to write all data (" << byte_count << " of " << data.length() << " bytes) to file " << filename << endl;
909 }
910 file.close();
911 file.setPermissions (QFile::ReadOwner|QFile::WriteOwner|QFile::ReadGroup|QFile::ReadOther);
912
913 return 0;
914 }
915
generateSSHKeys()916 int OSConfigurator_secuwall::generateSSHKeys()
917 {
918 int i;
919 string cmd;
920 QString pwd = QDir::currentPath();
921 string filename;
922 string hostKey_file;
923 string fwadmin_keyfilename;
924 QFile file (filename.c_str());
925
926 /* TODO: Rewrite with popen for error handling */
927 /* Generate RSA Keys */
928 filename = fw->getName() + "/" + ssh_dir + "/ssh_host_rsa_key";
929 if (!QFile::exists(filename.c_str()))
930 {
931 cmd = "ssh-keygen -t rsa -b 2048 -f " + pwd.toStdString() + "/" + filename + " -C root@" + fw->getName() + " -P \"\" 2>&1";
932 i = system(cmd.c_str());
933 }
934 else
935 {
936 cout << " Found existing RSA key: skipping key generation." << endl;
937 }
938
939 /* Generate DSA Keys */
940 filename = fw->getName() + "/" + ssh_dir + "/ssh_host_dsa_key";
941 if (!QFile::exists(filename.c_str()))
942 {
943 cmd = "ssh-keygen -t dsa -f " + pwd.toStdString() + "/" + filename + " -C root@" + fw->getName() + " -P \"\" 2>&1";
944 i = system(cmd.c_str());
945 }
946 else
947 {
948 cout << " Found existing DSA key: skipping key generation." << endl;
949 }
950
951 Q_UNUSED(i);
952
953 /* Add RSA pub key of fwadmin to the firewall's known hosts file */
954 fwadmin_keyfilename = getenv("HOME");
955 fwadmin_keyfilename += fwadmin_ssh_key;
956 QFile fwadmin_ssh_keyfile(fwadmin_keyfilename.c_str());
957 filename = pwd.toStdString() + "/" + fw->getName() + "/" + ssh_dir + "/authorized_keys2";
958 if (!QFile::exists(filename.c_str()))
959 {
960 if (fwadmin_ssh_keyfile.open(QIODevice::ReadOnly))
961 {
962 /* Temporary storage for file content */
963 QString stream_string;
964 QTextStream stream(&stream_string);
965 stream << fwadmin_ssh_keyfile.readAll();
966 fwadmin_ssh_keyfile.close();
967 /* Write actual authorized_keys2 file */
968 stringToFile(stream.string()->toStdString(),
969 fw->getName() + "/" + ssh_dir + "/authorized_keys2");
970
971 QFile::setPermissions (filename.c_str(), QFile::ReadOwner|QFile::ReadGroup);
972 }
973 else
974 {
975 cout << " Unable to open " << fwadmin_keyfilename << endl;
976 }
977 }
978 else
979 {
980 cout << " Found existing key authorization file: skipping addition of management key." << endl;
981 }
982
983 /* Add RSA host key of firewall to the fwadmin's known hosts file */
984 string hostKey_filename = getenv("HOME");
985 hostKey_filename += fwadmin_known_hosts;
986 QFile host_key_file(hostKey_filename.c_str());
987 bool keyPresent = false;
988 /* Check if hosts key file exists */
989 if (host_key_file.exists())
990 {
991 /* Check if key entry is present */
992 host_key_file.open(QIODevice::ReadOnly);
993 QTextStream known_hosts(&host_key_file);
994 QString tmp;
995 while(!known_hosts.atEnd())
996 {
997 known_hosts >> tmp;
998 if (containsFirewallKey(tmp.toStdString()))
999 keyPresent = true;
1000 }
1001 host_key_file.close();
1002 }
1003
1004 if (!keyPresent)
1005 {
1006 filename = pwd.toStdString() + "/" + fw->getName() + "/" + ssh_dir + "/ssh_host_rsa_key.pub";
1007 QFile ssh_keyfile(filename.c_str());
1008 if (ssh_keyfile.open(QIODevice::ReadOnly))
1009 {
1010 /* Temporary storage for file content */
1011 QString stream_string;
1012 QTextStream stream(&stream_string);
1013 stream << fw->getName().c_str() << " ";
1014 stream << ssh_keyfile.readAll();
1015 ssh_keyfile.close();
1016
1017 /* Append entry to authorized_keys2 file */
1018 stringToFile(stream.string()->toStdString(), hostKey_filename, QIODevice::Append);
1019 }
1020 else
1021 {
1022 cout << " Unable to open firewall public key" << endl;
1023 }
1024 }
1025 else
1026 {
1027 cout << " Found existing authorization entry: skipping addition of firewall key." << endl;
1028 }
1029
1030 cout << " generated SSH keys successfully" << endl << flush;
1031
1032 return 0;
1033 }
1034
1035 /* TODO: Put in utility library */
containsFirewallKey(string in) const1036 bool OSConfigurator_secuwall::containsFirewallKey(string in) const
1037 {
1038 string match = "root@"+fw->getName();
1039 if (match == in)
1040 return true;
1041 else
1042 return false;
1043 }
1044
printPathForAllTools(const string &)1045 string OSConfigurator_secuwall::printPathForAllTools(const string &)
1046 {
1047 return OSConfigurator_linux24::printPathForAllTools("secuwall");
1048 }
1049
getGeneratedFiles() const1050 map<string, string> OSConfigurator_secuwall::getGeneratedFiles() const
1051 {
1052 map<string, string> files;
1053 return files;
1054 }
1055