diff options
author | Sebastien Braun | 2010-10-06 15:01:33 +0200 |
---|---|---|
committer | Sebastien Braun | 2010-10-06 15:01:33 +0200 |
commit | 9602e1063f5459d9ca05ba8f90304b7d34072561 (patch) | |
tree | 606bccc73e6f9954dcb6896b53f4bef6fd96baaf | |
parent | Add headers containing translated strings to sources for pvsmgr[touch] (diff) | |
download | pvs-9602e1063f5459d9ca05ba8f90304b7d34072561.tar.gz pvs-9602e1063f5459d9ca05ba8f90304b7d34072561.tar.xz pvs-9602e1063f5459d9ca05ba8f90304b7d34072561.zip |
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.
-rw-r--r-- | src/input/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/input/pvsCheckPrivileges.cpp | 161 | ||||
-rw-r--r-- | src/input/pvsCheckPrivileges.h | 19 |
3 files changed, 178 insertions, 3 deletions
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 <sys/types.h> +#include <pwd.h> +#include <grp.h> #include <unistd.h> #include <iostream> #include <cerrno> #include <cstdlib> +#include <cstring> #include <QCoreApplication> #include <QDir> #include <QFileInfo> +#include <QFileSystemWatcher> +#include <QSettings> #include <QTimer> #include <QtDBus/QDBusArgument> #include <QtDBus/QDBusConnection> @@ -35,6 +41,7 @@ #include <QtGlobal> #include <QDebug> #include <QUuid> +#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<QString, uid_t> 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 <sys/types.h> +#include <QObject> #include <QString> +#include <QList> +#include <QMultiMap> #include <QHash> #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<pid_t, QPair<uid_t, gid_t> > piduidgid; @@ -134,6 +144,11 @@ private: QHash<CachedInputContext, UserPrivilege> _savedUserPrivilege; QHash<CachedInputContext, SessionKind> _savedSessionKind; QHash<CachedInputContext, QString> _savedConsoleKitSession; + + QList<uid_t> _privilegedUsers; + QList<gid_t> _privilegedGroups; + QMultiMap<uid_t, gid_t> _userGroupMap; + QFileSystemWatcher* _watcher; }; #endif /* PVSCHECKPRIVILEGES_H_ */ |