kdelibs/kdecore/kernel/kauthorized.cpp
2015-10-17 11:45:14 +03:00

383 lines
12 KiB
C++

/* This file is part of the KDE libraries
Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
Copyright (C) 1998, 1999, 2000 Waldo Bastian <bastian@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kauthorized.h"
#include <QtCore/QDir>
#include <QtCore/QRegExp>
#include <QList>
#include <QCoreApplication>
#include <kglobal.h>
#include <ksharedconfig.h>
#include <kprotocolinfo.h>
#include <kstandarddirs.h>
#include <stdlib.h> // srand(), rand()
#include <unistd.h>
#include <netdb.h>
#include <kurl.h>
#include <kconfiggroup.h>
#include <QMutex>
#include <QtCore/qmutex.h>
#include <QtCore/qglobal.h>
extern bool kde_kiosk_exception;
class URLActionRule
{
public:
#define checkExactMatch(s, b) \
if (s.isEmpty()) b = true; \
else if (s[s.length()-1] == QLatin1Char('!')) \
{ b = false; s.truncate(s.length()-1); } \
else b = true;
#define checkStartWildCard(s, b) \
if (s.isEmpty()) b = true; \
else if (s[0] == QLatin1Char('*')) \
{ b = true; s = s.mid(1); } \
else b = false;
#define checkEqual(s, b) \
b = (s == QString::fromLatin1("="));
URLActionRule(const QByteArray &act,
const QString &bProt, const QString &bHost, const QString &bPath,
const QString &dProt, const QString &dHost, const QString &dPath,
bool perm)
: action(act),
baseProt(bProt), baseHost(bHost), basePath(bPath),
destProt(dProt), destHost(dHost), destPath(dPath),
permission(perm)
{
checkExactMatch(baseProt, baseProtWildCard);
checkStartWildCard(baseHost, baseHostWildCard);
checkExactMatch(basePath, basePathWildCard);
checkExactMatch(destProt, destProtWildCard);
checkStartWildCard(destHost, destHostWildCard);
checkExactMatch(destPath, destPathWildCard);
checkEqual(destProt, destProtEqual);
checkEqual(destHost, destHostEqual);
}
bool baseMatch(const KUrl &url, const QString &protClass) const
{
if (baseProtWildCard)
{
if ( !baseProt.isEmpty() && !url.protocol().startsWith(baseProt) &&
(protClass.isEmpty() || (protClass != baseProt)) )
return false;
}
else
{
if ( (url.protocol() != baseProt) &&
(protClass.isEmpty() || (protClass != baseProt)) )
return false;
}
if (baseHostWildCard)
{
if (!baseHost.isEmpty() && !url.host().endsWith(baseHost))
return false;
}
else
{
if (url.host() != baseHost)
return false;
}
if (basePathWildCard)
{
if (!basePath.isEmpty() && !url.path().startsWith(basePath))
return false;
}
else
{
if (url.path() != basePath)
return false;
}
return true;
}
bool destMatch(const KUrl &url, const QString &protClass, const KUrl &base, const QString &baseClass) const
{
if (destProtEqual)
{
if ( (url.protocol() != base.protocol()) &&
(protClass.isEmpty() || baseClass.isEmpty() || protClass != baseClass) )
return false;
}
else if (destProtWildCard)
{
if ( !destProt.isEmpty() && !url.protocol().startsWith(destProt) &&
(protClass.isEmpty() || (protClass != destProt)) )
return false;
}
else
{
if ( (url.protocol() != destProt) &&
(protClass.isEmpty() || (protClass != destProt)) )
return false;
}
if (destHostWildCard)
{
if (!destHost.isEmpty() && !url.host().endsWith(destHost))
return false;
}
else if (destHostEqual)
{
if (url.host() != base.host())
return false;
}
else
{
if (url.host() != destHost)
return false;
}
if (destPathWildCard)
{
if (!destPath.isEmpty() && !url.path().startsWith(destPath))
return false;
}
else
{
if (url.path() != destPath)
return false;
}
return true;
}
QByteArray action;
QString baseProt;
QString baseHost;
QString basePath;
QString destProt;
QString destHost;
QString destPath;
bool baseProtWildCard : 1;
bool baseHostWildCard : 1;
bool basePathWildCard : 1;
bool destProtWildCard : 1;
bool destHostWildCard : 1;
bool destPathWildCard : 1;
bool destProtEqual : 1;
bool destHostEqual : 1;
bool permission;
};
class KAuthorizedPrivate {
public:
KAuthorizedPrivate()
: actionRestrictions( false ), blockEverything(false),mutex(QMutex::Recursive)
{
Q_ASSERT_X(QCoreApplication::instance(),"KAuthorizedPrivate()","There has to be an existing QCoreApplication::instance() pointer");
KSharedConfig::Ptr config = KGlobal::config();
Q_ASSERT_X(config,"KAuthorizedPrivate()","There has to be an existing KGlobal::config() pointer");
if (!config) {
blockEverything=true;
return;
}
actionRestrictions = config->hasGroup("KDE Action Restrictions" ) && !kde_kiosk_exception;
}
~KAuthorizedPrivate()
{
}
bool actionRestrictions : 1;
bool blockEverything : 1;
QList<URLActionRule> urlActionRestrictions;
QMutex mutex;
};
Q_GLOBAL_STATIC(KAuthorizedPrivate,authPrivate)
#define MY_D KAuthorizedPrivate *d=authPrivate();
bool KAuthorized::authorize(const QString &genericAction)
{
MY_D
if (d->blockEverything) return false;
if (!d->actionRestrictions)
return true;
KConfigGroup cg(KGlobal::config(), "KDE Action Restrictions");
return cg.readEntry(genericAction, true);
}
bool KAuthorized::authorizeKAction(const QString& action)
{
MY_D
if (d->blockEverything) return false;
if (!d->actionRestrictions || action.isEmpty())
return true;
return authorize(QLatin1String("action/") + action);
}
bool KAuthorized::authorizeControlModule(const QString &menuId)
{
if (menuId.isEmpty() || kde_kiosk_exception)
return true;
KConfigGroup cg(KGlobal::config(), "KDE Control Module Restrictions");
return cg.readEntry(menuId, true);
}
QStringList KAuthorized::authorizeControlModules(const QStringList &menuIds)
{
KConfigGroup cg(KGlobal::config(), "KDE Control Module Restrictions");
QStringList result;
foreach(const QString it, menuIds)
{
if (cg.readEntry(it, true))
result.append(it);
}
return result;
}
static void initUrlActionRestrictions()
{
MY_D
const QString Any;
d->urlActionRestrictions.clear();
d->urlActionRestrictions.append(
URLActionRule("open", Any, Any, Any, Any, Any, Any, true));
d->urlActionRestrictions.append(
URLActionRule("list", Any, Any, Any, Any, Any, Any, true));
// TEST:
// d->urlActionRestrictions.append(
// URLActionRule("list", Any, Any, Any, Any, Any, Any, false));
// d->urlActionRestrictions.append(
// URLActionRule("list", Any, Any, Any, "file", Any, QDir::homePath(), true));
d->urlActionRestrictions.append(
URLActionRule("link", Any, Any, Any, QLatin1String(":internet"), Any, Any, true));
d->urlActionRestrictions.append(
URLActionRule("redirect", Any, Any, Any, QLatin1String(":internet"), Any, Any, true));
// We allow redirections to file: but not from internet protocols, redirecting to file:
// is very popular among io-slaves and we don't want to break them
d->urlActionRestrictions.append(
URLActionRule("redirect", Any, Any, Any, QLatin1String("file"), Any, Any, true));
d->urlActionRestrictions.append(
URLActionRule("redirect", QLatin1String(":internet"), Any, Any, QLatin1String("file"), Any, Any, false));
// local protocols may redirect everywhere
d->urlActionRestrictions.append(
URLActionRule("redirect", QLatin1String(":local"), Any, Any, Any, Any, Any, true));
// Anyone may redirect to about:
d->urlActionRestrictions.append(
URLActionRule("redirect", Any, Any, Any, QLatin1String("about"), Any, Any, true));
// Anyone may redirect to mailto:
d->urlActionRestrictions.append(
URLActionRule("redirect", Any, Any, Any, QLatin1String("mailto"), Any, Any, true));
// Anyone may redirect to itself, cq. within it's own group
d->urlActionRestrictions.append(
URLActionRule("redirect", Any, Any, Any, QLatin1String("="), Any, Any, true));
d->urlActionRestrictions.append(
URLActionRule("redirect", QLatin1String("about"), Any, Any, Any, Any, Any, true));
KConfigGroup cg(KGlobal::config(), "KDE URL Restrictions");
int count = cg.readEntry("rule_count", 0);
QString keyFormat = QString::fromLatin1("rule_%1");
for(int i = 1; i <= count; i++)
{
QString key = keyFormat.arg(i);
const QStringList rule = cg.readEntry(key, QStringList());
if (rule.count() != 8)
continue;
const QByteArray action = rule[0].toLatin1();
QString refProt = rule[1];
QString refHost = rule[2];
QString refPath = rule[3];
QString urlProt = rule[4];
QString urlHost = rule[5];
QString urlPath = rule[6];
bool bEnabled = (rule[7].toLower() == QLatin1String("true"));
if (refPath.startsWith(QLatin1String("$HOME")))
refPath.replace(0, 5, QDir::homePath());
else if (refPath.startsWith(QLatin1Char('~')))
refPath.replace(0, 1, QDir::homePath());
if (urlPath.startsWith(QLatin1String("$HOME")))
urlPath.replace(0, 5, QDir::homePath());
else if (urlPath.startsWith(QLatin1Char('~')))
urlPath.replace(0, 1, QDir::homePath());
if (refPath.startsWith(QLatin1String("$TMP")))
refPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
if (urlPath.startsWith(QLatin1String("$TMP")))
urlPath.replace(0, 4, KGlobal::dirs()->saveLocation("tmp"));
d->urlActionRestrictions.append(
URLActionRule( action, refProt, refHost, refPath, urlProt, urlHost, urlPath, bEnabled));
}
}
void KAuthorized::allowUrlAction(const QString &action, const KUrl &_baseURL, const KUrl &_destURL)
{
MY_D
QMutexLocker locker((&d->mutex));
if (authorizeUrlAction(action, _baseURL, _destURL))
return;
d->urlActionRestrictions.append( URLActionRule
( action.toLatin1(), _baseURL.protocol(), _baseURL.host(), _baseURL.path(KUrl::RemoveTrailingSlash),
_destURL.protocol(), _destURL.host(), _destURL.path(KUrl::RemoveTrailingSlash), true));
}
bool KAuthorized::authorizeUrlAction(const QString &action, const KUrl &_baseURL, const KUrl &_destURL)
{
MY_D
QMutexLocker locker(&(d->mutex));
if (d->blockEverything) return false;
if (_destURL.isEmpty())
return true;
bool result = false;
if (d->urlActionRestrictions.isEmpty())
initUrlActionRestrictions();
KUrl baseURL(_baseURL);
baseURL.setPath(QDir::cleanPath(baseURL.path()));
QString baseClass = KProtocolInfo::protocolClass(baseURL.protocol());
KUrl destURL(_destURL);
destURL.setPath(QDir::cleanPath(destURL.path()));
QString destClass = KProtocolInfo::protocolClass(destURL.protocol());
foreach(const URLActionRule &rule, d->urlActionRestrictions) {
if ((result != rule.permission) && // No need to check if it doesn't make a difference
(action == QLatin1String(rule.action)) &&
rule.baseMatch(baseURL, baseClass) &&
rule.destMatch(destURL, destClass, baseURL, baseClass))
{
result = rule.permission;
}
}
return result;
}