Files
fwbuilder/src/libgui/instDialog_ui_ops.cpp
T

1459 lines
44 KiB
C++

/*
Firewall Builder
Copyright (C) 2008 NetCitadel, LLC
Author: Vadim Kurland vadim@fwbuilder.org
$Id$
This program is free software which we release under the GNU General Public
License. You may redistribute and/or modify this program under the terms
of that license as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
To get a copy of the GNU General Public License, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../../config.h"
#include "global.h"
#include "utils.h"
#include "utils_no_qt.h"
#include "instDialog.h"
#include "FirewallInstaller.h"
#include "FWBSettings.h"
#include "FWWindow.h"
#include "InstallFirewallViewItem.h"
#include "instOptionsDialog.h"
#include "instBatchOptionsDialog.h"
#include "UserWorkflow.h"
#include "FirewallCodeViewer.h"
#include <qcheckbox.h>
#include <qlineedit.h>
#include <qtextedit.h>
#include <qtimer.h>
#include <qfiledialog.h>
#include <qpushbutton.h>
#include <qlabel.h>
#include <qprogressbar.h>
#include <qprocess.h>
#include <qapplication.h>
#include <qeventloop.h>
#include <qfile.h>
#include <qdir.h>
#include <qmessagebox.h>
#include <qspinbox.h>
#include <qgroupbox.h>
#include <qcolor.h>
#include <qtablewidget.h>
#include <qtextcodec.h>
#include <qfileinfo.h>
#include <qtextstream.h>
#include <qpixmapcache.h>
#include <QPixmap>
#include <QDateTime>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QTreeWidgetItemIterator>
#include <QTextBlockFormat>
#include <QBrush>
#include <QTextFormat>
#include <QtDebug>
#include <QTime>
#include "fwbuilder/Resources.h"
#include "fwbuilder/FWObjectDatabase.h"
#include "fwbuilder/Library.h"
#include "fwbuilder/Firewall.h"
#include "fwbuilder/Cluster.h"
#include "fwbuilder/XMLTools.h"
#include "fwbuilder/Interface.h"
#include "fwbuilder/Management.h"
#include "fwbuilder/StateSyncClusterGroup.h"
#ifndef _WIN32
# include <unistd.h> // for access(2) and getdomainname
#endif
#include <errno.h>
#include <iostream>
#include <algorithm>
using namespace std;
using namespace libfwbuilder;
void instDialog::enableStopButton()
{
currentStopButton->setText(tr("Stop"));
currentStopButton->setEnabled(true);
}
void instDialog::disableStopButton()
{
currentStopButton->setEnabled(false);
}
bool instDialog::checkIfNeedToCompile(Firewall *fw)
{
return (fw->needsCompile() && !fw->getInactive());
}
bool instDialog::checkIfNeedToInstall(Firewall *fw)
{
return (fw->needsInstall() && !fw->getInactive());
}
QTreeWidgetItem* instDialog::createTreeItem(QTreeWidgetItem* parent,
Firewall *fw)
{
QTreeWidgetItem* item;
QStringList sl;
sl.push_back(QString::fromUtf8(fw->getName().c_str()));
if (parent)
item = new QTreeWidgetItem(parent, sl);
else
item = new QTreeWidgetItem(sl);
QString icn_filename = (":/Icons/" + fw->getTypeName() + "/icon").c_str();
QPixmap pm;
if ( ! QPixmapCache::find(icn_filename, pm))
{
pm.load(icn_filename);
QPixmapCache::insert(icn_filename, pm);
}
item->setIcon(0, QIcon(pm));
item->setData(0, Qt::UserRole, QVariant(fw->getId()));
// Mark cluster members
// If parent!=NULL, new tree item corresponds to the cluster member
item->setData(1, Qt::UserRole, QVariant(parent!=NULL));
// it is useful to know how many members does this cluster have. If this is
// not a cluster, store 0
list<Firewall*> members;
if (Cluster::isA(fw))
Cluster::cast(fw)->getMembersList(members);
int num_members = members.size();
item->setData(2, Qt::UserRole, QVariant(num_members));
// item->setCheckState(COMPILE_CHECKBOX_COLUMN, checkIfNeedToCompile(fw)?Qt::Checked:Qt::Unchecked);
// if (!compile_only)
// item->setCheckState(INSTALL_CHECKBOX_COLUMN, checkIfNeedToInstall(fw)?Qt::Checked:Qt::Unchecked);
return item;
}
void instDialog::setFlags(QTreeWidgetItem* item)
{
int obj_id = item->data(0, Qt::UserRole).toInt();
Firewall *fw = Firewall::cast(project->db()->findInIndex(obj_id));
QTreeWidgetItem* parent = item->parent();
time_t lm = fw->getInt("lastModified");
time_t lc = fw->getInt("lastCompiled");
time_t li = fw->getInt("lastInstalled");
QDateTime dt;
if (fwbdebug)
{
qDebug() << "instDialog::setFlags"
<< item->text(0)
<< "parent=" << parent
<< "fw=" << fw
<< "Firewall::isA(fw)=" << Firewall::isA(fw)
<< "lm=" << lm
<< "lc=" << lc
<< "li=" << li
<< "compile_only=" << compile_only;
qDebug() << "fw->needsCompile()" << fw->needsCompile()
<< "checkIfNeedToCompile(fw)=" << checkIfNeedToCompile(fw);
}
// need to skip the secondary cluster members if platform only
// allows installations on the primary (e.g. PIX). Note that
// platform attribute must be the same in the cluster and member
// firewalls objects. See #998
string platform = fw->getStr("platform");
bool install_only_on_primary_member = Resources::getTargetCapabilityBool(
platform, "install_only_on_primary");
Cluster *cluster = NULL;
FWObject *master_interface = NULL;
if (parent)
{
int obj_id = parent->data(0, Qt::UserRole).toInt();
cluster = Cluster::cast(project->db()->findInIndex(obj_id));
if (cluster)
{
FWObject *state_sync_group =
cluster->getFirstByType(StateSyncClusterGroup::TYPENAME);
// use state sync group to find which member firewall is
// master. This is only needed for platforms that install
// only on master (PIX at this time)
if (state_sync_group)
{
string master_id = state_sync_group->getStr("master_iface");
for (FWObjectTypedChildIterator grp_it =
state_sync_group->findByType(FWObjectReference::TYPENAME);
grp_it != grp_it.end(); ++grp_it)
{
FWObject *iface = FWObjectReference::getObject(*grp_it);
if (FWObjectDatabase::getStringId(iface->getId()) == master_id)
{
master_interface = iface;
break;
}
}
}
}
}
// Real firewalls get checkbox for install
if (Firewall::isA(fw))
{
bool checked = false;
if (!compile_only)
{
checked = checkIfNeedToInstall(fw);
if (cluster)
{
// override if checkIfNeedToCompile() is true for the
// parent cluster.
if (checkIfNeedToCompile(cluster))
{
checked = true;
}
}
item->setCheckState(INSTALL_CHECKBOX_COLUMN,
checked?Qt::Checked:Qt::Unchecked);
// If this platform requires installation only on
// the master, disable and uncheck checkbox for the standby.
if (install_only_on_primary_member && master_interface != NULL)
{
QString txt = item->text(0);
if (master_interface->isChildOf(fw))
{
// Master
item->setText(0, QString("%1 (master)").arg(txt));
} else
{
// Standby
item->setText(0, QString("%1 (standby)").arg(txt));
item->setCheckState(INSTALL_CHECKBOX_COLUMN, Qt::Unchecked);
item->setFlags(0);
}
}
}
if (cluster==NULL)
{
// we are adding firewall that is not cluster member, it
// needs "compile" checkbox
checked = checkIfNeedToCompile(fw);
item->setCheckState(COMPILE_CHECKBOX_COLUMN,
checked?Qt::Checked:Qt::Unchecked);
}
}
int num_members = 0;
// Clusters only get checkbox for compile, and only if they have members.
if (Cluster::isA(fw))
{
list<Firewall*> members;
Cluster::cast(fw)->getMembersList(members);
num_members = members.size();
if (num_members)
{
bool checked = checkIfNeedToCompile(fw);
item->setCheckState(COMPILE_CHECKBOX_COLUMN,
checked?Qt::Checked:Qt::Unchecked);
}
}
dt.setTime_t(lm);
item->setText(LAST_MODIFIED_COLUMN, (lm)?dt.toString():QString("Never"));
dt.setTime_t(lc);
item->setText(LAST_COMPILED_COLUMN, (lc)?dt.toString():QString("Never"));
dt.setTime_t(li);
item->setText(LAST_INSTALLED_COLUMN, (li)?dt.toString():QString("Never"));
}
/*
* The following color and font manipulations are subject to QT bug
* http://trolltech.no/developer/task-tracker/index_html?method=entry&id=212207
*
* This requires QT 4.4.1 or 4.3
*/
void instDialog::setSuccessState(QTreeWidgetItem *item)
{
QBrush b = item->foreground(1);
b.setColor(Qt::darkGreen);
item->setForeground(1,b);
item->setForeground(0,b);
QFont f = item->font(1);
f.setBold(true);
item->setFont(1,f);
item->setFont(0,f);
}
void instDialog::setFailureState(QTreeWidgetItem *item)
{
QBrush b = item->foreground(1);
b.setColor(Qt::darkRed);
item->setForeground(1,b);
item->setForeground(0,b);
QFont f = item->font(1);
f.setBold(true);
item->setFont(1,f);
item->setFont(0,f);
}
void instDialog::setErrorState(QTreeWidgetItem *item)
{
QBrush b = item->foreground(1);
b.setColor(Qt::darkRed);
item->setForeground(1,b);
item->setForeground(0,b);
QFont f = item->font(1);
f.setBold(true);
item->setFont(1,f);
item->setFont(0,f);
}
void instDialog::setInProcessState(QTreeWidgetItem *item)
{
QBrush b = item->foreground(1);
b.setColor(Qt::black);
item->setForeground(1,b);
item->setForeground(0,b);
QFont f = item->font(1);
f.setBold(true);
item->setFont(1,f);
item->setFont(0,f);
}
void instDialog::opSuccess(Firewall *fw)
{
if (fwbdebug)
qDebug() << "instDialog::opSuccess fw=" << fw->getName().c_str();
compile_status[fw] = fwcompiler::BaseCompiler::FWCOMPILER_SUCCESS;
QTreeWidgetItem* itm = opListMapping[(fw)->getId()];
if (itm)
{
itm->setText(1,tr("Success"));
setSuccessState(itm);
}
currentLabel->setText("");
if (installer)
wfl->registerFlag(UserWorkflow::INSTALL_SUCCESS, true);
}
void instDialog::opError(Firewall *fw)
{
if (fwbdebug)
qDebug() << "instDialog::opError fw=" << fw->getName().c_str();
compile_status[fw] = fwcompiler::BaseCompiler::FWCOMPILER_ERROR;
QTreeWidgetItem* itm = opListMapping[(fw)->getId()];
if (itm)
{
itm->setText(1, tr("Error"));
setErrorState(itm);
}
currentLabel->setText("");
}
void instDialog::opCancelled(Firewall *fw)
{
compile_status[fw] = fwcompiler::BaseCompiler::FWCOMPILER_ERROR;
QTreeWidgetItem* itm = opListMapping[(fw)->getId()];
// itm can be NULL, for example when we install to PIX cluster
// where we skip one of the members
if (itm)
{
itm ->setText(1, tr("Cancelled"));
setErrorState(itm);
}
currentLabel->setText("");
}
void instDialog::nextClicked()
{
if (currentPage() == CHOOSE_OBJECTS)
{
page_1_op = INST_DLG_COMPILE;
showPage(COMPILE_INSTALL);
return;
}
if (currentPage() == COMPILE_INSTALL &&
(page_1_op == INST_DLG_COMPILE || page_1_op == INST_DLG_INSPECT))
{
// clicking "Next" on page 1 (compile/install) changes
// contents of the same page
page_1_op = INST_DLG_INSTALL;
showPage(COMPILE_INSTALL);
return;
}
}
void instDialog::backClicked()
{
if (currentPage() == COMPILE_INSTALL && page_1_op == INST_DLG_COMPILE)
{
// clicking "Back" on page 1 in mode "compile" returns to page 0
page_1_op = INST_DLG_COMPILE;
showPage(CHOOSE_OBJECTS);
return;
}
if (currentPage() == COMPILE_INSTALL && page_1_op == INST_DLG_INSTALL)
{
// clicking "Back" on page 1 in mode "install" changes
// contents of the same page. Ideally, I would like to be
// able to move back from "install" mode to "compile" mode
// without recompiling everything. This is impossible in the
// current implementation because we reuse the same widgets on
// the page. This will be possible when "install" becomes its
// own page of the wizard.
// page_1_op = INST_DLG_COMPILE;
// showPage(COMPILE_INSTALL);
return;
}
if (currentPage() == COMPILE_INSTALL && page_1_op == INST_DLG_INSPECT)
{
page_1_op = INST_DLG_COMPILE;
showPage(COMPILE_INSTALL);
return;
}
}
void instDialog::inspectFiles()
{
page_1_op = INST_DLG_INSPECT;
showPage(COMPILE_INSTALL);
}
void instDialog::prepareInstConf(Firewall *)
{
if (fwbdebug) qDebug("instDialog::prepareInstConf");
}
void instDialog::storeInstallerOptions()
{
st->setValue(SETTINGS_PATH_PREFIX"/Installer/savediff",cnf.save_diff);
st->setValue(SETTINGS_PATH_PREFIX"/Installer/saveStandby",cnf.saveStandby);
st->setValue(SETTINGS_PATH_PREFIX"/Installer/dryrun" ,cnf.dry_run);
st->setValue(SETTINGS_PATH_PREFIX"/Installer/quiet", cnf.quiet);
st->setValue(SETTINGS_PATH_PREFIX"/Installer/verbose", cnf.verbose);
st->setValue(SETTINGS_PATH_PREFIX"/Installer/stripComments", cnf.stripComments);
st->setValue(SETTINGS_PATH_PREFIX"/Installer/compressScript", cnf.compressScript);
st->setValue(SETTINGS_PATH_PREFIX"/Installer/copyFWB", cnf.copyFWB);
}
void instDialog::summary()
{
QStringList str;
str.append(QObject::tr("Summary:"));
str.append(QObject::tr("* Running as user : %1").arg(user_name));
str.append(QObject::tr("* Firewall name : %1")
.arg(QString::fromUtf8(cnf.fwobj->getName().c_str())));
str.append(QObject::tr("* Installer uses user name : %1").arg(cnf.user));
// print destination machine address or name correctly, taking into
// account putty session if any
if (!cnf.putty_session.isEmpty())
str.append(QObject::tr("* Using putty session: %1").arg(cnf.putty_session));
else
str.append(QObject::tr("* Management address : %1").arg(cnf.maddr));
str.append(QObject::tr("* Platform : %1")
.arg(cnf.fwobj->getStr("platform").c_str()));
str.append(QObject::tr("* Host OS : %1")
.arg(cnf.fwobj->getStr("host_OS").c_str()));
str.append(QObject::tr("* Loading configuration from file %1")
.arg(cnf.fwbfile));
if (cnf.save_diff)
str.append(QObject::tr("* Configuration diff will be saved in file %1").
arg(cnf.diff_file));
if (cnf.dry_run)
str.append(QObject::tr("* Commands will not be executed on the firewall"));
if (fwbdebug)
{
str.append(QObject::tr("--------------------------------"));
str.append(QObject::tr("* Variables:"));
str.append(QObject::tr("* fwdir= %1") .arg(cnf.fwdir));
str.append(QObject::tr("* fwscript= %1") .arg(cnf.fwscript));
str.append(QObject::tr("* remote_script= %1") .arg(cnf.remote_script));
}
str.append("");
QTextCursor cursor = m_dialog->procLogDisplay->textCursor();
cursor.insertBlock();
cursor.insertText(str.join("\n"), highlight_format);
}
void instDialog::fillCompileSelectList()
{
if (fwbdebug) qDebug("instDialog::fillCompileSelectList");
Firewall *fw;
Cluster *cl;
QDateTime dt;
creatingTable = true;
m_dialog->selectTable->clear();
list<Firewall*> working_list_of_firewalls = firewalls;
for (list<Cluster *>::iterator i=clusters.begin(); i!=clusters.end(); ++i)
{
cl = *i;
QTreeWidgetItem* cluster_item = createTreeItem(NULL, cl);
m_dialog->selectTable->addTopLevelItem(cluster_item);
list<Firewall*> members;
cl->getMembersList(members);
for (list<Firewall*>::iterator member=members.begin();
member!=members.end(); ++member)
{
createTreeItem(cluster_item, *member);
working_list_of_firewalls.remove(*member);
}
cluster_item->setExpanded(true);
}
for (list<Firewall *>::iterator i=working_list_of_firewalls.begin();
i!=working_list_of_firewalls.end(); ++i)
{
fw = *i;
QTreeWidgetItem* fw_item = createTreeItem(NULL, fw);
m_dialog->selectTable->addTopLevelItem(fw_item);
}
QTreeWidgetItemIterator it(m_dialog->selectTable);
while (*it)
{
setFlags(*it);
++it;
}
/* ticket #1305
* check if any of the firewall objects are members of clusters but
* the clusters are not requested for compile
*/
QString warn1(
tr("<b>You are trying to compile policy for a firewall object that is "
"a member of a cluster, however you requested compilation of only "
"this member firewall and not the cluster it belongs to. Assuming "
"firewall is standalone and not cluster member. Rules and parts of "
"the script specific for the cluster configuration will not be "
"generated.</b>"));
QStringList warn2;
list<FWObject*> all_libs = project->db()->getByType(Library::TYPENAME);
foreach(FWObject *lib, all_libs)
{
if (lib->getId() == FWObjectDatabase::DELETED_OBJECTS_ID) continue;
list<FWObject*> all_clusters = lib->getByTypeDeep(Cluster::TYPENAME);
foreach(FWObject *_cl, all_clusters)
{
if (std::find(clusters.begin(), clusters.end(), _cl) == clusters.end())
{
Cluster *cluster = Cluster::cast(_cl);
assert(cluster);
foreach(FWObject *fw, firewalls)
{
if (cluster->hasMember(Firewall::cast(fw)))
{
warn2 <<
QString(tr("Firewall '%1' is member of cluster '%2'")
.arg(QString::fromUtf8(fw->getName().c_str()))
.arg(QString::fromUtf8(cluster->getPath().c_str())));
}
}
}
}
}
if (!warn2.empty())
{
m_dialog->warning_message_1->setText(warn1);
m_dialog->warning_message_2->setText(warn2.join("\n"));
m_dialog->warning_space->show();
}
creatingTable = false;
for (int i=0; i<m_dialog->selectTable->columnCount(); i++)
m_dialog->selectTable->resizeColumnToContents(i);
setNextEnabled(0, tableHasCheckedItems());
//m_dialog->selectTable->resizeRowsToContents();
}
void instDialog::displayCommand(const QStringList &args)
{
QStringList a1 = args;
for (QStringList::iterator i=a1.begin(); i!=a1.end(); i++)
{
if ( (*i)=="-pw" )
{
i++;
*i = "XXXXXX";
break;
}
}
QString s=a1.join(" ");
addToLog( tr("Running command '%1'\n").arg(s) );
}
void instDialog::updateProgressBar(int n, bool setsize)
{
if (fwbdebug)
qDebug("instDialog::updateProgressBar n=%d setsize=%d",n,setsize);
if (setsize) currentProgressBar->setMaximum(n);
else
currentProgressBar->setValue(currentProgressBar->maximum()-n);
}
void instDialog::finishClicked()
{
finished = true;
accept();
}
/* user clicked 'Cancel' */
void instDialog::cancelClicked()
{
if (fwbdebug) qDebug("instDialog::cancelClicked()");
finished = true;
if (proc.state() == QProcess::Running)
{
if (fwbdebug)
qDebug() << "instDialog::cancelClicked killing background process";
rejectDialogFlag = true;
proc.kill();
}
if (installer != NULL)
{
if (fwbdebug)
qDebug() << "instDialog::cancelClicked killing installer";
installer->terminate();
delete installer;
installer = NULL;
}
QDialog::reject();
}
void instDialog::showEvent( QShowEvent *ev)
{
st->restoreGeometry(this, QRect(200,100,780,500) );
QDialog::showEvent(ev);
}
void instDialog::hideEvent( QHideEvent *ev)
{
st->saveGeometry(this);
QDialog::hideEvent(ev);
}
void instDialog::saveLog()
{
QString dir;
//if (m_dialog->procLogDisplay==NULL) return;
dir=st->getWDir();
if (dir.isEmpty()) dir=st->getOpenFileDir();
if (dir.isEmpty()) dir="~";
/*
* We use QTextEdit::append to add lines to the log buffer, each
append creates a new paragraph so QTextEdit::text returns only
contents of the last paragraph. Need to reassemble the whole text
adding text from each paragraph separately.
*/
QString logText;
logText = m_dialog->procLogDisplay->toPlainText();
QString s = QFileDialog::getSaveFileName(
this,
"Choose a file",
dir,
"Text file (*.txt)");
if (fwbdebug)
qDebug( "Saving log to file %s", s.toAscii().constData() );
if (!s.isEmpty())
{
if (!s.endsWith(".txt"))
{
s+=".txt";
}
QFile f(s);
if (f.open( QIODevice::WriteOnly ))
{
QTextStream str( &f );
str << logText;
f.close();
}
}
}
/*
* Adds one line of text to the log
*
*/
void instDialog::addToLog(const QString &buf)
{
if (buf.isEmpty()) return;
foreach(QString line, buf.trimmed().split("\n"))
{
QTextCharFormat format = normal_format;
list<QRegExp>::const_iterator it;
for (it=error_re.begin(); it!=error_re.end(); ++it)
{
if ((*it).indexIn(line) != -1)
{
format = error_format;
break;
}
}
for (it=warning_re.begin(); it!=warning_re.end(); ++it)
{
if ((*it).indexIn(line) != -1)
{
format = warning_format;
break;
}
}
/* See sourceforge bug https://sourceforge.net/tracker/?func=detail&aid=2847263&group_id=5314&atid=1070394
*
* QTextEditor::insertHtml() becomes incrementally slow as the
* amount of text already in the QTextEditor
* increases. Compiling ~10 firewalls with few dozen rules
* each slows the output to a crawl on Windows. Keeping each
* line in a separate block makes it much faster.
*/
QString txt = line;
while (!txt.isEmpty() && (txt.endsWith("\n") || txt.endsWith("\r")))
txt.chop(1);
if (format == error_format || format == warning_format )
format.setAnchorHref(txt);
QTextCursor cursor = m_dialog->procLogDisplay->textCursor();
cursor.insertBlock();
cursor.insertText(txt, format);
}
//m_dialog->procLogDisplayList->addItem(txt);
m_dialog->procLogDisplay->ensureCursorVisible();
//qApp->processEvents();
}
void instDialog::interpretLogLine(const QString &line)
{
if (fwbdebug)
qDebug("instDialog::interpretLogLine %s", line.toAscii().constData() );
QStringList words = line.trimmed().split(" ");
if (fwbdebug)
{
for (int i=0; i<words.size(); ++i)
qDebug("instDialog::interpretLogLine words[%d]='%s'",
i, words[i].toAscii().constData());
}
if (words.first().indexOf("rule")>=0)
{
bool ok;
processedRules = words[1].toInt(&ok);
if (ok)
currentProgressBar->setValue(processedRules);
if (fwbdebug)
qDebug("instDialog::interpretLogLine set progress bar current=%d",
processedRules);
} else
{
if (words.first().indexOf("processing")>=0)
{
currentProgressBar->reset();
bool ok;
int totalRules = words[1].toInt(&ok);
if (ok)
currentProgressBar->setMaximum(totalRules);
processedRules = 0;
if (fwbdebug)
qDebug("instDialog::interpretLogLine set progress bar max=%d",
totalRules);
} else
{
if (words.first().indexOf("Compiling")>=0)
{
//currentLabel->setText(line.trimmed());
currentProgressBar->reset();
} else
{
if (line.indexOf("Compiled successfully")>=0)
{
//currentLabel->setText(line.trimmed());
currentProgressBar->setValue(currentProgressBar->maximum());
if (fwbdebug)
qDebug("instDialog::interpretLogLine set progress "
"bar to max");
}
}
}
}
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents,1);
}
void instDialog::readFromStdout()
{
char buf[2048];
int read_status = 0;
while ((read_status = proc.readLine(buf, sizeof(buf)))>0)
{
if (fwbdebug)
{
qDebug("instDialog::readFromStdout: read_status=%d buf=%s",
read_status, buf);
}
addToLog(buf);
interpretLogLine(buf);
}
}
void instDialog::selectAllFirewalls()
{
if (fwbdebug) qDebug("instDialog::selectAllFirewalls");
setSelectStateAll(INSTALL_CHECKBOX_COLUMN, Qt::Checked);
setSelectStateAll(COMPILE_CHECKBOX_COLUMN, Qt::Checked);
tableItemChanged(NULL, 0);
}
void instDialog::deselectAllFirewalls()
{
setSelectStateAll(INSTALL_CHECKBOX_COLUMN, Qt::Unchecked);
setSelectStateAll(COMPILE_CHECKBOX_COLUMN, Qt::Unchecked);
tableItemChanged(NULL, 0);
}
void instDialog::setSelectStateAll(int column, Qt::CheckState select)
{
QTreeWidgetItemIterator it(m_dialog->selectTable);
while (*it)
{
int obj_id = (*it)->data(0, Qt::UserRole).toInt();
FWObject *o = project->db()->findInIndex(obj_id);
bool cluster_member = (*it)->data(1, Qt::UserRole).toBool();
int num_members = (*it)->data(2, Qt::UserRole).toInt();
Qt::ItemFlags flags = (*it)->flags();
if ((flags & Qt::ItemIsUserCheckable) != 0)
{
// firewalls only get checkboxes for install,
if (column == INSTALL_CHECKBOX_COLUMN && Firewall::isA(o))
(*it)->setCheckState(column, select);
// Cluster gets checkbox for compile.
// Cluster should never get a checkbox if it has no members.
// Firewall that is not a cluster member gets compile checkbox
if ((column == COMPILE_CHECKBOX_COLUMN && Cluster::isA(o) && num_members) ||
(Firewall::isA(o) && !cluster_member))
(*it)->setCheckState(column, select);
}
++it;
}
}
void instDialog::fillCompileOpList()
{
compile_fw_list.clear();
QTreeWidgetItemIterator it(m_dialog->selectTable);
while (*it)
{
if ((*it)->checkState(COMPILE_CHECKBOX_COLUMN))
{
int obj_id = (*it)->data(0, Qt::UserRole).toInt();
FWObject *o = project->db()->findInIndex(obj_id);
compile_fw_list.push_back(Firewall::cast(o));
}
++it;
}
compile_list_initial_size = compile_fw_list.size();
}
void instDialog::fillCompileUIList()
{
if (fwbdebug) qDebug("instDialog::fillCompileUIList");
m_dialog->fwWorkList->clear();
opListMapping.clear();
Firewall * f;
InstallFirewallViewItem * item;
list<Firewall*>::iterator i;
for(i=compile_fw_list.begin(); i!=compile_fw_list.end(); ++i)
{
f = (*i);
item = new InstallFirewallViewItem(
NULL,//m_dialog->fwWorkList,
QString::fromUtf8(f->getName().c_str()),
false);
item->setData(0, Qt::UserRole, QVariant(f->getId()));
m_dialog->fwWorkList->insertTopLevelItem(0, item);
opListMapping[f->getId()] = item;
}
m_dialog->fwWorkList->resizeColumnToContents(0);
m_dialog->fwWorkList->sortByColumn(0, Qt::AscendingOrder);
}
void instDialog::fillInstallOpList()
{
if (fwbdebug) qDebug("instDialog::fillInstallOpList");
install_fw_list.clear();
QTreeWidgetItemIterator it(m_dialog->selectTable);
while (*it)
{
if ((*it)->checkState(INSTALL_CHECKBOX_COLUMN))
{
int obj_id = (*it)->data(0, Qt::UserRole).toInt();
FWObject *o = project->db()->findInIndex(obj_id);
install_fw_list.push_back(Firewall::cast(o));
if (fwbdebug)
qDebug("fillInstallOpList: Install requested for %s", o->getName().c_str());
}
++it;
}
install_list_initial_size = install_fw_list.size();
}
void instDialog::fillInstallUIList()
{
if (fwbdebug) qDebug("instDialog::fillInstallUIList");
m_dialog->fwWorkList->clear();
opListMapping.clear();
Firewall * f;
InstallFirewallViewItem * item;
list<Firewall*>::iterator i;
for(i=install_fw_list.begin(); i!=install_fw_list.end(); ++i)
{
f = (*i);
item = new InstallFirewallViewItem(
NULL,
QString::fromUtf8(f->getName().c_str()),
false);
m_dialog->fwWorkList->insertTopLevelItem(0, item);
opListMapping[f->getId()] = item;
}
m_dialog->fwWorkList->resizeColumnToContents(0);
m_dialog->fwWorkList->sortByColumn(0, Qt::AscendingOrder);
}
void instDialog::findFirewallInCompileLog(QTreeWidgetItem* item)
{
if (fwbdebug) qDebug("instDialog::findFirewallInCompileLog");
m_dialog->detailMCframe->show();
qApp->processEvents();
QString fw_name = item->text(0);
m_dialog->procLogDisplay->moveCursor( QTextCursor::End );
m_dialog->procLogDisplay->find(currentSearchString +
fw_name,
QTextDocument::FindWholeWords |
QTextDocument::FindCaseSensitively |
QTextDocument::FindBackward);
}
void instDialog::tableItemChanged(QTreeWidgetItem*, int)
{
if (!creatingTable)
setNextEnabled(0, tableHasCheckedItems());
}
bool instDialog::tableHasCheckedItems()
{
QTreeWidgetItemIterator it(m_dialog->selectTable);
while (*it)
{
if ((*it)->checkState(COMPILE_CHECKBOX_COLUMN) ||
(*it)->checkState(INSTALL_CHECKBOX_COLUMN))
return true;
++it;
}
return false;
}
/*
* getInstOptions() fills attributes of the cnf object
*/
bool instDialog::getInstOptions(Firewall *fw, bool cancelAllVisible)
{
if (fwbdebug)
qDebug() << "instDialog::getInstOptions() begin"
<< "cnf.user=" << cnf.user
<< "cnf.maddr=" << cnf.maddr
<< "fw=" << fw;
cnf.fwobj = fw;
readInstallerOptionsFromSettings();
readInstallerOptionsFromFirewallObject(fw);
if (m_dialog->batchInstall->isChecked() && batch_inst_opt_dlg)
{
// in batch install mode we use the same dialog to fill cnf
// without showing it to the user again
readInstallerOptionsFromDialog(fw, batch_inst_opt_dlg);
} else
{
// In non-batch mode installer options from the dialog
// overwrite options set in the fw object itself.
instOptionsDialog *inst_opt_dlg = new instOptionsDialog(
this, &cnf, cancelAllVisible);
int resultCode = inst_opt_dlg->exec();
// 0 - rejected
// 1 - accepted
// -1 - cancell all clicked
if (resultCode == -1)
{
canceledAll = true;
delete inst_opt_dlg;
return false;
}
if (resultCode == QDialog::Rejected)
{
delete inst_opt_dlg;
return false;
}
readInstallerOptionsFromDialog(fw, inst_opt_dlg);
inst_opt_dlg->close();
inst_opt_dlg->deleteLater();
}
if (fwbdebug)
qDebug() << "instDialog::getInstOptions() end"
<< "cnf.user=" << cnf.user
<< "cnf.maddr=" << cnf.maddr;
return verifyManagementAddress();
}
/*
* getBatchInstOptions() fills attributes of the cnf object for batch install
*/
bool instDialog::getBatchInstOptions(Firewall *first_fw)
{
if (fwbdebug)
qDebug() << "instDialog::getBatchInstOptions() begin"
<< "cnf.user=" << cnf.user
<< "cnf.maddr=" << cnf.maddr
<< "first_fw=" << first_fw;
cnf.fwobj = first_fw; // NULL;
readInstallerOptionsFromSettings();
readInstallerOptionsFromFirewallObject(first_fw);
if (batch_inst_opt_dlg != NULL) delete batch_inst_opt_dlg;
batch_inst_opt_dlg = new instBatchOptionsDialog(this, &cnf);
if (batch_inst_opt_dlg->exec()==QDialog::Rejected)
{
stopProcessFlag = true;
this->m_dialog->finishButton->setEnabled(true);
this->m_dialog->finishButton->setDefault(true);
foreach(Firewall *fw, this->install_fw_list)
this->opCancelled(fw);
return false;
}
// clear aternative address in the dialog
batch_inst_opt_dlg->m_dialog->altAddress->setText("");
readInstallerOptionsFromDialog(NULL, batch_inst_opt_dlg);
if (fwbdebug)
qDebug() << "instDialog::getBatchInstOptions() end"
<< "cnf.user=" << cnf.user
<< "cnf.maddr=" << cnf.maddr;
return verifyManagementAddress();
}
void instDialog::readInstallerOptionsFromSettings()
{
if (fwbdebug) qDebug("instDialog::readInstallerOptionsFromSettings");
fwb_prompt="--**--**--";
cnf.batchInstall = m_dialog->batchInstall->isChecked();
cnf.save_diff = st->value(SETTINGS_PATH_PREFIX"/Installer/savediff").toBool();
cnf.saveStandby = st->value(SETTINGS_PATH_PREFIX"/Installer/saveStandby").toBool();
cnf.dry_run = st->value(SETTINGS_PATH_PREFIX"/Installer/dryrun").toBool();
cnf.quiet = st->value(SETTINGS_PATH_PREFIX"/Installer/quiet").toBool();
cnf.verbose = st->value(SETTINGS_PATH_PREFIX"/Installer/verbose" ).toBool();
cnf.stripComments = st->value(SETTINGS_PATH_PREFIX"/Installer/stripComments").toBool();
cnf.compressScript = st->value(SETTINGS_PATH_PREFIX"/Installer/compressScript").toBool();
cnf.copyFWB = st->value(SETTINGS_PATH_PREFIX"/Installer/copyFWB").toBool();
}
void instDialog::readInstallerOptionsFromFirewallObject(Firewall *fw)
{
if (fwbdebug)
qDebug() << "instDialog::readInstallerOptionsFromFirewallObject"
<< "fw=" << fw
<< QString( (fw) ? QString::fromUtf8(fw->getName().c_str()) : "");
FWOptions *fwopt = NULL;
if (fw)
{
fwopt = fw->getOptionsObject();
string platform = cnf.fwobj->getStr("platform");
string host_OS = cnf.fwobj->getStr("host_OS");
cnf.user = fwopt->getStr("admUser").c_str();
QString standard_management_addr;
// Note that Host::getManagementAddress() scans interfaces and
// finds one marked as "management" and takes its address.
// It does not use Management child object.
const InetAddr *mgmt_addr = cnf.fwobj->getManagementAddress();
if (mgmt_addr)
standard_management_addr = mgmt_addr->toString().c_str();
else
standard_management_addr = "";
QString aaddr = fwopt->getStr("altAddress").c_str();
if (fwbdebug)
qDebug() << " standard_management_addr="
<< standard_management_addr
<< "aaddr=" << aaddr;
if (!aaddr.isEmpty()) cnf.maddr = aaddr;
else cnf.maddr = standard_management_addr;
cnf.putty_session = "";
#ifdef _WIN32
/*
* See #1724. There is a problem with pscp.exe and putty
* sessions. Plink.exe accepts session name in place of the host name
* on the command line, but pscp.exe does not. We ask user to enter
* session name in the "alternative name or address to use to
* communicate with the firewall" input field in the "Installer" tab
* of the firewall settings dialog and then use it in place of the
* host name in the command line for pscp.exe and plink.exe. This
* works with plink.exe but breaks pscp.exe which interprets it as a
* host name and fails with an error ""ssh_init: Host does not exist".
*
* Will try to determine if what user entered in the "alternative host
* or address field" is a session name and use different command line
* for pscp.exe
*
*
* HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\<session_name>
*/
QSettings putty_reg(QSettings::UserScope, "SimonTatham", "PuTTY\\Sessions");
QStringList sessions = putty_reg.childGroups();
if (fwbdebug)
{
qDebug() << putty_reg.fileName();
qDebug() << "found " << sessions.size() << " putty sessions";
foreach(QString key, sessions)
{
qDebug() << "putty session " << key;
}
}
if (sessions.contains(aaddr))
{
if (fwbdebug)
qDebug() << "Found matching putty session" << aaddr;
cnf.maddr = standard_management_addr;
cnf.putty_session = aaddr;
}
#endif
/*
* if user requested test run, store firewall script in a temp
* file. Always store it in a temp file on linksys
*/
QString s;
/* user_can_change_install_dir */
bool uccid = Resources::getTargetOptionBool(
host_OS, "user_can_change_install_dir");
if (uccid) s = fwopt->getStr("firewall_dir").c_str();
if (s.isEmpty()) s = Resources::getTargetOptionStr(
host_OS, "activation/fwdir").c_str();
cnf.fwdir = s;
/*
* Generated files should be saved in the same directory where
* the .fwb file is located, except if user specified full path
* in the advaced settings dialog.
*/
cnf.script = FirewallInstaller::getGeneratedFileFullPath(fw);
// cnf.script = FirewallInstaller::getGeneratedFileName(fw);
cnf.remote_script = ""; // filled in FirewallInstaller::readManifest()
cnf.fwbfile = project->db()->getFileName().c_str();
cnf.wdir = getFileDir( project->getRCS()->getFileName() );
cnf.diff_file = QString(cnf.fwobj->getName().c_str())+".diff";
cnf.diff_pgm = Resources::platform_res[platform]->
getResourceStr("/FWBuilderResources/Target/diff").c_str();
cnf.diff_pgm = getPathToBinary(
cnf.diff_pgm.toAscii().constData()).c_str();
#ifdef _WIN32
cnf.diff_pgm = cnf.diff_pgm + ".exe";
#endif
cnf.sshArgs = fwopt->getStr("sshArgs").c_str();
cnf.scpArgs = fwopt->getStr("scpArgs").c_str();
cnf.useSCPForRouter = fwopt->getBool("use_scp");
cnf.activationCmd = fwopt->getStr("activationCmd").c_str();
if (fwbdebug)
{
qDebug("platform: %s", platform.c_str());
qDebug("host_OS: %s", host_OS.c_str());
qDebug("user_can_change_install_dir=%d", uccid);
qDebug("firewall_dir='%s'", fwopt->getStr("firewall_dir").c_str());
qDebug("management address: %s", cnf.maddr.toAscii().constData());
qDebug("cnf.fwdir='%s'", cnf.fwdir.toAscii().constData());
qDebug("activationCmd='%s'", cnf.activationCmd.toAscii().constData());
}
}
}
void instDialog::readInstallerOptionsFromDialog(Firewall *fw,
instOptionsDialog *dlg)
{
if (fwbdebug)
qDebug() << "instDialog::readInstallerOptionsFromDialog"
<< "fw=" << fw;
QString adm_user;
FWOptions *fwopt = NULL;
if (fw)
{
fwopt = cnf.fwobj->getOptionsObject();
adm_user = fwopt->getStr("admUser").c_str();
}
cnf.dry_run = dlg->m_dialog->test->isChecked();
cnf.backup_file = dlg->m_dialog->backupConfigFile->text();
cnf.backup = !cnf.backup_file.isEmpty();
cnf.save_diff = dlg->m_dialog->saveDiff->isChecked();
cnf.saveStandby = dlg->m_dialog->saveStandby->isChecked();
/* Alternative address:
- first, check dialog. User could have overriden it using dialog
- then check firewall options, user could have set it in the "Install"
tab of firewall settings dialog
- last, if all overrides are empty, take it from the management interface
*/
QString aaddr = dlg->m_dialog->altAddress->text();
if (!aaddr.isEmpty())
{
/* alternative address can also be putty session name. In any case,
* leave it up to ssh to resolve it and signal an error if it can't be
* resolved ( Putty session name does not have to be in DNS at all ).
*/
cnf.maddr = aaddr;
if (fwbdebug)
qDebug() << "alternative addr:" << aaddr;
}
// user name set in the dialog overrides that set in the fw object
// But the dialog user name input field can be left blank, in which
// case we use the one configured in the object
if (!adm_user.isEmpty()) cnf.user = adm_user;
if (!dlg->m_dialog->uname->text().isEmpty())
cnf.user = dlg->m_dialog->uname->text();
cnf.pwd = dlg->m_dialog->pwd->text();
cnf.epwd = dlg->m_dialog->epwd->text();
cnf.quiet = dlg->m_dialog->quiet->isChecked();
cnf.verbose = dlg->m_dialog->verbose->isChecked();
cnf.stripComments = dlg->m_dialog->stripComments->isChecked();
cnf.compressScript= dlg->m_dialog->compressScript->isChecked();
cnf.copyFWB = dlg->m_dialog->copyFWB->isChecked();
dlg->savePassword();
storeInstallerOptions();
}
bool instDialog::verifyManagementAddress()
{
/* check for a common error when none or multiple interfaces are marked as
* 'management'
*/
if (cnf.maddr.isEmpty() && cnf.putty_session.isEmpty() && cnf.fwobj)
{
int nmi = 0;
list<FWObject*> ll = cnf.fwobj->getByTypeDeep(Interface::TYPENAME);
for (FWObject::iterator i=ll.begin(); i!=ll.end(); i++)
{
Interface *intf = Interface::cast( *i );
if (intf->isManagement()) nmi++;
}
if (nmi>1)
{
QString err = QObject::tr("Only one interface of the firewall '%1' "
"must be marked as management interface.\n")
.arg(QString::fromUtf8(cnf.fwobj->getName().c_str()));
QMessageBox::critical(this, "Firewall Builder", err,
tr("&Continue") );
addToLog(err);
return false;
}
if (nmi==0)
{
QString err = QObject::tr(
"One of the interfaces of the firewall '%1' "
"must be marked as management interface. "
"To set the management interface, double click "
"on the interface of the firewall that you will "
"connect to and check the box called Management "
"interface in the Editor panel")
.arg(QString::fromUtf8(cnf.fwobj->getName().c_str()));
QMessageBox::critical(this, "Firewall Builder", err,
tr("&Continue") );
addToLog(err);
return false;
}
if (cnf.maddr == "" ||
cnf.maddr == QString(InetAddr::getAny().toString().c_str()))
{
QString err = QObject::tr(
"Management interface does not have IP address, "
"can not communicate with the firewall.\n");
QMessageBox::critical(this, "Firewall Builder", err,
tr("&Continue") );
addToLog(err);
return false;
}
}
return true;
}
void instDialog::logItemClicked(QUrl data)
{
QStringList parts = data.toString().split(':');
if (parts[0] == "Error") return;
if (parts.size()<3)
{
if(fwbdebug)
cout << "Wrong error message clicked" << endl;
return;
}
emit activateRule(project, parts[0], parts[1], parts[2].toInt());
}
void instDialog::closeEvent(QCloseEvent *)
{
if (fwbdebug) qDebug() << "instDialog::closeEvent";
if (proc.state() == QProcess::Running)
{
if (fwbdebug)
qDebug() << "instDialog::closeEvent killing process";
proc.kill();
}
if (installer != NULL)
{
if (fwbdebug)
qDebug() << "instDialog::closeEvent killing installer";
installer->terminate();
delete installer;
installer = NULL;
}
}