From ee159229bcfb6f2dbd19ef16e37fa2c65cd3846d Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 5 Oct 2010 15:15:36 +0200 Subject: Add Permission checking and session information code. --- src/input/pvsCheckPrivileges.cpp | 314 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 src/input/pvsCheckPrivileges.cpp (limited to 'src/input/pvsCheckPrivileges.cpp') diff --git a/src/input/pvsCheckPrivileges.cpp b/src/input/pvsCheckPrivileges.cpp new file mode 100644 index 0000000..56073bc --- /dev/null +++ b/src/input/pvsCheckPrivileges.cpp @@ -0,0 +1,314 @@ +/* + # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg + # + # This program is free software distributed under the GPL version 2. + # See http://openslx.org/COPYING + # + # If you have any feedback please consult http://openslx.org/feedback and + # send your suggestions, praise, or complaints to feedback@openslx.org + # + # General information about OpenSLX can be found at http://openslx.org/ + # -------------------------------------------------------------------------- + # pvsCheckPrivileges.cpp: + # - A small program that checks whether or not it is called from + # a physical seat and conditionally executes the pvs input daemon. + # Additional security-relevant conditions should be checked here. + # + # The program is called with exactly one parameter, specifying the + # number of the file descriptor which is to be passed to its child. + # -------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pvsCheckPrivileges.h" + +using namespace std; + +#define TIMEOUT_VALUE 10000 /* Wait for max. 10 seconds */ + +// We need these classes for PolicyKit access: +struct PolKitSubject { + QString subject_kind; + QMap subject_details; +}; +Q_DECLARE_METATYPE(PolKitSubject); + +QDBusArgument& operator<<(QDBusArgument& arg, PolKitSubject const& subj) +{ + arg.beginStructure(); + arg << subj.subject_kind << subj.subject_details; + arg.endStructure(); + return arg; +} + +QDBusArgument const& operator>>(QDBusArgument const& arg, PolKitSubject& subj) +{ + arg.beginStructure(); + arg >> subj.subject_kind >> subj.subject_details; + arg.endStructure(); + return arg; +} + +struct PolKitAuthReply { + bool isAuthorized; + bool isChallenge; + QMap details; +}; +Q_DECLARE_METATYPE(PolKitAuthReply); + +QDBusArgument& operator<<(QDBusArgument& arg, PolKitAuthReply const& reply) +{ + arg.beginStructure(); + arg << reply.isAuthorized << reply.isChallenge << reply.details; + arg.endStructure(); + return arg; +} + +QDBusArgument const& operator>>(QDBusArgument const& arg, PolKitAuthReply& reply) +{ + arg.beginStructure(); + arg >> reply.isAuthorized >> reply.isChallenge >> reply.details; + arg.endStructure(); + return arg; +} + +// We need to pass QMap to QVariant: +typedef QMap QStringStringMap; +Q_DECLARE_METATYPE(QStringStringMap) + +PVSCheckPrivileges* PVSCheckPrivileges::instance() +{ + static PVSCheckPrivileges static_instance; + return &static_instance; +} + +PVSCheckPrivileges::PVSCheckPrivileges() +{ +} + +PVSCheckPrivileges::~PVSCheckPrivileges() +{ +} + +QString PVSCheckPrivileges::getSessionReference(CachedInputContext const& sender) +{ + if(!sender.isValid()) + { + return QString(); + } + + QString sessionReference = _savedConsoleKitSession.value(sender, QString()); + if(sessionReference.isNull()) + { + QDBusConnection conn = QDBusConnection::systemBus(); + // Find the name of the current session: + QDBusInterface manager("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", conn); + QDBusReply replyGetSession = manager.call(QDBus::Block, "GetSessionForUnixProcess", (quint32)sender.pid); + if(!replyGetSession.isValid()) + { + qWarning("Reply to GetSessionForUnixProcess is invalid: %s: %s", replyGetSession.error().name().toLocal8Bit().constData(), replyGetSession.error().message().toLocal8Bit().constData()); + return QString(); + } + _savedConsoleKitSession[sender] = sessionReference = replyGetSession.value().path(); + } + return sessionReference; +} + +PVSCheckPrivileges::SessionKind PVSCheckPrivileges::getSessionKind(CachedInputContext const& sender) +{ + if(!sender.isValid()) + { + return SESSION_UNKNOWN; + } + + // if the sender is root, we always suppose he works locally. + if(sender.uid == 0) + { + return SESSION_LOCAL; + } + + QString sessionReference = getSessionReference(sender); + if(sessionReference.isNull()) + { + return SESSION_LOOKUP_FAILURE; + } + + QDBusConnection conn = QDBusConnection::systemBus(); + QDBusInterface session("org.freedesktop.ConsoleKit", sessionReference, "org.freedesktop.ConsoleKit.Session", conn); + QDBusReply replyIsLocal = session.call(QDBus::Block, "IsLocal"); + + if(!replyIsLocal.isValid()) + { + qWarning("Unable to find out whether the current session is local: %s: %s", replyIsLocal.error().name().toLocal8Bit().constData(), replyIsLocal.error().message().toLocal8Bit().constData()); + return SESSION_LOOKUP_FAILURE; + } + return replyIsLocal.value() ? SESSION_LOCAL : SESSION_NONLOCAL; +} + +PVSCheckPrivileges::UserPrivilege PVSCheckPrivileges::getUserPrivilege(CachedInputContext const& sender) +{ + // Always allow root: + if(sender.uid == 0) + return USER_PRIVILEGED; + + // For PolKit, we need the start-time of the process. + // On Linux, we can get it from /proc: + QString procStat = QString("/proc/%1/stat").arg(sender.pid); + QFile procStatFile(procStat); + if(!procStatFile.exists()) + { + qWarning("Could not look up any info on process %d, its %s file does not exist", sender.pid, procStat.toLocal8Bit().constData()); + return USER_LOOKUP_FAILURE; + } + procStatFile.open(QIODevice::ReadOnly); + QByteArray procStatBytes = procStatFile.readAll(); + qDebug() << "Read stat file: " << procStatBytes; + QString procStatLine = QString::fromLocal8Bit(procStatBytes.constData(), procStatBytes.length()); + QStringList procStatFields = procStatLine.split(QRegExp("\\s+")); + qDebug() << "Found stat fields: " << procStatFields; + bool ok; + quint64 startTime = procStatFields[21].toULongLong(&ok); + if(!ok) + { + qWarning("Could not find out start time for process %d", (int)sender.pid); + return USER_LOOKUP_FAILURE; + } + + // Okay, we got the startTime. Now ask PolicyKit: + + QDBusConnection conn = QDBusConnection::systemBus(); + QDBusInterface intf("org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority", "org.freedesktop.PolicyKit1.Authority", conn); + PolKitSubject subj; + subj.subject_kind = "unix-process"; + subj.subject_details["pid"] = (quint32)sender.pid; + subj.subject_details["start-time"] = startTime; + QDBusReply reply = intf.call(QDBus::Block, + QLatin1String("CheckAuthorization"), + QVariant::fromValue(subj), + "org.openslx.pvs.privilegedinput", + QVariant::fromValue(QMap()) /* No details */, + (quint32)1 /* Allow Interaction */, + QUuid::createUuid().toString() /* Cancellation ID */); + if(!reply.isValid()) + { + QDBusError err = reply.error(); + + qWarning("Reply to CheckAuthorization is invalid: %s: %s", err.name().toLocal8Bit().constData(), err.message().toLocal8Bit().constData()); + return USER_LOOKUP_FAILURE; + } + return reply.value().isAuthorized ? USER_PRIVILEGED : USER_UNPRIVILEGED; +} + +QString PVSCheckPrivileges::getX11SessionName(CachedInputContext const& sender) +{ + QString sessionReference = getSessionReference(sender); + if(sessionReference.isNull()) + { + return QString(); + } + + QDBusConnection conn = QDBusConnection::systemBus(); + QDBusInterface intf("org.freedesktop.ConsoleKit", sessionReference, "org.freedesktop.ConsoleKit.Session", conn); + QDBusReply reply = intf.call(QDBus::Block, QLatin1String("GetX11Display")); + if(!reply.isValid()) + { + QDBusError err = reply.error(); + + qWarning("Reply to GetX11Display is invalid: %s: %s", err.name().toLocal8Bit().constData(), err.message().toLocal8Bit().constData()); + return QString(); + } + + return reply.value(); +} + +QString PVSCheckPrivileges::getX11DisplayDevice(CachedInputContext const& sender) +{ + QString sessionReference = getSessionReference(sender); + if(sessionReference.isNull()) + { + return QString(); + } + + QDBusConnection conn = QDBusConnection::systemBus(); + QDBusInterface intf("org.freedesktop.ConsoleKit", sessionReference, "org.freedesktop.ConsoleKit.Session", conn); + QDBusReply reply = intf.call(QDBus::Block, QLatin1String("GetX11DisplayDevice")); + if(!reply.isValid()) + { + QDBusError err = reply.error(); + + qWarning("Reply to GetX11DisplayDevice is invalid: %s: %s", err.name().toLocal8Bit().constData(), err.message().toLocal8Bit().constData()); + return QString(); + } + + return reply.value(); +} + +bool PVSCheckPrivileges::require(SessionKind sessionKind, CachedInputContext const& sender) +{ + SessionKind cachedSessionKind; + + if(sessionKind < SESSION_NONLOCAL) + { + if((cachedSessionKind = _savedSessionKind.value(sender, SESSION_UNKNOWN)) == SESSION_UNKNOWN) + { + cachedSessionKind = getSessionKind(sender); + if(cachedSessionKind != SESSION_LOOKUP_FAILURE) + _savedSessionKind[sender] = cachedSessionKind; + qDebug("Got session kind: %s", toString(cachedSessionKind).toLocal8Bit().constData()); + } + if(cachedSessionKind > sessionKind) + return false; + } + + return true; +} + +bool PVSCheckPrivileges::require(UserPrivilege userPrivilege, CachedInputContext const& sender) +{ + UserPrivilege cachedUserPrivilege; + + if(userPrivilege < USER_UNPRIVILEGED) + { + if((cachedUserPrivilege = _savedUserPrivilege.value(sender, USER_UNKNOWN)) == USER_UNKNOWN) + { + cachedUserPrivilege = getUserPrivilege(sender); + if(cachedUserPrivilege != USER_LOOKUP_FAILURE) + _savedUserPrivilege[sender] = cachedUserPrivilege; + qDebug("Got user privilege: %s", toString(cachedUserPrivilege).toLocal8Bit().constData()); + } + if(cachedUserPrivilege > userPrivilege) + return false; + } + return true; +} + +bool PVSCheckPrivileges::require(SessionKind sessionKind, + UserPrivilege userPrivilege, + CachedInputContext const& sender) +{ + if(!require(sessionKind, sender)) + return false; + if(!require(userPrivilege, sender)) + return false; + return true; +} + +uint qHash(CachedInputContext const& p) +{ + return qHash(qMakePair(p.pid, qMakePair(p.uid, p.gid))); +} -- cgit v1.2.3-55-g7522 From 9602e1063f5459d9ca05ba8f90304b7d34072561 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 6 Oct 2010 15:01:33 +0200 Subject: Implement administratively configured user privileges The administrator can set a list of users and a list of groups to see as privileged. This list is reloaded whenever the configuration file changes, or changes to the user/group database are detected. --- src/input/CMakeLists.txt | 1 + src/input/pvsCheckPrivileges.cpp | 161 ++++++++++++++++++++++++++++++++++++++- src/input/pvsCheckPrivileges.h | 19 ++++- 3 files changed, 178 insertions(+), 3 deletions(-) (limited to 'src/input/pvsCheckPrivileges.cpp') diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 1a3b154..29c463a 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -25,6 +25,7 @@ if(UNIX) set(pvsprivinputd_MOC_HDRS pvsPrivInputHandler.h + pvsCheckPrivileges.h ) qt4_wrap_cpp(pvsprivinputd_MOC_SRCS diff --git a/src/input/pvsCheckPrivileges.cpp b/src/input/pvsCheckPrivileges.cpp index 56073bc..71c5861 100644 --- a/src/input/pvsCheckPrivileges.cpp +++ b/src/input/pvsCheckPrivileges.cpp @@ -19,13 +19,19 @@ # -------------------------------------------------------------------------- */ +#include +#include +#include #include #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -35,6 +41,7 @@ #include #include #include +#include "pvsPrivInputSocket.h" #include "pvsCheckPrivileges.h" using namespace std; @@ -97,8 +104,19 @@ PVSCheckPrivileges* PVSCheckPrivileges::instance() return &static_instance; } -PVSCheckPrivileges::PVSCheckPrivileges() +PVSCheckPrivileges::PVSCheckPrivileges(QObject* parent) + : QObject(parent) { + // initialise our cache: + updateCachedUserDatabase(); + rereadConfiguration(); + + // and make it update itself: + QStringList paths; + paths << "/etc/passwd" << "/etc/group" << pvsPrivInputGetSettingsPath(); + _watcher = new QFileSystemWatcher(paths, this); + connect(_watcher, SIGNAL(fileChanged(QString const&)), this, SLOT(updateCachedUserDatabase())); + connect(_watcher, SIGNAL(fileChanged(QString const&)), this, SLOT(rereadConfiguration())); } PVSCheckPrivileges::~PVSCheckPrivileges() @@ -164,8 +182,26 @@ PVSCheckPrivileges::UserPrivilege PVSCheckPrivileges::getUserPrivilege(CachedInp { // Always allow root: if(sender.uid == 0) + { + return USER_PRIVILEGED; + } + + // Or if the user is one of those enumerated in the privileged-users configuration value: + if(_privilegedUsers.contains(sender.uid)) + { return USER_PRIVILEGED; + } + + // Or if the user is a member of one of the groups enumerated in the privileged-groups configuration value: + foreach(gid_t gid, _privilegedGroups) + { + if(_userGroupMap.contains(sender.uid, gid)) + { + return USER_PRIVILEGED; + } + } + // User is not trivially privileged, so try to check with PolicyKit. // For PolKit, we need the start-time of the process. // On Linux, we can get it from /proc: QString procStat = QString("/proc/%1/stat").arg(sender.pid); @@ -312,3 +348,126 @@ uint qHash(CachedInputContext const& p) { return qHash(qMakePair(p.pid, qMakePair(p.uid, p.gid))); } + +void PVSCheckPrivileges::updateCachedUserDatabase() +{ + QHash userNames; + + _userGroupMap.clear(); + + // assemble a list of known users and their primary groups: + setpwent(); // open the user database + struct passwd* userrec; + while((userrec = getpwent())) + { + userNames.insert(userrec->pw_name, userrec->pw_uid); + _userGroupMap.insert(userrec->pw_uid, userrec->pw_gid); + } + endpwent(); // close the database + + // augment with secondary groups: + setgrent(); // open the group database + struct group* grouprec; + while((grouprec = getgrent())) + { + char** membername = grouprec->gr_mem; + while(*membername) + { + uid_t uid = userNames.value(*membername, (uid_t)-1); + if(uid != (uid_t)-1) + { + _userGroupMap.insert(uid, grouprec->gr_gid); + } + membername++; + } + } + endgrent(); + + // decisions may have changed, so clear the caches: + _savedUserPrivilege.clear(); +} + +void PVSCheckPrivileges::rereadConfiguration() +{ + QSettings* settings = pvsPrivInputReopenSettings(); + + _privilegedGroups.clear(); + QVariant groupList = settings->value("privileged-groups"); + if(groupList.isValid()) + { + if(!groupList.canConvert(QVariant::StringList)) + { + qWarning("There is a privileged-groups setting, but it cannot be converted to a list of strings."); + goto endGroupListScan; + } + + QStringList groups = groupList.toStringList(); + foreach(QString groupName, groups) + { + bool ok; + gid_t gid = groupName.toUInt(&ok); + if(ok) + { + _privilegedGroups.append(gid); + } + else + { + // lookup the name: + QByteArray groupNameBytes = groupName.toLocal8Bit(); + struct group* group = getgrnam(groupNameBytes.constData()); + if(group) + { + _privilegedGroups.append(group->gr_gid); + } + else + { + qWarning("privileged-groups setting contains %s which is neither a numeric GID " + "nor a valid group name. Skipping.", + groupNameBytes.constData()); + } + } + } + } + +endGroupListScan: + _privilegedUsers.clear(); + QVariant userList = settings->value("privileged-users"); + if(userList.isValid()) + { + if(!userList.canConvert(QVariant::StringList)) + { + qWarning("There is a privileged-users setting, but it cannot be converted to a list of strings."); + goto endUserListScan; + } + + QStringList users = userList.toStringList(); + foreach(QString userName, users) + { + bool ok; + uid_t uid = userName.toUInt(&ok); + if(ok) + { + _privilegedUsers.append(uid); + } + else + { + // lookup the name: + QByteArray userNameBytes = userName.toLocal8Bit(); + struct passwd* user = getpwnam(userNameBytes.constData()); + if(user) + { + _privilegedUsers.append(user->pw_uid); + } + else + { + qWarning("privileged-users setting contains %s which is neither a numeric UID " + "nor a valid user name. Skipping.", + userNameBytes.constData()); + } + } + } + } + +endUserListScan: + return; +} diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h index e5cc9a4..fc82e4c 100644 --- a/src/input/pvsCheckPrivileges.h +++ b/src/input/pvsCheckPrivileges.h @@ -19,7 +19,10 @@ #define PVSCHECKPRIVILEGES_H_ #include +#include #include +#include +#include #include #include "inputEventHandler.h" @@ -64,8 +67,11 @@ struct CachedInputContext }; uint qHash(CachedInputContext const& p); -class PVSCheckPrivileges +class QFileSystemWatcher; + +class PVSCheckPrivileges : public QObject { + Q_OBJECT public: typedef enum { SESSION_LOOKUP_FAILURE, // Comes first because we default to assume @@ -115,8 +121,12 @@ public: QString getX11SessionName(CachedInputContext const& sender); QString getX11DisplayDevice(CachedInputContext const& sender); +public slots: + void updateCachedUserDatabase(); + void rereadConfiguration(); + private: - PVSCheckPrivileges(); + PVSCheckPrivileges(QObject* parent = 0); virtual ~PVSCheckPrivileges(); typedef QPair > piduidgid; @@ -134,6 +144,11 @@ private: QHash _savedUserPrivilege; QHash _savedSessionKind; QHash _savedConsoleKitSession; + + QList _privilegedUsers; + QList _privilegedGroups; + QMultiMap _userGroupMap; + QFileSystemWatcher* _watcher; }; #endif /* PVSCHECKPRIVILEGES_H_ */ -- cgit v1.2.3-55-g7522 From c5c91f40c02d7b8611fb5e479f340fe19254592f Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 6 Oct 2010 15:09:43 +0200 Subject: Fix deletion order bug PVSCheckPrivileges::instance() is statically allocated. When it is deleted, the QCoreApplication is already gone (since it is stack- allocated), and the destructor of QFileSystemWatcher waits forever. --- src/input/pvsCheckPrivileges.cpp | 13 +++++++++++-- src/input/pvsCheckPrivileges.h | 1 + src/input/pvsprivinputd.cpp | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/input/pvsCheckPrivileges.cpp') diff --git a/src/input/pvsCheckPrivileges.cpp b/src/input/pvsCheckPrivileges.cpp index 71c5861..57b5d8b 100644 --- a/src/input/pvsCheckPrivileges.cpp +++ b/src/input/pvsCheckPrivileges.cpp @@ -100,8 +100,17 @@ Q_DECLARE_METATYPE(QStringStringMap) PVSCheckPrivileges* PVSCheckPrivileges::instance() { - static PVSCheckPrivileges static_instance; - return &static_instance; + static PVSCheckPrivileges* static_instance = 0; + if(!static_instance) + { + static_instance = new PVSCheckPrivileges(); + } + return static_instance; +} + +void PVSCheckPrivileges::deleteInstance() +{ + delete instance(); } PVSCheckPrivileges::PVSCheckPrivileges(QObject* parent) diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h index fc82e4c..ec6c591 100644 --- a/src/input/pvsCheckPrivileges.h +++ b/src/input/pvsCheckPrivileges.h @@ -114,6 +114,7 @@ public: } static PVSCheckPrivileges* instance(); + static void deleteInstance(); bool require(SessionKind sessionKind, CachedInputContext const& sender); bool require(UserPrivilege userPrivilege, CachedInputContext const& sender); diff --git a/src/input/pvsprivinputd.cpp b/src/input/pvsprivinputd.cpp index 361bf9f..2f19d90 100644 --- a/src/input/pvsprivinputd.cpp +++ b/src/input/pvsprivinputd.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "pvsCheckPrivileges.h" #include "pvsPrivInputSocket.h" #include "pvsPrivInputHandler.h" #include "pvsPrivInputSignalHandler.h" @@ -151,5 +152,7 @@ int main(int argc, char** argv) // and run the main loop. int ret = app.exec(); + + PVSCheckPrivileges::deleteInstance(); return ret; } -- cgit v1.2.3-55-g7522 From c8579de3b79b64bcb72adfd97d2ebf424e8df4b7 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 6 Oct 2010 15:13:31 +0200 Subject: Detect the presence of PolKit on configuration When no PolKit is installed, the program gets built without support for it. This can be overriden by specifying -DENABLE_POLKIT=ON on the cmake command line. --- src/input/CMakeLists.txt | 21 +++++++++++++++++++++ src/input/pvsCheckPrivileges.cpp | 4 ++++ 2 files changed, 25 insertions(+) (limited to 'src/input/pvsCheckPrivileges.cpp') diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index fcb5ff5..44cf6b6 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -57,6 +57,27 @@ if(UNIX) x11FakeMouseHandler.cpp privilegedHandlerForwarder.cpp ) + + # we need pkg-config to find out where to install the action file: + find_package(PkgConfig) + if(NOT PKG_CONFIG_FOUND) + # we will try to make a best effort and put our policy file into + # ${PREFIX}/share/polkit-1, but only if we can find + # the pkexec executable. + find_program(PKEXEC_LOCATION pkexec) + if(PKEXEC_LOCATION OR ENABLE_POLKIT) + set(POLKIT_FOUND ON) + endif() + else() + pkg_check_modules(POLKIT "polkit-gobject-1") + endif() + + # now, arrange for policykit integration: + if(POLKIT_FOUND OR ENABLE_POLKIT) + set_property(SOURCE ${pvsprivinputd_SRCS} + APPEND + PROPERTY COMPILE_DEFINITIONS HAVE_POLKIT) + endif() endif() add_library( diff --git a/src/input/pvsCheckPrivileges.cpp b/src/input/pvsCheckPrivileges.cpp index 57b5d8b..f9a8851 100644 --- a/src/input/pvsCheckPrivileges.cpp +++ b/src/input/pvsCheckPrivileges.cpp @@ -211,6 +211,7 @@ PVSCheckPrivileges::UserPrivilege PVSCheckPrivileges::getUserPrivilege(CachedInp } // User is not trivially privileged, so try to check with PolicyKit. +#ifdef HAVE_POLKIT // but only if it is present // For PolKit, we need the start-time of the process. // On Linux, we can get it from /proc: QString procStat = QString("/proc/%1/stat").arg(sender.pid); @@ -257,6 +258,9 @@ PVSCheckPrivileges::UserPrivilege PVSCheckPrivileges::getUserPrivilege(CachedInp return USER_LOOKUP_FAILURE; } return reply.value().isAuthorized ? USER_PRIVILEGED : USER_UNPRIVILEGED; +#else + return USER_UNPRIVILEGED; +#endif } QString PVSCheckPrivileges::getX11SessionName(CachedInputContext const& sender) -- cgit v1.2.3-55-g7522 From 958d63d244a3f4a4542c529761ccdd9cd8244fcf Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Thu, 7 Oct 2010 09:29:06 +0200 Subject: Make behaviour on lookup failures configurable --- src/input/pvsCheckPrivileges.cpp | 78 ++++++++++++++++++++++++++++++++++++---- src/input/pvsCheckPrivileges.h | 8 ++--- src/input/pvsprivinputd.conf | 16 ++++++++- 3 files changed, 88 insertions(+), 14 deletions(-) (limited to 'src/input/pvsCheckPrivileges.cpp') diff --git a/src/input/pvsCheckPrivileges.cpp b/src/input/pvsCheckPrivileges.cpp index f9a8851..2026c0a 100644 --- a/src/input/pvsCheckPrivileges.cpp +++ b/src/input/pvsCheckPrivileges.cpp @@ -311,7 +311,12 @@ bool PVSCheckPrivileges::require(SessionKind sessionKind, CachedInputContext con { SessionKind cachedSessionKind; - if(sessionKind < SESSION_NONLOCAL) + if(sessionKind == SESSION_NONLOCAL) + { + // All sessions are at least non-local + return true; + } + else if(sessionKind == SESSION_LOCAL) { if((cachedSessionKind = _savedSessionKind.value(sender, SESSION_UNKNOWN)) == SESSION_UNKNOWN) { @@ -320,18 +325,49 @@ bool PVSCheckPrivileges::require(SessionKind sessionKind, CachedInputContext con _savedSessionKind[sender] = cachedSessionKind; qDebug("Got session kind: %s", toString(cachedSessionKind).toLocal8Bit().constData()); } - if(cachedSessionKind > sessionKind) + + switch(cachedSessionKind) + { + case SESSION_LOOKUP_FAILURE: + case SESSION_UNKNOWN: + { + // If we cannot find out the correct session kind, look up what we should do in + // the configuration: + QSettings* config = pvsPrivInputGetSettings(); + QVariant assumeLocal = config->value("assume-session-local", false); + if(!assumeLocal.canConvert(QVariant::Bool)) + { + qWarning("There is an assume-session-local setting, but cannot convert it to boolean"); + return false; + } + return assumeLocal.toBool(); + } + case SESSION_LOCAL: + return true; + case SESSION_NONLOCAL: return false; + default: + qWarning("Internal error: Undefined session kind %d", (int)cachedSessionKind); + return false; + } + } + else + { + qWarning("Internal error: It does not make sense to require an unknown session or undefined session kind %d", (int)sessionKind); + return false; } - - return true; } bool PVSCheckPrivileges::require(UserPrivilege userPrivilege, CachedInputContext const& sender) { UserPrivilege cachedUserPrivilege; - if(userPrivilege < USER_UNPRIVILEGED) + if(userPrivilege == USER_UNPRIVILEGED) + { + // All users are unprivileged + return true; + } + else if(userPrivilege == USER_PRIVILEGED) { if((cachedUserPrivilege = _savedUserPrivilege.value(sender, USER_UNKNOWN)) == USER_UNKNOWN) { @@ -340,10 +376,38 @@ bool PVSCheckPrivileges::require(UserPrivilege userPrivilege, CachedInputContext _savedUserPrivilege[sender] = cachedUserPrivilege; qDebug("Got user privilege: %s", toString(cachedUserPrivilege).toLocal8Bit().constData()); } - if(cachedUserPrivilege > userPrivilege) + + switch(cachedUserPrivilege) + { + case USER_LOOKUP_FAILURE: + case USER_UNKNOWN: + { + // If we cannot find out the correct user privilege level, look up what we should do in + // the configuration: + QSettings* config = pvsPrivInputGetSettings(); + QVariant assumePrivileged = config->value("assume-user-privileged", false); + if(!assumePrivileged.canConvert(QVariant::Bool)) + { + qWarning("There is an assume-session-local setting, but cannot convert it to boolean"); + return false; + } + return assumePrivileged.toBool(); + } + case USER_PRIVILEGED: + return true; + case USER_UNPRIVILEGED: + return false; + default: + qWarning("Internal error: Found undefined user privilege level %d", (int)cachedUserPrivilege); + _savedUserPrivilege.remove(sender); return false; + } + } + else + { + qWarning("Internal error: It does not make sense to require an unknown or undefined user privilege level %d", (int)userPrivilege); + return false; } - return true; } bool PVSCheckPrivileges::require(SessionKind sessionKind, diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h index ec6c591..62b463c 100644 --- a/src/input/pvsCheckPrivileges.h +++ b/src/input/pvsCheckPrivileges.h @@ -74,11 +74,9 @@ class PVSCheckPrivileges : public QObject Q_OBJECT public: typedef enum { - SESSION_LOOKUP_FAILURE, // Comes first because we default to assume - // the session is local if we cannot look it - // up. SESSION_LOCAL, SESSION_NONLOCAL, + SESSION_LOOKUP_FAILURE, SESSION_UNKNOWN } SessionKind; static QString toString(SessionKind k) @@ -96,9 +94,7 @@ public: typedef enum { USER_PRIVILEGED, USER_UNPRIVILEGED, - USER_LOOKUP_FAILURE, // Comes last because we default to assume - // the user is unprivileged if we cannot get - // permission from PolicyKit. + USER_LOOKUP_FAILURE, USER_UNKNOWN } UserPrivilege; static QString toString(UserPrivilege k) diff --git a/src/input/pvsprivinputd.conf b/src/input/pvsprivinputd.conf index 52df206..a62a922 100644 --- a/src/input/pvsprivinputd.conf +++ b/src/input/pvsprivinputd.conf @@ -11,4 +11,18 @@ privileged-users = root ;; privileged-groups: ;; Comma-separated list of user groups that are allowed to run privileged actions ; privileged-groups = wheel - \ No newline at end of file + +;; assume-session-local: +;; Assume that a session is local if it can not be looked up in ConsoleKit, +;; for example, if you are not running ConsoleKit. +;; +;; WARNING: Setting this to true may be a security risk. Running ConsoleKit is +;; really recommended. +; assume-session-local = false + +;; assume-user-privileged: +;; Assume that a user is privileged if he/she can not be looked up in +;; the user database or PolicyKit fails to deliver an answer. +;; +;; WARNING: Setting this to true is most definitely a security risk. +; assume-user-privileged = false \ No newline at end of file -- cgit v1.2.3-55-g7522