mirror of
https://github.com/fwbuilder/fwbuilder
synced 2026-06-24 01:49:36 +02:00
630 lines
17 KiB
C++
630 lines
17 KiB
C++
/*
|
|
|
|
Firewall Builder
|
|
|
|
Copyright (C) 2003 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 "global.h"
|
|
#include "utils.h"
|
|
#include "utils_no_qt.h"
|
|
|
|
#include <qobject.h>
|
|
#include <qmenu.h>
|
|
#include <qcombobox.h>
|
|
#include <qlistwidget.h>
|
|
#include <qmessagebox.h>
|
|
#include <qpalette.h>
|
|
#include <qnamespace.h>
|
|
#include <QHostInfo>
|
|
#include <qhostaddress.h>
|
|
#include <qpixmapcache.h>
|
|
|
|
#include <QList>
|
|
#include <QStringList>
|
|
#include <QRegExp>
|
|
#include <QPixmap>
|
|
#include <QApplication>
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
#include <QtDebug>
|
|
|
|
#include "FWBSettings.h"
|
|
|
|
#include "fwbuilder/dns.h"
|
|
#include "fwbuilder/FWObject.h"
|
|
#include "fwbuilder/FWReference.h"
|
|
#include "fwbuilder/FWObjectDatabase.h"
|
|
#include "fwbuilder/Firewall.h"
|
|
#include "fwbuilder/Library.h"
|
|
#include "fwbuilder/Resources.h"
|
|
|
|
#if defined(_WIN32)
|
|
# include <stdio.h>
|
|
# include <sys/timeb.h>
|
|
# include <sys/stat.h>
|
|
# include <fcntl.h>
|
|
# include <time.h>
|
|
# include <windows.h>
|
|
#else
|
|
# include <unistd.h>
|
|
# include <string.h>
|
|
# include <errno.h>
|
|
# include <pwd.h>
|
|
#endif
|
|
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
|
|
#include "FWBTree.h"
|
|
|
|
using namespace std;
|
|
using namespace libfwbuilder;
|
|
|
|
|
|
QAction* addPopupMenuItem(QObject *res,
|
|
QMenu* menu,
|
|
const QString &resourceIconPath,
|
|
const QString itemName,
|
|
const char* member,
|
|
const QKeySequence &accel)
|
|
{
|
|
string icn;
|
|
QPixmap pm;
|
|
//int itmID = -1;
|
|
QAction *act = nullptr;
|
|
|
|
icn = Resources::global_res->getResourceStr(static_cast<const char*>(resourceIconPath.toLatin1()));
|
|
if(icn!="")
|
|
{
|
|
// pm = QPixmap::fromMimeSource( icn.c_str() );
|
|
if ( ! QPixmapCache::find( icn.c_str(), &pm) )
|
|
{
|
|
pm.load( (":/"+icn).c_str() );//fromMimeSource( icn.c_str() );
|
|
QPixmapCache::insert( icn.c_str(), pm);
|
|
}
|
|
act = menu->addAction( pm, itemName , res , member, accel ); //insertItem
|
|
} else
|
|
act = menu->addAction( itemName , res , member, accel); //insertItem
|
|
return act;
|
|
}
|
|
|
|
void fillLibraries(QComboBox *libs, libfwbuilder::FWObject *obj, bool rw)
|
|
{
|
|
bool standardObj = false;
|
|
bool templateObj = false;
|
|
bool deletedObj = false;
|
|
QString lib="";
|
|
|
|
if ( ! FWObjectDatabase::isA(obj))
|
|
{
|
|
FWObject *libobj = obj->getLibrary();
|
|
assert(libobj!=nullptr);
|
|
lib = libobj->getName().c_str();
|
|
standardObj = (libobj->getId()==FWObjectDatabase::STANDARD_LIB_ID);
|
|
templateObj = (libobj->getId()==FWObjectDatabase::TEMPLATE_LIB_ID);
|
|
deletedObj = (libobj->getId()==FWObjectDatabase::DELETED_OBJECTS_ID);
|
|
}
|
|
|
|
libs->clear();
|
|
list<FWObject*> ll = obj->getRoot()->getByType( Library::TYPENAME );
|
|
ll.sort(FWObjectNameCmpPredicate());
|
|
int n=0;
|
|
int cn=0;
|
|
string libicn;
|
|
for (FWObject::iterator i=ll.begin(); i!=ll.end(); i++)
|
|
{
|
|
if (libicn.empty())
|
|
libicn=(":/Icons/"+(*i)->getTypeName()+"/icon-tree").c_str();
|
|
|
|
if ( (*i)->getId()==FWObjectDatabase::STANDARD_LIB_ID &&
|
|
!standardObj) continue;
|
|
if ( (*i)->getId()==FWObjectDatabase::TEMPLATE_LIB_ID &&
|
|
!templateObj) continue;
|
|
if ( (*i)->getId()==FWObjectDatabase::DELETED_OBJECTS_ID &&
|
|
!deletedObj ) continue;
|
|
|
|
if (rw && (*i)->isReadOnly()) continue;
|
|
if (lib==QString((*i)->getName().c_str())) cn=n;
|
|
QPixmap icon;
|
|
icon.load( (libicn).c_str() );
|
|
|
|
libs->addItem(icon,
|
|
QString::fromUtf8((*i)->getName().c_str()) );
|
|
n++;
|
|
}
|
|
libs->setCurrentIndex(cn);
|
|
}
|
|
|
|
|
|
void fillLibraries(QListWidget *libs, libfwbuilder::FWObject *obj, bool rw)
|
|
{
|
|
bool standardObj = false;
|
|
bool templateObj = false;
|
|
bool deletedObj = false;
|
|
QString lib="";
|
|
|
|
if ( ! FWObjectDatabase::isA(obj))
|
|
{
|
|
FWObject *libobj = obj->getLibrary();
|
|
assert(libobj!=nullptr);
|
|
lib = libobj->getName().c_str();
|
|
standardObj = (libobj->getId()==FWObjectDatabase::STANDARD_LIB_ID);
|
|
templateObj = (libobj->getId()==FWObjectDatabase::TEMPLATE_LIB_ID);
|
|
deletedObj = (libobj->getId()==FWObjectDatabase::DELETED_OBJECTS_ID);
|
|
}
|
|
|
|
libs->clear();
|
|
list<FWObject*> ll = obj->getRoot()->getByType( Library::TYPENAME );
|
|
ll.sort(FWObjectNameCmpPredicate());
|
|
int n=0;
|
|
int cn=0;
|
|
string libicn;
|
|
for (FWObject::iterator i=ll.begin(); i!=ll.end(); i++)
|
|
{
|
|
if (libicn.empty())
|
|
libicn=Resources::global_res->getObjResourceStr(*i,"icon-tree").c_str();
|
|
|
|
if ( (*i)->getId()==FWObjectDatabase::STANDARD_LIB_ID && !standardObj) continue;
|
|
if ( (*i)->getId()==FWObjectDatabase::TEMPLATE_LIB_ID && !templateObj) continue;
|
|
if ( (*i)->getId()==FWObjectDatabase::DELETED_OBJECTS_ID && !deletedObj ) continue;
|
|
|
|
if (rw && (*i)->isReadOnly()) continue;
|
|
if (lib==QString((*i)->getName().c_str())) cn=n;
|
|
|
|
QPixmap icon;
|
|
icon.load( (":/"+libicn).c_str() );
|
|
|
|
QListWidgetItem *item = new QListWidgetItem(icon, (*i)->getName().c_str());
|
|
|
|
libs->addItem(item);
|
|
|
|
n++;
|
|
}
|
|
libs->setCurrentRow(cn);
|
|
}
|
|
|
|
|
|
bool isTreeReadWrite(QWidget *parent, FWObject *obj)
|
|
{
|
|
if (obj->isReadOnly())
|
|
{
|
|
QMessageBox::warning(
|
|
parent, "Firewall Builder",
|
|
QObject::tr("Impossible to apply changes because object is "
|
|
"located in read-only\npart of the tree or data "
|
|
"file was opened read-only"),
|
|
QObject::tr("&Continue"), 0, 0,
|
|
0, 2 );
|
|
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* compare names as QString objects to catch non-ascii names
|
|
*/
|
|
bool validateName(QWidget *parent, FWObject *obj, const QString &newname)
|
|
{
|
|
if (newname.isEmpty())
|
|
{
|
|
// show warning dialog only if app has focus
|
|
if (QApplication::focusWidget() != nullptr)
|
|
{
|
|
parent->blockSignals(true);
|
|
|
|
QMessageBox::warning(
|
|
parent, "Firewall Builder",
|
|
QObject::tr("Object name should not be blank"),
|
|
QObject::tr("&Continue"), nullptr, nullptr, 0, 2 );
|
|
|
|
parent->blockSignals(false);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FWObject *p = obj->getParent();
|
|
for (FWObject::iterator i=p->begin(); i!=p->end(); ++i)
|
|
{
|
|
FWObject *o1= *i;
|
|
// Another hack: we need to be able to create policy and nat
|
|
// ruleset objects with name "ftp-proxy/*" for PF. Allow
|
|
// objects of different type to have the same name.
|
|
|
|
if (o1 == obj || o1->getTypeName() != obj->getTypeName()) continue;
|
|
|
|
if (QString(o1->getName().c_str()) == newname)
|
|
{
|
|
/*
|
|
* when we open this warning dialog, the dialog class
|
|
* loses focus and obj_name lineEdit widget sends signal
|
|
* "editingfinished" again. To the user this looks like the
|
|
* warning dialog popped up twice (in fact two copies of the
|
|
* same warning dialog appear at the same time, one exactly on
|
|
* top of another). To avoid this, block signals for the
|
|
* duration while we show the dialog. Note that documentation
|
|
* does not mention that QObject::blockSignals() affects not
|
|
* only the widget but all its children, but it seems to work
|
|
* that way. Tested with Qt 4.6.1. See #1171
|
|
*/
|
|
|
|
// show warning dialog only if app has focus
|
|
if (QApplication::focusWidget() != nullptr)
|
|
{
|
|
parent->blockSignals(true);
|
|
|
|
QMessageBox::warning(
|
|
parent, "Firewall Builder",
|
|
QObject::tr("Object with name '%1' already exists, "
|
|
"please choose different name.").
|
|
arg(o1->getName().c_str()),
|
|
QObject::tr("&Continue"), nullptr, nullptr, 0, 2 );
|
|
|
|
parent->blockSignals(false);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QString quoteString(const QString &str)
|
|
{
|
|
QString res;
|
|
|
|
if (str.indexOf(" ")!=-1) res="\"";
|
|
res+=str;
|
|
if (str.indexOf(" ")!=-1) res+="\"";
|
|
|
|
return res;
|
|
}
|
|
|
|
QString getFileDir(const QString &file)
|
|
{
|
|
return QFileInfo(file).dir().path();
|
|
}
|
|
|
|
void setDisabledPalette(QWidget *w)
|
|
{
|
|
QPalette pal=w->palette();
|
|
|
|
pal.setCurrentColorGroup( QPalette::Active );
|
|
pal.setColor( QPalette::Text, Qt::black );
|
|
|
|
pal.setCurrentColorGroup( QPalette::Inactive );
|
|
pal.setColor( QPalette::Text, Qt::black );
|
|
|
|
pal.setCurrentColorGroup( QPalette::Disabled );
|
|
pal.setColor( QPalette::Text, Qt::black );
|
|
|
|
w->setPalette( pal );
|
|
}
|
|
|
|
QString getAddrByName(const QString &name, int af_type)
|
|
{
|
|
list<InetAddr> results;
|
|
try
|
|
{
|
|
results = DNS::getHostByName(name.toLatin1().constData(), af_type);
|
|
} catch (FWException &e)
|
|
{
|
|
if (fwbdebug) qDebug("utils::getAddrByName: DNS lookup error: %s",
|
|
e.toString().c_str());
|
|
return "";
|
|
}
|
|
|
|
try
|
|
{
|
|
if (results.size()>0)
|
|
return QString(results.front().toString().c_str());
|
|
} catch (FWException &e)
|
|
{
|
|
qDebug() << "utils::getAddrByName: Can not convert address to string";
|
|
qDebug() << e.toString().c_str();
|
|
}
|
|
return "";
|
|
|
|
#if 0
|
|
QHostInfo a = QHostInfo::fromName(name);
|
|
|
|
QList<QHostAddress> alist = a.addresses();
|
|
|
|
if (alist.empty()) return "";
|
|
return alist.front().toString();
|
|
#endif
|
|
}
|
|
|
|
QString getNameByAddr(const QString &addr)
|
|
{
|
|
/*QHostAddress ha;
|
|
ha.setAddress(addr);
|
|
|
|
Q3Dns qry( ha, Q3Dns::Ptr);
|
|
|
|
QStringList nlist = qry.hostNames();
|
|
|
|
while (qry.isWorking())
|
|
{
|
|
app->processEvents(200);
|
|
}
|
|
nlist = qry.hostNames();
|
|
if (nlist.empty()) return "";
|
|
|
|
return nlist.front();*/
|
|
QHostInfo a = QHostInfo::fromName(addr);
|
|
|
|
return a.hostName();
|
|
}
|
|
|
|
QString wordWrap(const QString& s, int maxchinline)
|
|
{
|
|
int chcount=0;
|
|
int lastwdpos=0;
|
|
int linestart=0;
|
|
bool fl_wd=true;
|
|
/*unsigned*/ int pos=0;
|
|
QString res="";
|
|
QChar ch;
|
|
|
|
for ( ; pos < s.length(); pos++,chcount++)
|
|
{
|
|
ch = s.at(pos);
|
|
if (!ch.isLetter() && !ch.isNumber())
|
|
{
|
|
fl_wd=false;
|
|
} else
|
|
{
|
|
if (!fl_wd)
|
|
{
|
|
fl_wd=true;
|
|
lastwdpos=pos;
|
|
}
|
|
}
|
|
if (chcount>maxchinline)
|
|
{
|
|
if (fl_wd)
|
|
{
|
|
if (linestart<lastwdpos)
|
|
{
|
|
res.append(s.mid(linestart,lastwdpos-linestart));
|
|
linestart=lastwdpos;
|
|
pos=lastwdpos;
|
|
|
|
}else
|
|
{
|
|
res.append(s.mid(linestart,pos-linestart));
|
|
linestart=pos;
|
|
lastwdpos=pos;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
res.append(s.mid(linestart,pos-linestart));
|
|
while (++pos< s.length() && s.at(pos).isSpace()) ;
|
|
if (pos<s.length())
|
|
{
|
|
linestart=pos--;
|
|
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
res.append('\n');
|
|
chcount=0;
|
|
}
|
|
}
|
|
res.append(s.mid(linestart,pos-linestart));
|
|
return res;
|
|
}
|
|
|
|
void loadIcon(QPixmap &pm, FWObject *obj)
|
|
{
|
|
QString icn_file = (":/Icons/" + obj->getTypeName()+"/icon-tree").c_str();
|
|
LoadPixmap(icn_file, pm);
|
|
|
|
// if ( ! QPixmapCache::find( icn_file, pm) )
|
|
// {
|
|
// pm.load( icn_file );
|
|
// QPixmapCache::insert( icn_file, pm);
|
|
// }
|
|
}
|
|
|
|
void LoadPixmap(const QString &path, QPixmap &pm)
|
|
{
|
|
if ( ! QPixmapCache::find( path, &pm ) )
|
|
{
|
|
pm.load( path );
|
|
if (pm.width() == 0)
|
|
qDebug("pixmap load failed: %s", path.toLatin1().constData());
|
|
QPixmapCache::insert( path, pm );
|
|
}
|
|
}
|
|
|
|
QPixmap LoadPixmap(const QString &path)
|
|
{
|
|
|
|
QPixmap p;
|
|
LoadPixmap(path, p);
|
|
return p;
|
|
}
|
|
|
|
QString calculateIconName(const QString &_icn, bool negation)
|
|
{
|
|
// if _icn has white space, use only the first word
|
|
QStringList icnl = _icn.split(" ");
|
|
|
|
QString icn = ":/Icons/" + icnl[0] + "/icon";
|
|
|
|
if (negation)
|
|
{
|
|
icn = icn + "-neg";
|
|
}
|
|
|
|
if (FWBSettings::SIZE16X16 == st->getIconsInRulesSize())
|
|
{
|
|
return icn+"-tree";
|
|
}
|
|
|
|
return icn;
|
|
}
|
|
|
|
void doSetObjectIcon(FWObject *obj, QPixmap *pm, int icon_size)
|
|
{
|
|
QString icn_alias;
|
|
QString icn_sfx;
|
|
|
|
switch (icon_size)
|
|
{
|
|
case 0: icn_sfx = "icon-tree"; break;
|
|
case 2: icn_sfx = "icon-big"; break;
|
|
default: icn_sfx = "icon"; break;
|
|
}
|
|
|
|
// note that we do not have "locked" version of large icons
|
|
if (obj->getRO() && icon_size != 2)
|
|
icn_alias = ":/Icons/lock";
|
|
else
|
|
{
|
|
if (FWBTree().isStandardFolder(obj))
|
|
icn_alias = ":/Icons/SystemGroup/" + icn_sfx;
|
|
else
|
|
icn_alias = QString(":/Icons/") + obj->getTypeName().c_str() + "/" + icn_sfx;
|
|
}
|
|
|
|
LoadPixmap(icn_alias, *pm);
|
|
}
|
|
|
|
QString _getNextToken(QStringList &args)
|
|
{
|
|
QString a;
|
|
while (args.size() > 0)
|
|
{
|
|
a = args.front();
|
|
args.pop_front();
|
|
if (!a.isEmpty()) break;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
// reassemble quoted strings from the list of tokens, possibly
|
|
// recursively if there are quoted strings inside. The first token is
|
|
// assumed to be " or '. Pops all processed tokens from the list but
|
|
// leaves the rest in it.
|
|
QString _parseTokens(QStringList &args, const QChar closing_quote='\0')
|
|
{
|
|
QString a = _getNextToken(args);
|
|
if (args.size() == 0) return a;
|
|
|
|
if (closing_quote != QChar('\0') && a.endsWith(closing_quote))
|
|
return a;
|
|
|
|
if (a.startsWith("\"") || a.startsWith("'"))
|
|
{
|
|
QStringList res;
|
|
QChar closing_quote = a[0];
|
|
|
|
res.append(a);
|
|
|
|
while (!a.endsWith(closing_quote) && args.size() > 0)
|
|
{
|
|
a = _parseTokens(args, closing_quote);
|
|
res.append(a);
|
|
}
|
|
|
|
return res.join(" ");
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* parse command line for ssh or scp given by user in the global
|
|
* preferences dialog. The challenge is to be able to handle situation
|
|
* when the program is installed in directory with a whitespace in the
|
|
* name, so we can't just split the string by a " ".
|
|
*
|
|
* Recognize the following constructs:
|
|
*
|
|
* /path/to/program/program -arg1 val1 -arg2 val2 -arg3 "value 3"
|
|
*
|
|
* everything before the first "-" is considered executable name
|
|
* (possibly with full path)
|
|
*
|
|
* word that starts with "-" or "/" preceded by a space is an argument
|
|
* argument may have an optional parameter
|
|
* parameter may be quoted using double or single quotes
|
|
*/
|
|
void parseCommandLine(const QString &cmd, QStringList &argv)
|
|
{
|
|
int first_arg = cmd.indexOf(QRegExp(" *-"));
|
|
if (first_arg == -1)
|
|
{
|
|
// no arguments
|
|
argv.append(cmd.trimmed());
|
|
return;
|
|
}
|
|
QString program = cmd.mid(0, first_arg).trimmed();
|
|
if (!program.isEmpty()) argv.append(program);
|
|
|
|
QStringList args = cmd.mid(first_arg).split(QRegExp("\\s+"));
|
|
// QString::SkipEmptyParts);
|
|
// splits like this:
|
|
// ["", "-arg1", "val1", "-arg2", "\"value", "2", "\""]
|
|
|
|
while (args.size() > 0)
|
|
{
|
|
QString t = _parseTokens(args);
|
|
|
|
// remove quotes from quoted strings
|
|
if ((t.startsWith('\"') && t.endsWith('\"')) ||
|
|
(t.startsWith('\'') || t.endsWith('\'')))
|
|
{
|
|
t = t.mid(1, t.length()-2);
|
|
}
|
|
argv.append(t);
|
|
}
|
|
}
|
|
|
|
|
|
static bool stringsCompare(const QString &a, const QString &b)
|
|
{
|
|
QString aLower = a.toLower();
|
|
QString bLower = b.toLower();
|
|
int result = aLower.localeAwareCompare(bLower);
|
|
if (result == 0) {
|
|
return a.localeAwareCompare(b) < 0;
|
|
} else {
|
|
return result < 0;
|
|
}
|
|
}
|
|
|
|
|
|
QStringList sortStrings(const QStringList &list)
|
|
{
|
|
QStringList ret = list;
|
|
std::sort(ret.begin(), ret.end(), stringsCompare);
|
|
return ret;
|
|
}
|