diff options
Diffstat (limited to 'src/core/kauthorized.cpp')
| -rw-r--r-- | src/core/kauthorized.cpp | 393 | 
1 files changed, 393 insertions, 0 deletions
| diff --git a/src/core/kauthorized.cpp b/src/core/kauthorized.cpp new file mode 100644 index 00000000..abf479ca --- /dev/null +++ b/src/core/kauthorized.cpp @@ -0,0 +1,393 @@ +/* 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 <QUrl> + +#include <QCoreApplication> +#include <ksharedconfig.h> +#include <stdlib.h> // srand(), rand() +#ifndef Q_OS_WIN +#include <unistd.h> +#include <netdb.h> +#endif + +#include <kconfiggroup.h> + +#include <QMutex> +#include <QMutexLocker> + +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 QUrl &url, const QString &protClass) const +     { +        if (baseProtWildCard) +        { +           if ( !baseProt.isEmpty() && !url.scheme().startsWith(baseProt) && +                (protClass.isEmpty() || (protClass != baseProt)) ) +              return false; +        } +        else +        { +           if ( (url.scheme() != 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 QUrl &url, const QString &protClass, const QUrl &base, const QString &baseClass) const +     { +        if (destProtEqual) +        { +           if ( (url.scheme() != base.scheme()) && +                (protClass.isEmpty() || baseClass.isEmpty() || protClass != baseClass) ) +              return false; +        } +        else if (destProtWildCard) +        { +           if ( !destProt.isEmpty() && !url.scheme().startsWith(destProt) && +                (protClass.isEmpty() || (protClass != destProt)) ) +              return false; +        } +        else +        { +           if ( (url.scheme() != 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 = KSharedConfig::openConfig(); + +    Q_ASSERT_X(config,"KAuthorizedPrivate()","There has to be an existing KSharedConfig::openConfig() 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(KSharedConfig::openConfig(), "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(KSharedConfig::openConfig(), "KDE Control Module Restrictions"); +   return cg.readEntry(menuId, true); +} + +QStringList KAuthorized::authorizeControlModules(const QStringList &menuIds) +{ +   KConfigGroup cg(KSharedConfig::openConfig(), "KDE Control Module Restrictions"); +   QStringList result; +   for(QStringList::ConstIterator it = menuIds.begin(); +       it != menuIds.end(); ++it) +   { +      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(KSharedConfig::openConfig(), "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, QDir::tempPath()); +    if (urlPath.startsWith(QLatin1String("$TMP"))) +       urlPath.replace(0, 4, QDir::tempPath()); + +    d->urlActionRestrictions.append( +	URLActionRule( action, refProt, refHost, refPath, urlProt, urlHost, urlPath, bEnabled)); +  } +} + +namespace KAuthorized +{ +// Called by KAuthorized::allowUrlAction in KIO +KCONFIGCORE_EXPORT void allowUrlActionInternal(const QString &action, const QUrl &_baseURL, const QUrl &_destURL) +{ +  MY_D +  QMutexLocker locker((&d->mutex)); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 3, 0) +  const QString basePath = _baseURL.adjusted(QUrl::StripTrailingSlash).path(); +  const QString destPath = _destURL.adjusted(QUrl::StripTrailingSlash).path(); +#else +  const QString basePath = QUrl(_baseURL.toString(QUrl::StripTrailingSlash)).path(); +  const QString destPath = QUrl(_destURL.toString(QUrl::StripTrailingSlash)).path(); +#endif + +  d->urlActionRestrictions.append( URLActionRule +      ( action.toLatin1(), _baseURL.scheme(), _baseURL.host(), basePath, +        _destURL.scheme(), _destURL.host(), destPath, true)); +} + +// Called by KAuthorized::authorizeUrlAction in KIO +KCONFIGCORE_EXPORT bool authorizeUrlActionInternal(const QString& action, const QUrl &_baseURL, const QUrl &_destURL, const QString& baseClass, const QString& destClass) +{ +  MY_D +  QMutexLocker locker(&(d->mutex)); +  if (d->blockEverything) return false; + +  if (_destURL.isEmpty()) +     return true; + +  bool result = false; +  if (d->urlActionRestrictions.isEmpty()) +     initUrlActionRestrictions(); + +  QUrl baseURL(_baseURL); +  baseURL.setPath(QDir::cleanPath(baseURL.path())); + +  QUrl destURL(_destURL); +  destURL.setPath(QDir::cleanPath(destURL.path())); + +  Q_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.constData())) && +         rule.baseMatch(baseURL, baseClass) && +         rule.destMatch(destURL, destClass, baseURL, baseClass)) +     { +        result = rule.permission; +     } +  } +  return result; +} + +} // namespace | 
