1 /*
2 
3                           Firewall Builder
4 
5                  Copyright (C) 2003-2011 NetCitadel, LLC
6 
7   Author:  Vadim Kurland     vadim@fwbuilder.org
8 
9   This program is free software which we release under the GNU General Public
10   License. You may redistribute and/or modify this program under the terms
11   of that license as published by the Free Software Foundation; either
12   version 2 of the License, or (at your option) any later version.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   To get a copy of the GNU General Public License, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22 */
23 
24 #include "config.h"
25 #include "global.h"
26 #include "utils.h"
27 #include "utils_no_qt.h"
28 #include "platforms.h"
29 
30 #include "newFirewallDialog.h"
31 #include "ObjConflictResolutionDialog.h"
32 #include "upgradePredicate.h"
33 #include "FWBSettings.h"
34 #include "FWBTree.h"
35 #include "events.h"
36 #include "FWBApplication.h"
37 #include "QDesktopWidget"
38 #include "networkZoneManager.h"
39 #include "ObjConflictResolutionDialog.h"
40 
41 #include "interfaceProperties.h"
42 #include "interfacePropertiesObjectFactory.h"
43 
44 #include "fwbuilder/Library.h"
45 #include "fwbuilder/Firewall.h"
46 #include "fwbuilder/Resources.h"
47 #include "fwbuilder/Policy.h"
48 #include "fwbuilder/BackgroundOp.h"
49 #include "fwbuilder/IPv4.h"
50 #include "fwbuilder/IPv6.h"
51 #include "fwbuilder/Constants.h"
52 
53 #include <QLineEdit>
54 #include <QTextEdit>
55 #include <QSpinBox>
56 #include <QComboBox>
57 #include <QPushButton>
58 #include <QToolButton>
59 #include <QRadioButton>
60 #include <QCheckBox>
61 #include <QTreeWidget>
62 #include <QTableWidget>
63 #include <QTextBrowser>
64 #include <QMessageBox>
65 #include <QTimer>
66 #include <QListWidget>
67 #include <QApplication>
68 #include <QCursor>
69 #include <QPixmapCache>
70 #include <QFileDialog>
71 #include <QDir>
72 #include <QtDebug>
73 
74 #include <algorithm>
75 #include <iostream>
76 
77 // must be the last for win
78 #include "fwbuilder/snmp.h"
79 
80 using namespace libfwbuilder;
81 using namespace std;
82 
83 
84 #define NAME_AND_PLATFORM_PAGE 0
85 #define INTERFACES_MANUAL_OR_SNMP 1
86 #define CONFIGURE_INTERFACES_MANUALLY 2
87 #define CONFIGURE_SECURITY_LEVELS 3
88 #define CONFIGURE_NETWORK_ZONES 4
89 #define CHOOSE_FW_TEMPLATE 5
90 #define CONFIGURE_TEMPLATE_INTERFACES_MANUALLY 6
91 
92 
newFirewallDialog(QWidget * parentw,FWObject * _p)93 newFirewallDialog::newFirewallDialog(QWidget *parentw, FWObject *_p) :
94     QDialog(parentw)
95 {
96 
97     db_orig = _p->getRoot();
98     db_copy = new FWObjectDatabase();
99     db_copy->duplicate(db_orig, false);
100 
101     parent = db_copy->getById(_p->getId(), true);
102 
103     m_dialog = new Ui::newFirewallDialog_q;
104     m_dialog->setupUi(this);
105 
106     possible_inside_interface_labels.push_back("inside");
107     possible_inside_interface_labels.push_back("GREEN");
108     possible_inside_interface_labels.push_back("green");
109 
110     possible_outside_interface_labels.push_back("outside");
111     possible_outside_interface_labels.push_back("RED");
112     possible_outside_interface_labels.push_back("red");
113 
114     possible_dmz_interface_labels.push_back("dmz");
115     possible_dmz_interface_labels.push_back("ORANGE");
116     possible_dmz_interface_labels.push_back("orange");
117 
118 
119     setControlWidgets(this, m_dialog->stackedWidget,
120                       m_dialog->nextButton,
121                       m_dialog->finishButton,
122                       m_dialog->backButton,
123                       m_dialog->cancelButton,
124                       m_dialog->titleLabel);
125 
126     nfw = NULL;
127     tmpldb = NULL;
128     snmpPollCompleted = false;
129     q = NULL;
130     unloadTemplatesLib = false;
131     getInterfacesBusy = false;
132 
133     timer = new QTimer(this);
134     connect( timer, SIGNAL(timeout()), this, SLOT(monitor()));
135     connect( m_dialog->selectCustomTemplateLib, SIGNAL(pressed()),
136              this, SLOT(browseTemplate()));
137     connect( m_dialog->useStandard, SIGNAL(toggled(bool)),
138              this, SLOT(updateTemplatePanel()));
139     connect( m_dialog->useTemplate, SIGNAL(released()),
140              this, SLOT(updateTemplatePanel()));
141 
142     m_dialog->useStandard->setChecked(true);
143     m_dialog->templateFilePath->setText(
144         Constants::getTemplatesObjectsFilePath().c_str());
145     updateTemplatePanel();
146 
147     /* fill in platform. Since iptables is the most popular, start with
148      * it.
149      */
150     QString new_fw_platform = st->getNewFirewallPlatform();
151 
152     /* if new_fw_platform is empty, the drop-down list will have empty
153      * item which will be current. This is so only on the first run of
154      * the program because it remembers chosen platform and uses it on
155      * subsequent runs.
156      */
157     setPlatform(m_dialog->platform, new_fw_platform);
158 
159     /* fill in host OS  */
160     setHostOS(m_dialog->hostOS, readPlatform(m_dialog->platform), "");
161 
162     setNextEnabled( NAME_AND_PLATFORM_PAGE, false );
163 
164     //m_dialog->iface_sl_list->setAllColumnsShowFocus( true );
165     QTimer::singleShot(0, m_dialog->obj_name, SLOT(setFocus()));
166 
167     currentTemplate = NULL;
168     this->m_dialog->interfaceEditor1->clear();
169     this->m_dialog->interfaceEditor2->clear();
170     this->m_dialog->interfaceEditor1->closeTab();
171     this->m_dialog->interfaceEditor2->closeTab();//->removeTab(0);
172 
173     this->m_dialog->interfaceEditor1->setExplanation(
174         tr("Interfaces with the type set to 'Dynamic IP address' get "
175            "IP address by means of DHCP or PPP protocol and do not "
176            "require an address here. Interfaces with the type set to "
177            "'Static IP address' have statically configured IP address "
178            "which should be entered on this page. Interface can have "
179            "several IPv4 and IPv6 addresses.")
180     );
181 
182     this->m_dialog->interfaceEditor2->setExplanation(
183         tr("Here you can change IP address of the template interface "
184            "to match addresses used on your network. "
185            "Interface can have several IPv4 and "
186            "IPv6 addresses.")
187     );
188 
189     this->resize(this->width(), this->minimumHeight());
190     int maxheight = (int)(app->desktop()->height()*0.9);
191     if (this->height() > maxheight)
192         this->resize(this->width(), maxheight);
193 
194     showPage(NAME_AND_PLATFORM_PAGE);
195 }
196 
browseTemplate()197 void newFirewallDialog::browseTemplate()
198 {
199     QString fileName = QFileDialog::getOpenFileName(
200         this, tr("FWBuilder template files"), st->getOpenFileDir(),
201         tr("FWBuilder template files (*.xml *.fwb *.fwl)"));
202 
203     if (fileName.isEmpty()) return;
204     st->setOpenFileDir(fileName);
205 
206     m_dialog->templateFilePath->setText(fileName);
207     updateTemplatePanel();
208 }
209 
useStandardTemplate()210 void newFirewallDialog::useStandardTemplate()
211 {
212     m_dialog->templateFilePath->setText(
213         Constants::getTemplatesObjectsFilePath().c_str());
214     updateTemplatePanel();
215 }
216 
updateTemplatePanel()217 void newFirewallDialog::updateTemplatePanel()
218 {
219     if (st->customTemplatesEnabled() &&
220         m_dialog->useTemplate->checkState()==Qt::Checked)
221     {
222         QString fileName = m_dialog->templateFilePath->text();
223         bool using_std = m_dialog->useStandard->isChecked();
224 
225         m_dialog->templateGroupBox->setVisible(true);
226         m_dialog->templateFilePathLabel->setVisible(true);
227         m_dialog->templateFilePath->setVisible(true);
228         m_dialog->templateLibExplanation->setVisible(true);
229 
230         m_dialog->templateFilePath->setEnabled(!using_std);
231         m_dialog->selectCustomTemplateLib->setEnabled(!using_std);
232 
233         if (using_std)
234         {
235             m_dialog->templateFilePath->setText(
236                 Constants::getTemplatesObjectsFilePath().c_str());
237         }
238     }
239     else
240     {
241         m_dialog->templateGroupBox->setVisible(false);
242     }
243 }
244 
~newFirewallDialog()245 newFirewallDialog::~newFirewallDialog()
246 {
247     delete m_dialog;
248     if (timer!=NULL) delete timer;
249 #ifdef HAVE_LIBSNMP
250     if (q!=NULL) delete q;
251 #endif
252     delete db_copy;
253 }
254 
changed()255 void newFirewallDialog::changed()
256 {
257     int p = currentPage();
258 
259     if (fwbdebug)
260         qDebug() << "newFirewallDialog::changed() page=" << p
261                  << "use_manual=" << m_dialog->use_manual->isChecked()
262                  << "use_snmp=" << m_dialog->use_snmp->isChecked();
263 
264     if (p==NAME_AND_PLATFORM_PAGE)
265     {
266         setNextEnabled(p,
267                        !m_dialog->obj_name->text().isEmpty() &&
268                        !readPlatform(m_dialog->platform).isEmpty()
269         );
270         setHostOS(m_dialog->hostOS, readPlatform(m_dialog->platform), "");
271         QString host_os = readHostOS(m_dialog->hostOS);
272         m_dialog->interfaceEditor1->setHostOS(host_os);
273         m_dialog->interfaceEditor2->setHostOS(host_os);
274     }
275 
276     if (p==INTERFACES_MANUAL_OR_SNMP)
277     {
278 
279         bool use_snmp = false;
280 
281 #ifdef HAVE_LIBSNMP
282         use_snmp = m_dialog->use_snmp->isChecked();
283 #else
284         use_snmp = false;
285         m_dialog->use_snmp->setEnabled( use_snmp );
286 #endif
287         m_dialog->snmpIP->setEnabled( use_snmp );
288         m_dialog->snmp_community->setEnabled( use_snmp );
289         m_dialog->snmpQuery->setEnabled( use_snmp );
290         m_dialog->snmpProgress->setEnabled( use_snmp );
291         if ( use_snmp ) m_dialog->snmp_community->setFocus();
292 
293         if (use_snmp)
294         {
295             getIPAddressOfFirewallByName();
296         }
297 
298         use_snmp = m_dialog->use_manual->isChecked() || snmpPollCompleted;
299         setNextEnabled( 1, use_snmp );
300     }
301 
302     if (fwbdebug)
303         qDebug() << "newFirewallDialog::changed() done";
304 }
305 
getIPAddressOfFirewallByName()306 void newFirewallDialog::getIPAddressOfFirewallByName()
307 {
308     getInterfacesBusy = true;
309 
310     m_dialog->snmpIP->setText("");
311 
312     QString name = m_dialog->obj_name->text().toLatin1().constData();
313     QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
314     QString addr = getAddrByName(name, AF_INET);
315     QApplication::restoreOverrideCursor();
316 
317     if (!addr.isEmpty())
318         m_dialog->snmpIP->setText(addr);
319     else
320     {
321         QMessageBox::warning(
322             this,"Firewall Builder",
323             tr("Address of %1 could not be obtained via DNS")
324             .arg(m_dialog->obj_name->text()),
325             "&Continue", QString::null, QString::null, 0, 1 );
326     }
327 
328     getInterfacesBusy = false;
329 }
330 
monitor()331 void newFirewallDialog::monitor()
332 {
333     if (logger==NULL || q==NULL) return;
334 
335 #ifdef HAVE_LIBSNMP
336 
337     if( logger->ready() )
338     {
339         QString str = logger->getLine().c_str();
340         m_dialog->snmpProgress->moveCursor( QTextCursor::End );
341         m_dialog->snmpProgress->insertPlainText( str );
342         return;
343     }
344 
345     if (q->isRunning()) return;
346 
347     timer->stop();
348 
349     QString platform = readPlatform(m_dialog->platform);
350 
351     guessOSAndPlatformFromSysDescr(q->getDescr().c_str(),
352                                    discovered_platform,
353                                    discovered_host_os,
354                                    discovered_version);
355 
356     if (fwbdebug)
357         qDebug() << "Guessed version as " << discovered_version;
358 
359 
360     map<int, InterfaceData>* intf = q->getInterfaces();
361     map<int, InterfaceData>::iterator i;
362     this->m_dialog->interfaceEditor1->clear();
363     this->m_dialog->interfaceEditor1->removeTab(0);
364     for (i=intf->begin(); i!=intf->end(); ++i)
365     {
366         InterfaceData* idata = &(i->second);
367 
368         if (fwbdebug)
369         {
370             qDebug() << "------------------------------------------------";
371             qDebug() << "id=" << idata->id.c_str();
372             qDebug() << "name=" << idata->name.c_str();
373             qDebug() << "snmp_type=" << idata->snmp_type;
374             qDebug() << "ostatus=" << idata->ostatus;
375             qDebug() << "mac_addr=" << idata->mac_addr.c_str();
376             qDebug() << "interface_type=" << idata->interface_type.c_str();
377             qDebug() << "";
378         }
379 
380         /*
381          * some special treatment of discovered interfaces for Cisco ASA devices:
382          * if mac address is reported as 00:00:00:00:00:00 or
383          * 00:00:00:anything, this is usually some kind of internal special
384          * interface and we can skip it. Examples: "_internal_loopback",
385          * "Internal-Data0/1"
386          *
387          * This is different from how Linux reports mac address of a
388          * loopback because Linux snmpd returns empty string for the
389          * loopback mac address.
390          *
391          * The name of the interface reported by ASA is like this:
392          * "Adaptive Security Appliance 'Ethernet0/0' interface"
393          *
394          * Need to strip all thie verbose description
395          */
396 
397         if (idata->ostatus)
398         {
399             guessInterfaceLabel(idata);
400 
401             if (platform == "pix" || platform == "fwsm")
402             {
403                 if ( ! idata->mac_addr.empty() && idata->snmp_type == 1 &&
404                      idata->mac_addr.find("00:00:00")==0) continue;
405 
406                 QString name = idata->name.c_str();
407                 name.replace("Adaptive Security Appliance '", "");
408                 name.replace("Cisco PIX Security Appliance '", "");
409                 name.replace("PIX Firewall '", "");
410                 name.replace("' interface", "");
411                 idata->name = name.toStdString();
412             }
413 
414             this->m_dialog->interfaceEditor1->addInterfaceFromData(idata);
415         }
416     }
417     if ( this->m_dialog->interfaceEditor1->count() == 0 )
418         this->m_dialog->interfaceEditor1->addNewInterface();
419 
420     delete q;
421     q=NULL;
422 
423 #endif
424 
425     snmpPollCompleted=true;
426     setNextEnabled( INTERFACES_MANUAL_OR_SNMP, true );
427 }
428 
getInterfacesViaSNMP()429 void newFirewallDialog::getInterfacesViaSNMP()
430 {
431 #ifdef HAVE_LIBSNMP
432 
433 // need to protect from reentry because getAddrByName processes events
434     if (q!=NULL || getInterfacesBusy) return;
435 
436     snmpPollCompleted=false;
437     m_dialog->interfaceEditor1->clear();
438 
439     string rcomm=m_dialog->snmp_community->text().toLatin1().constData();
440 
441     if ( rcomm.empty() )
442     {
443         QMessageBox::warning(
444             this,"Firewall Builder",
445             tr("Missing SNMP community string."),
446             "&Continue", QString::null, QString::null, 0, 1 );
447         return ;
448     }
449 
450     getInterfacesBusy = true;
451 
452     InetAddr addr;
453     try
454     {
455         addr = InetAddr(m_dialog->snmpIP->text().toStdString());
456     }
457     catch (FWException &ex)
458     {
459         try
460         {
461             QApplication::setOverrideCursor( QCursor( Qt::WaitCursor) );
462             QString a = getAddrByName(m_dialog->snmpIP->text(), AF_INET);
463             QApplication::restoreOverrideCursor();
464 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
465             addr = InetAddr(a.toAscii().constData());
466 #else
467             addr = InetAddr(a.toLatin1().constData());
468 #endif
469             getInterfacesBusy = false;
470         }
471         catch (FWException &ex)
472         {
473             QMessageBox::warning(
474                 this,"Firewall Builder",
475                 tr("Address of %1 could not be obtained via DNS")
476                 .arg(m_dialog->snmpIP->text()),
477                 "&Continue", QString::null, QString::null, 0, 1 );
478             getInterfacesBusy = false;
479             return ;
480         }
481     }
482 
483     logger = NULL;
484     m_dialog->snmpProgress->clear();
485 
486     if (q!=NULL) delete q;
487 
488     q = new SNMP_interface_query();
489     q->init(addr.toString(), rcomm, SNMP_DEFAULT_RETRIES, SNMP_DEFAULT_TIMEOUT);
490 
491     timer->setSingleShot(false);
492     timer->start(0);
493 
494     try
495     {
496         logger = q->start_operation();
497 
498     } catch(const FWException &ex)
499     {
500         //do nothing
501     }
502 
503     getInterfacesBusy = false;
504 
505 #endif
506 }
507 
interfaceCompare(libfwbuilder::Interface * first,libfwbuilder::Interface * second)508 bool interfaceCompare(libfwbuilder::Interface *first,
509                       libfwbuilder::Interface *second)
510 {
511     return first->getName() < second->getName();
512 }
513 
appropriate(const int page) const514 bool newFirewallDialog::appropriate(const int page) const
515 {
516     switch (page)
517     {
518     case NAME_AND_PLATFORM_PAGE:
519     case CHOOSE_FW_TEMPLATE:
520         return true;
521 
522     case INTERFACES_MANUAL_OR_SNMP:
523     case CONFIGURE_INTERFACES_MANUALLY:
524     case CONFIGURE_SECURITY_LEVELS:
525     case CONFIGURE_NETWORK_ZONES:
526         return (!m_dialog->useTemplate->isChecked());
527     }
528     return true;
529 }
530 
nextClicked()531 void newFirewallDialog::nextClicked()
532 {
533     if ( currentPage() == CHOOSE_FW_TEMPLATE )
534     {
535         if (m_dialog->templateList->currentItem() == NULL)
536         {
537             QMessageBox::warning(
538                     this,"Firewall Builder",
539                     tr("Please select template"),
540                     tr("&Continue"), QString::null,QString::null,
541                     0, 1 );
542             showPage(CHOOSE_FW_TEMPLATE);
543             return;
544         }
545     }
546 
547     if ( currentPage() == CONFIGURE_INTERFACES_MANUALLY )
548         if ( !this->m_dialog->interfaceEditor1->isValid() )
549             return;
550 
551     // FakeWizard::nextRelevant() finds next (in the numerical order)
552     // page that is permitted by function appropriate() and returns
553     // its number
554     if (nextRelevant( currentPage() ) > -1)
555         showPage(nextRelevant( currentPage() ));
556 }
557 
backClicked()558 void newFirewallDialog::backClicked()
559 {
560     if (previousRelevant( currentPage() ) > -1)
561         showPage(previousRelevant( currentPage() ));
562 }
563 
showPage(const int page)564 void newFirewallDialog::showPage(const int page)
565 {
566     FakeWizard::showPage(page);
567 
568     int p = page;
569 
570     if (fwbdebug)
571         qDebug() << "newFirewallDialog::showPage  page=" << page;
572 
573 // p is a page number _after_ it changed
574     switch (p)
575     {
576     case NAME_AND_PLATFORM_PAGE:
577         // we get here if user hits "Back" on page 4 (where they
578         // choose template object)
579         if (tmpldb!=NULL)
580         {
581             m_dialog->templateList->clear();
582             delete tmpldb;
583             tmpldb = NULL;
584         }
585         m_dialog->nextButton->setDefault(true);
586         m_dialog->obj_name->setFocus();
587         break;
588 
589     case INTERFACES_MANUAL_OR_SNMP:
590     {
591 // page 1 is where we choose to configure interfaces manually or via snmp
592         m_dialog->snmpIP->setText("");
593         changed();  // to properly enable/disable widgets
594         m_dialog->nextButton->setDefault(true);
595         break;
596     }
597 
598     case CONFIGURE_INTERFACES_MANUALLY:
599     {
600         if (!Resources::getTargetCapabilityBool(
601                 readPlatform(m_dialog->platform).toLatin1().constData(),
602                 "security_levels") )
603         {
604 
605 /* if chosen fw platform does not support security levels,
606  * this is the last page
607  */
608             setNextEnabled( CONFIGURE_INTERFACES_MANUALLY, false );
609             setFinishEnabled( CONFIGURE_INTERFACES_MANUALLY, true );
610             m_dialog->finishButton->setDefault(true);
611         }
612         break;
613     }
614 
615     case CONFIGURE_SECURITY_LEVELS:
616     {
617         if (m_dialog->useTemplate->isChecked())
618         {
619             showPage( NAME_AND_PLATFORM_PAGE );
620             return;
621         }
622 
623         // Edit security levels
624         fillInterfaceSLList();
625 
626         setNextEnabled( CONFIGURE_SECURITY_LEVELS, true );
627         setFinishEnabled( CONFIGURE_SECURITY_LEVELS, false );
628         m_dialog->nextButton->setDefault(true);
629         break;
630     }
631 
632     case CONFIGURE_NETWORK_ZONES:
633     {
634         if (m_dialog->useTemplate->isChecked())
635         {
636             showPage( NAME_AND_PLATFORM_PAGE );
637             return;
638         }
639 
640         // Edit network zones
641         fillInterfaceNZList();
642 
643         setNextEnabled(CONFIGURE_NETWORK_ZONES, false );
644         setFinishEnabled(CONFIGURE_NETWORK_ZONES, true );
645         m_dialog->finishButton->setDefault(true);
646         break;
647     }
648 
649     case CHOOSE_FW_TEMPLATE:
650     {
651         // Show firewall templates
652         setFinishEnabled( CHOOSE_FW_TEMPLATE, false );
653         setNextEnabled( CHOOSE_FW_TEMPLATE, true );
654 
655         // load templates if not loaded
656         if (tmpldb==NULL)
657         {
658 
659             MessageBoxUpgradePredicate upgrade_predicate(this);
660             tmpldb = new FWObjectDatabase();
661             tmpldb->setReadOnly( false );
662             try
663             {
664 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
665                 tmpldb->load(
666                     m_dialog->templateFilePath->text().toAscii().data(),
667                     &upgrade_predicate, Constants::getDTDDirectory());
668 #else
669                 tmpldb->load(
670                     m_dialog->templateFilePath->text().toLatin1().data(),
671                     &upgrade_predicate, Constants::getDTDDirectory());
672 #endif
673             }
674             catch (FWException &ex)
675             {
676                 QMessageBox::critical(
677                     this,"Firewall Builder",
678                     tr("Error loading template library:\n%1")
679                     .arg(ex.toString().c_str()),
680                     tr("&Continue"), QString::null,QString::null,
681                     0, 1 );
682             }
683         }
684 
685         // nfw != NULL if user clicked Back on one of the subsequent
686         // pages because we create firewall object when they click
687         // Next on the page where they choose template ( see case
688         // CONFIGURE_TEMPLATE_INTERFACES_MANUALLY below)
689         if (nfw)
690         {
691             parent->remove(nfw, false);
692             delete nfw;
693             nfw = NULL;
694         }
695 
696         list<FWObject*> fl;
697 
698         FWObjectTypedChildIterator libiter = tmpldb->findByType(Library::TYPENAME);
699         for ( ; libiter!=libiter.end(); ++libiter)
700             findFirewalls(*libiter, fl, false);
701 
702         QString icn = ":/Icons/Firewall/icon-tree";
703 
704         m_dialog->templateList->clear();
705 
706         int n = 0;
707         QListWidgetItem *first_template = NULL;
708         for (list<FWObject*>::iterator m=fl.begin(); m!=fl.end(); m++,n++)
709         {
710             FWObject *o = *m;
711 
712 /*
713   Ticket #1492 requested the change to only show the user templates
714   that match platform and host OS they choose on the first page of the
715   wizard.
716 
717   Unfortunately this does not really work because most templates have
718   platform and host OS set to "unknown". Either we have to maintain
719   many almost identical templates to provide enough choices for all
720   possible platforms, or we should not filter by platform.
721 
722 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
723             string platform = readPlatform(m_dialog->platform).toAscii().constData();
724             string host_os = readHostOS(m_dialog->hostOS).toAscii().constData();
725 #else
726             string platform = readPlatform(m_dialog->platform).toLatin1().constData();
727             string host_os = readHostOS(m_dialog->hostOS).toLatin1().constData();
728 #endif
729             if (o->getStr("platform") != platform || o->getStr("host_OS") != host_os)
730                 continue;
731 */
732 
733             QPixmap pm;
734             if ( ! QPixmapCache::find( icn, pm) )
735             {
736                 pm.load( icn );
737                 QPixmapCache::insert( icn, pm);
738             }
739 
740             QListWidgetItem *twi = new QListWidgetItem;
741             twi->setIcon( QIcon(pm) );
742             twi->setText( QString(o->getName().c_str()) );
743 
744             m_dialog->templateList->addItem( twi );
745             templates[ m_dialog->templateList->item(
746                     m_dialog->templateList->count()-1 ) ] = o;
747 
748             if (first_template == NULL) first_template = twi;
749         }
750 
751         m_dialog->templateList->setFocus();
752         m_dialog->templateList->setCurrentItem(first_template,
753                                                QItemSelectionModel::SelectCurrent);
754         m_dialog->finishButton->setDefault(false);
755         m_dialog->nextButton->setDefault(true);
756         break;
757     }
758 
759     case CONFIGURE_TEMPLATE_INTERFACES_MANUALLY:
760     {
761         // Edit interfaces of the template object
762         createFirewallFromTemplate();
763         setFinishEnabled( CONFIGURE_TEMPLATE_INTERFACES_MANUALLY, true );
764 
765         this->m_dialog->interfaceEditor2->clear();
766         this->m_dialog->interfaceEditor2->closeTab();//->removeTab(0);
767         this->m_dialog->interfaceEditor2->setCornerWidgetsVisible(false);
768         QList<Interface*> interfaces;
769         FWObjectTypedChildIterator intiter = nfw->findByType(Interface::TYPENAME);
770         for ( ; intiter != intiter.end(); ++intiter )
771             interfaces.append(Interface::cast(*intiter));
772         sort(interfaces.begin(), interfaces.end(), interfaceCompare);
773         foreach(Interface* intr, interfaces)
774             m_dialog->interfaceEditor2->addInterface(intr);
775         m_dialog->finishButton->setDefault(true);
776     }
777     }
778 }
779 
getInterfaceDataFromInterfaceEditor(EditedInterfaceData & edata,InterfaceData & idata)780 void newFirewallDialog::getInterfaceDataFromInterfaceEditor(
781     EditedInterfaceData &edata, InterfaceData &idata)
782 {
783     idata.name  = edata.name.toStdString();
784     idata.label = edata.label.toStdString();
785     AddressInfo address;
786     bool gotIPv4 = false;
787     foreach(AddressInfo addr, edata.addresses.values())
788     {
789         if (addr.ipv4)
790         {
791             address = addr;
792             gotIPv4 = true;
793             break;
794         }
795     }
796 
797     InetAddrMask *iam;// = new InetAddrMask();
798     if (edata.type == 0 && edata.addresses.size() != 0)
799     {
800         if (!gotIPv4) address = edata.addresses.values().first();
801         if ( address.ipv4 )
802             iam = new InetAddrMask(
803                 InetAddr(address.address.toStdString()),
804                 InetAddr(address.netmask.toStdString()));
805         else
806         {
807             iam = new InetAddrMask(
808                 InetAddr(AF_INET6, address.address.toStdString()),
809                 InetAddr(AF_INET6, address.netmask.toStdString()));
810         }
811         idata.addr_mask.push_back(iam);
812     }
813 
814     if (gotIPv4)
815     {
816         try
817         {
818             guessSecurityLevel(
819                 readPlatform(m_dialog->platform).toStdString(), &idata);
820         }
821         catch (FWException &ex)
822         {
823             QMessageBox::warning(
824                 this,"Firewall Builder", ex.toString().c_str(),
825                 "&Continue", QString::null, QString::null, 0, 1 );
826             showPage( CONFIGURE_INTERFACES_MANUALLY );
827             return;
828         }
829     }
830     else idata.securityLevel = 0;
831 }
832 
fillInterfaceSLList()833 void newFirewallDialog::fillInterfaceSLList()
834 {
835     m_dialog->iface_sl_list->clear();
836 
837     QStringList labels;
838     labels << QObject::tr("Name") << QObject::tr("Label")
839            << QObject::tr("Address") << QObject::tr("Security Level");
840     m_dialog->iface_sl_list->setHorizontalHeaderLabels(labels);
841 
842     int row = 0;
843     foreach(EditedInterfaceData iface,
844             this->m_dialog->interfaceEditor1->getData().values() +
845             this->m_dialog->interfaceEditor1->getNewData())
846     {
847         InterfaceData idata;
848 
849         getInterfaceDataFromInterfaceEditor(iface, idata);
850 
851         m_dialog->iface_sl_list->insertRow(row);
852 
853         QTableWidgetItem* itm;
854 
855         itm = new QTableWidgetItem(iface.name);
856         itm->setFlags(itm->flags() & ~Qt::ItemIsEditable);
857         m_dialog->iface_sl_list->setItem(row, 0, itm);
858 
859         itm = new QTableWidgetItem(iface.label);
860         itm->setFlags(itm->flags() & ~Qt::ItemIsEditable);
861         m_dialog->iface_sl_list->setItem(row, 1, itm);
862 
863         QString addr_str;
864         if (iface.addresses.size() > 0)
865         {
866             AddressInfo addr = *(iface.addresses.begin());
867             addr_str = addr.address;
868         }
869 
870         itm = new QTableWidgetItem(addr_str);
871         itm->setFlags(itm->flags() & ~Qt::ItemIsEditable);
872         m_dialog->iface_sl_list->setItem(row, 2, itm);
873 
874         //itm = new QTableWidgetItem(QString::number(idata.securityLevel));
875         QSpinBox *widget = new QSpinBox();
876         widget->setMaximum(100);
877         widget->setMinimum(0);
878         widget->setValue(idata.securityLevel);
879         m_dialog->iface_sl_list->setCellWidget(row, 3, widget);
880 
881         row++;
882     }
883 }
884 
fillInterfaceNZList()885 void newFirewallDialog::fillInterfaceNZList()
886 {
887     m_dialog->iface_nz_list->clear();
888 
889     QStringList labels;
890     labels << QObject::tr("Name") << QObject::tr("Label")
891            << QObject::tr("Address") << QObject::tr("Network Zone");
892     m_dialog->iface_nz_list->setHorizontalHeaderLabels(labels);
893 
894     NetworkZoneManager netzone_manager;
895     netzone_manager.load(db_copy);
896 
897     int row = 0;
898     foreach(EditedInterfaceData iface,
899             this->m_dialog->interfaceEditor1->getData().values() +
900             this->m_dialog->interfaceEditor1->getNewData())
901     {
902         InterfaceData idata;
903 
904         getInterfaceDataFromInterfaceEditor(iface, idata);
905 
906         m_dialog->iface_nz_list->insertRow(row);
907 
908         QTableWidgetItem* itm;
909 
910         itm = new QTableWidgetItem(iface.name);
911         itm->setFlags(itm->flags() & ~Qt::ItemIsEditable);
912         m_dialog->iface_nz_list->setItem(row, 0, itm);
913 
914         itm = new QTableWidgetItem(iface.label);
915         itm->setFlags(itm->flags() & ~Qt::ItemIsEditable);
916         m_dialog->iface_nz_list->setItem(row, 1, itm);
917 
918         QString addr_str;
919         if (iface.addresses.size() > 0)
920         {
921             AddressInfo addr = *(iface.addresses.begin());
922             addr_str = addr.address;
923         }
924 
925         itm = new QTableWidgetItem(addr_str);
926         itm->setFlags(itm->flags() & ~Qt::ItemIsEditable);
927         m_dialog->iface_nz_list->setItem(row, 2, itm);
928 
929         QComboBox *widget = new QComboBox();
930         netzone_manager.packComboBox(widget, -1);
931         m_dialog->iface_nz_list->setCellWidget(row, 3, widget);
932 
933         row++;
934     }
935 
936     m_dialog->iface_nz_list->resizeColumnToContents(3);
937 }
938 
939 /*
940  * this slot is connected to currentItemChanged signal of templateList
941  * As a side effect, this slot is called when we clear templateList.
942  */
templateSelected(QListWidgetItem * itm)943 void newFirewallDialog::templateSelected(QListWidgetItem *itm)
944 {
945     if (templates.size()==0) return;
946     FWObject *o = templates[itm];
947     if (o==NULL) return;
948     this->m_dialog->interfaceEditor2->setTemplate(o);
949     currentTemplate = o;
950 
951     Firewall *fw = Firewall::cast(o);
952 
953     m_dialog->templateComment->clear();
954     QString s = QString("<a name=\"top\">\n") + fw->getComment().c_str();
955     m_dialog->templateComment->append( s );
956     m_dialog->templateComment->scrollToAnchor("top");
957 
958     bool haveOutside = false;
959     bool haveInside  = false;
960     bool haveDMZ     = false;
961     list<FWObject*> ll = fw->getByType(Interface::TYPENAME);
962     for (FWObject::iterator i=ll.begin(); i!=ll.end(); i++)
963     {
964         Interface *intf = Interface::cast( *i );
965         if (std::find(possible_outside_interface_labels.begin(),
966                       possible_outside_interface_labels.end(),
967                       intf->getLabel()) != possible_outside_interface_labels.end())
968         {
969             haveOutside=true;
970             m_dialog->intfOutsideLine->show();
971             m_dialog->intfOutsideText->show();
972             fillInterfaceData(intf,m_dialog->intfOutsideText);
973         }
974 
975         if (std::find(possible_inside_interface_labels.begin(),
976                       possible_inside_interface_labels.end(),
977                       intf->getLabel()) != possible_inside_interface_labels.end())
978         {
979             haveInside=true;
980             m_dialog->intfInsideLine->show();
981             m_dialog->intfInsideText->show();
982             fillInterfaceData(intf,m_dialog->intfInsideText);
983         }
984 
985         if (std::find(possible_dmz_interface_labels.begin(),
986                       possible_dmz_interface_labels.end(),
987                       intf->getLabel()) != possible_dmz_interface_labels.end())
988         {
989             haveDMZ=true;
990             m_dialog->intfDMZLine->show();
991             m_dialog->intfDMZText->show();
992             fillInterfaceData(intf,m_dialog->intfDMZText);
993         }
994     }
995 
996     if (!haveOutside) { m_dialog->intfOutsideLine->hide(); m_dialog->intfOutsideText->hide(); }
997     if (!haveInside)  { m_dialog->intfInsideLine->hide();  m_dialog->intfInsideText->hide();  }
998     if (!haveDMZ)     { m_dialog->intfDMZLine->hide();     m_dialog->intfDMZText->hide();     }
999 }
1000 
fillInterfaceData(Interface * intf,QTextBrowser * qte)1001 void newFirewallDialog::fillInterfaceData(Interface *intf, QTextBrowser *qte)
1002 {
1003     qte->clear();
1004     QString s;
1005 
1006     s += "<table border='0' cellspacing='0' cellpadding='0'>";
1007 
1008     s += "<tr>";
1009     s += "<td>";
1010     s +=  tr("Interface: %1 (%2)")
1011         .arg(intf->getName().c_str())
1012         .arg(intf->getLabel().c_str());
1013     s += "</td>";
1014     s += "</tr>";
1015 
1016     s += "<tr>";
1017     s += "<td>";
1018     if (intf->isDyn()) s +=  tr("Dynamic address");
1019     else
1020         if (intf->isUnnumbered()) s +=  tr("Unnumbered interface");
1021         else
1022         {
1023             const InetAddr *addr = intf->getAddressPtr();
1024             QString addr_str = (addr) ? addr->toString().c_str() : "";
1025             const InetAddr *netm = intf->getNetmaskPtr();
1026             QString netm_str = (netm) ? netm->toString().c_str() : "";
1027             s += QString("%1/%2").arg(addr_str).arg(netm_str);
1028         }
1029     s += "</td>";
1030     s += "</tr>";
1031     s += "</table>";
1032     qte->setText(s);
1033 }
1034 
validateAddressAndMask(const QString & addr,const QString & netm)1035 bool newFirewallDialog::validateAddressAndMask(const QString &addr,
1036                                            const QString &netm)
1037 {
1038     try
1039     {
1040         InetAddr(addr.toLatin1().constData());
1041     }
1042     catch (FWException &ex)
1043     {
1044         QMessageBox::warning(
1045             this,"Firewall Builder",
1046             tr("Invalid address '%1/%2'").arg(addr).arg(netm),
1047             "&Continue", QString::null, QString::null, 0, 1 );
1048         return false;
1049     }
1050     try
1051     {
1052         bool ok = false ;
1053         int ilen = netm.toInt (&ok);
1054         if (ok)
1055         {
1056             if (ilen < 0 || ilen > 32)
1057             {
1058                 QMessageBox::warning(
1059                     this,"Firewall Builder",
1060                     tr("Invalid address '%1/%2'").arg(addr).arg(netm),
1061                     "&Continue", QString::null, QString::null, 0, 1 );
1062                 return false;
1063             }
1064         }
1065         else
1066         {
1067             InetAddr(netm.toLatin1().constData());
1068         }
1069 
1070     }
1071     catch (FWException &ex)
1072     {
1073         QMessageBox::warning(
1074             this,"Firewall Builder",
1075             tr("Invalid address '%1/%2'").arg(addr).arg(netm),
1076             "&Continue", QString::null, QString::null, 0, 1 );
1077         return false;
1078     }
1079     return true;
1080 }
1081 
cleanup()1082 void newFirewallDialog::cleanup()
1083 {
1084     if (nfw)
1085     {
1086         parent->remove(nfw, false);
1087         delete nfw;
1088         nfw = NULL;
1089     }
1090 
1091     if (tmpldb)
1092     {
1093         delete tmpldb;
1094         tmpldb = NULL;
1095     }
1096 }
1097 
cancelClicked()1098 void newFirewallDialog::cancelClicked()
1099 {
1100     cleanup();
1101     reject();
1102 }
1103 
finishClicked()1104 void newFirewallDialog::finishClicked()
1105 {
1106     // getting focus to close table cell editor
1107     // see #1594
1108     m_dialog->finishButton->setFocus(Qt::OtherFocusReason);
1109 
1110     if (fwbdebug)
1111         qDebug() << "newFirewallDialog::finishClicked()"
1112                  << "currentPage()=" << currentPage();
1113 
1114     if ((!this->m_dialog->useTemplate->isChecked()) &&
1115         currentPage() == CONFIGURE_INTERFACES_MANUALLY)
1116     {
1117         if ( !this->m_dialog->interfaceEditor1->isValid() )
1118             return;
1119     }
1120 
1121     if ( currentPage() == CONFIGURE_TEMPLATE_INTERFACES_MANUALLY )
1122         if ( !this->m_dialog->interfaceEditor2->isValid() )
1123             return;
1124 
1125 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
1126     string platform = readPlatform(m_dialog->platform).toAscii().constData();
1127     string host_os = readHostOS(m_dialog->hostOS).toAscii().constData();
1128 #else
1129     string platform = readPlatform(m_dialog->platform).toLatin1().constData();
1130     string host_os = readHostOS(m_dialog->hostOS).toLatin1().constData();
1131 #endif
1132 
1133     st->setNewFirewallPlatform(platform.c_str());
1134 
1135     if (currentPage()==CONFIGURE_INTERFACES_MANUALLY)  fillInterfaceSLList();
1136 
1137     if (currentPage()==CHOOSE_FW_TEMPLATE ||
1138         currentPage()==CONFIGURE_TEMPLATE_INTERFACES_MANUALLY)
1139     {
1140         // Creating from a template
1141         if (nfw==NULL) createFirewallFromTemplate();
1142         else
1143             changedAddressesInNewFirewall();
1144 
1145     } else
1146     {
1147         // Create from interface list (obtained either manually or via snmp)
1148         if ( !this->m_dialog->interfaceEditor1->isValid() )
1149             return;
1150 
1151         FWObject *o;
1152         o = db_copy->create(Firewall::TYPENAME);
1153 
1154         if (o==NULL)
1155         {
1156             QDialog::accept();
1157             return;
1158         }
1159 
1160         o->setName( string( m_dialog->obj_name->text().toUtf8().constData() ) );//.toStdString());
1161         parent->add(o);
1162 
1163         nfw = Firewall::cast(o);
1164 
1165         o->setStr("platform", platform);
1166         Resources::setDefaultTargetOptions(platform , nfw);
1167 
1168         o->setStr("host_OS", host_os);
1169         Resources::setDefaultTargetOptions(host_os , nfw);
1170 
1171         if ( ! discovered_version.isEmpty())
1172             o->setStr("version", discovered_version.toStdString());
1173 
1174 /* create interfaces */
1175 
1176         foreach(EditedInterfaceData iface,
1177                 this->m_dialog->interfaceEditor1->getNewData())
1178         {
1179             QString name     =  iface.name;
1180             QString label    =  iface.label;
1181             bool    dyn      =  iface.type == 1;
1182             bool    unnum    =  iface.type == 2;
1183             QString physaddr =  iface.mac;
1184             int     sec_level = 0;
1185             string  network_zone_str_id = "";
1186 
1187             QList<QTableWidgetItem*> ltwi =
1188                 m_dialog->iface_sl_list->findItems( name , Qt::MatchExactly );
1189 
1190             if ( ! ltwi.empty())
1191             {
1192                 QTableWidgetItem *itm2 = ltwi[0];
1193                 assert(itm2!=NULL);
1194                 int row = itm2->row();
1195                 QSpinBox *sb = dynamic_cast<QSpinBox*>(
1196                     m_dialog->iface_sl_list->cellWidget(row, 3));
1197                 assert(sb!=NULL);
1198                 sec_level = sb->value();
1199             }
1200 
1201             ltwi = m_dialog->iface_nz_list->findItems( name , Qt::MatchExactly );
1202             if ( ! ltwi.empty())
1203             {
1204                 QTableWidgetItem *itm2 = ltwi[0];
1205                 assert(itm2!=NULL);
1206                 int row = itm2->row();
1207                 QComboBox *cb = dynamic_cast<QComboBox*>(
1208                     m_dialog->iface_nz_list->cellWidget(row, 3));
1209                 assert(cb!=NULL);
1210                 int network_zone_int_id =
1211                     cb->itemData(cb->currentIndex(), Qt::UserRole).toInt();
1212                 if (network_zone_int_id != 0)
1213                     network_zone_str_id = FWObjectDatabase::getStringId(
1214                         network_zone_int_id);
1215                 else
1216                     network_zone_str_id = "";
1217             }
1218 
1219             Interface *oi = Interface::cast(db_copy->create(Interface::TYPENAME));
1220             assert(oi!=NULL);
1221 
1222             nfw->add(oi);
1223 
1224             oi->setName( string(name.toUtf8().constData()) );
1225             oi->setLabel( string(label.toUtf8().constData()) );
1226             oi->setComment( string(iface.comment.toUtf8().constData()) );
1227 
1228             oi->setDyn(dyn);
1229             oi->setUnnumbered(unnum);
1230             oi->setSecurityLevel(sec_level);
1231 
1232             // only set network zone if it is supported and is not empty. See #2014
1233             if (!network_zone_str_id.empty())
1234                 oi->setStr("network_zone", network_zone_str_id);
1235 
1236             std::auto_ptr<interfaceProperties> int_prop(
1237                 interfacePropertiesObjectFactory::getInterfacePropertiesObject(nfw));
1238             if (int_prop->looksLikeVlanInterface(name))
1239             {
1240                 QString base_name;
1241                 int vlan_id;
1242                 int_prop->parseVlan(name, &base_name, &vlan_id);
1243 
1244                 oi->getOptionsObject()->setStr("type", "8021q");
1245                 oi->getOptionsObject()->setInt("vlan_id", vlan_id);
1246             }
1247 
1248 
1249             if (iface.type == 0)
1250             {
1251                 foreach(AddressInfo address, iface.addresses)
1252                 {
1253                     if (address.address == "0.0.0.0") continue;
1254                     if (address.ipv4)
1255                     {
1256                         string addrname = string( QString("%1:%2:ip").arg(QString(m_dialog->obj_name->text())).arg(name).toUtf8().constData() );
1257                         IPv4 *oa = IPv4::cast(db_copy->create(IPv4::TYPENAME));
1258                         oi->add(oa);
1259                         oa->setName(addrname);
1260                         oa->setAddress( InetAddr(address.address.toLatin1().constData()) );
1261                         bool ok = false ;
1262                         int inetmask = address.netmask.toInt(&ok);
1263                         if (ok)
1264                         {
1265                             oa->setNetmask( InetAddr(inetmask) );
1266                         }
1267                         else
1268                         {
1269                             oa->setNetmask( InetAddr(address.netmask.toLatin1().constData()) );
1270                         }
1271                     }
1272                     else
1273                     {
1274                         string addrname = string ( QString("%1:%2:ip6").arg(QString(m_dialog->obj_name->text())).arg(name).toUtf8().constData() );
1275                         IPv6 *oa = IPv6::cast(db_copy->create(IPv6::TYPENAME));
1276                         oi->add(oa);
1277                         oa->setName(addrname);
1278                         oa->setAddress(InetAddr(AF_INET6, address.address.toLatin1().constData()) );
1279                         bool ok = false ;
1280                         int inetmask = address.netmask.toInt(&ok);
1281                         if (ok)
1282                         {
1283                             oa->setNetmask( InetAddr(AF_INET6, inetmask) );
1284                         }
1285                         else
1286                         {
1287                             oa->setNetmask(InetAddr(AF_INET6, address.netmask.toLatin1().constData()));
1288                         }
1289                     }
1290                 }
1291             }
1292         }
1293     }
1294 
1295     // merge dbcopy into db
1296 
1297     CompareObjectsDialog cod(this);
1298     db_orig->merge(db_copy, &cod);
1299     db_orig->fixTree();
1300 
1301     nfw = Firewall::cast(db_orig->findInIndex(nfw->getId()));
1302 
1303     if (tmpldb!=NULL)
1304     {
1305         delete tmpldb;
1306         tmpldb = NULL;
1307     }
1308 
1309     QDialog::accept();
1310 }
1311 
1312 
1313