summaryrefslogtreecommitdiffstats
path: root/src/input
diff options
context:
space:
mode:
authorSebastien Braun2010-10-06 15:01:33 +0200
committerSebastien Braun2010-10-06 15:01:33 +0200
commit9602e1063f5459d9ca05ba8f90304b7d34072561 (patch)
tree606bccc73e6f9954dcb6896b53f4bef6fd96baaf /src/input
parentAdd headers containing translated strings to sources for pvsmgr[touch] (diff)
downloadpvs-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.
Diffstat (limited to 'src/input')
-rw-r--r--src/input/CMakeLists.txt1
-rw-r--r--src/input/pvsCheckPrivileges.cpp161
-rw-r--r--src/input/pvsCheckPrivileges.h19
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_ */