From 266eb5fb14c07e67aa211a5860e9abf3009136e3 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Mon, 4 Oct 2010 00:22:14 +0200 Subject: Implement first version of basic input event support --- src/input/inputEventHandler.h | 187 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 src/input/inputEventHandler.h (limited to 'src/input/inputEventHandler.h') diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h new file mode 100644 index 0000000..3910f93 --- /dev/null +++ b/src/input/inputEventHandler.h @@ -0,0 +1,187 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # inputEventHandler.h: + # - Common definitions for input event handlers + # -------------------------------------------------------------------------- + */ + +#ifndef INPUTEVENTHANDLER_H_ +#define INPUTEVENTHANDLER_H_ + +#include +#include +#include +#include +#include + +#define HANDLER_TYPE_DONT_CARE 0xffff +#define HANDLER_CODE_DONT_CARE 0xffff +#define HANDLER_VALUE_DONT_CARE 0xffffffff + +template +class DefaultInputEventHandler { +public: + static bool matches(InputEvent const& evt) { + if(Type != 0xffff) { + if(evt.type() != Type) + return false; + } + if(Code != 0xffff) { + if(evt.code() != Code) + return false; + } + if(Value != 0xffffffff) { + if(evt.value() != Value) + return false; + } + return true; + } + + static void initialize() + { + } +}; + +namespace policy { + +struct NoSecurityCheck { + static bool allow(InputEvent const&) { + return true; + } +}; + +struct PhysicalSeatSecurityCheck { + static bool allow(InputEvent const&) { + return /* TODO implement */ true; + } +}; + +struct AlwaysDenySecurityCheck { + static bool allow(InputEvent const&) { + return false; + } +}; + +struct UnixLike; +struct Linux; +struct Windows; + +#if defined(__linux) +typedef boost::mpl::vector2::type Systems; +#elif defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +typedef boost::mpl::vector1::type Systems; +#else +# error "Porting is needed!" +#endif + +struct SystemEnabled; +struct SystemDisabled; + +template +struct RequireSystem +{ + typedef typename boost::mpl::contains::type enabled_type; + static const bool enabled = enabled_type::value; +}; + +struct RequireNoSystem +{ + typedef boost::mpl::bool_::type enabled_type; + static const bool enabled = enabled_type::value; +}; + +} + +template +class HandlerHelper +{ +public: + static bool handle(InputEvent const& evt) { + if(!SecurityPolicy::allow(evt)) + { + return true; + } + if(Delegate::matches(evt)) { + Delegate::handle(evt); + return true; + } else { + return false; + } + } + + static void initialize() + { + Delegate::initialize(); + } +}; + +template +class HandlerHelper +{ +public: + static bool handle(InputEvent const& evt) { + return false; + } + + static void initialize() + { + } +}; + +template +struct Handler : public HandlerHelper +{ +}; + +template +struct InputEventHandlerChainHelper +{ +private: + typedef typename boost::mpl::next::type next_iterator_type; + typedef InputEventHandlerChainHelper next_in_chain; + + typedef typename boost::mpl::deref::type handler_type; + +public: + static void handle(InputEvent const& evt) { + if(!handler_type::handle(evt)) { + next_in_chain::handle(evt); + } + } + + static void initialize() { + handler_type::initialize(); + next_in_chain::initialize(); + } +}; + +template +struct InputEventHandlerChainHelper +{ +public: + static void handle(InputEvent const&) { + // do nothing + } + + static void initialize() { + // do nothing + } +}; + +template +struct InputEventHandlerChain : public InputEventHandlerChainHelper::type, typename boost::mpl::end::type> +{ +}; + +#endif /* INPUTEVENTHANDLER_H_ */ -- cgit v1.2.3-55-g7522 From c5c46660130456afea285e460be44e1c723e4a49 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 5 Oct 2010 15:07:43 +0200 Subject: Refactor InputEvent handler code. - Make static methods virtual and store instances in the chains. - Propagate security context information. - Saner security policy implementation. --- src/input/inputEventHandler.h | 108 +++++++++++++++++++++++------------ src/input/inputHandlerChain.h | 34 +++++++++++ src/input/unprivilegedHandlerChain.h | 34 ----------- src/input/x11FakeKeyboardHandler.cpp | 4 +- src/input/x11FakeKeyboardHandler.h | 4 +- src/input/x11FakeMouseHandler.cpp | 6 +- src/input/x11FakeMouseHandler.h | 4 +- src/pvs.cpp | 6 +- src/pvs.h | 2 + 9 files changed, 121 insertions(+), 81 deletions(-) create mode 100644 src/input/inputHandlerChain.h delete mode 100644 src/input/unprivilegedHandlerChain.h (limited to 'src/input/inputEventHandler.h') diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 3910f93..330f5a7 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -27,49 +27,80 @@ #define HANDLER_CODE_DONT_CARE 0xffff #define HANDLER_VALUE_DONT_CARE 0xffffffff +class InputEventContext +{ +public: + virtual pid_t getSenderPid() const = 0; + virtual uid_t getSenderUid() const = 0; + virtual gid_t getSenderGid() const = 0; +}; + +struct SpecialInputEventDescription +{ + SpecialInputEventDescription(QString const& d, quint16 t, quint16 c, quint32 v = 0) + : descriptionString(d), evtType(t), evtCode(c), evtValue(v) + { + } + + QString descriptionString; + quint16 evtType; + quint16 evtCode; + quint32 evtValue; + + InputEvent toEvent() const + { + return InputEvent(evtType, evtCode, evtValue); + } +}; + template class DefaultInputEventHandler { public: - static bool matches(InputEvent const& evt) { - if(Type != 0xffff) { + virtual bool matches(InputEvent const& evt, InputEventContext const*) { + if(Type != HANDLER_TYPE_DONT_CARE) { if(evt.type() != Type) return false; } - if(Code != 0xffff) { + if(Code != HANDLER_CODE_DONT_CARE) { if(evt.code() != Code) return false; } - if(Value != 0xffffffff) { + if(Value != HANDLER_VALUE_DONT_CARE) { if(evt.value() != Value) return false; } return true; } - static void initialize() + virtual void initialize() { } -}; -namespace policy { + virtual void handle(InputEvent const& evt, InputEventContext const*) = 0; -struct NoSecurityCheck { - static bool allow(InputEvent const&) { - return true; + static void describeInto(QList& description) + { } }; -struct PhysicalSeatSecurityCheck { - static bool allow(InputEvent const&) { - return /* TODO implement */ true; - } +namespace policy { + +enum SecurityFlags { + SEC_PHYSICAL_SEAT = 1, + SEC_PRIVILEGED_USER = 2 }; -struct AlwaysDenySecurityCheck { - static bool allow(InputEvent const&) { - return false; +bool allowPhysicalSeat(InputEvent const& evt, InputEventContext const* ctx); +bool allowPrivilegedUser(InputEvent const& evt, InputEventContext const* ctx); + +template +struct Security +{ + bool allow(InputEvent const& evt, InputEventContext const* ctx) + { + return true; } }; @@ -107,39 +138,43 @@ template class HandlerHelper { public: - static bool handle(InputEvent const& evt) { - if(!SecurityPolicy::allow(evt)) + bool handle(InputEvent const& evt, InputEventContext const* context = 0) { + if(!securityPolicy.allow(evt, context)) { return true; } - if(Delegate::matches(evt)) { - Delegate::handle(evt); + if(delegate.matches(evt, context)) { + delegate.handle(evt, context); return true; } else { return false; } } - static void initialize() + void initialize() { - Delegate::initialize(); + delegate.initialize(); } + +private: + Delegate delegate; + SecurityPolicy securityPolicy; }; template class HandlerHelper { public: - static bool handle(InputEvent const& evt) { + bool handle(InputEvent const& evt, InputEventContext const* context = 0) { return false; } - static void initialize() + void initialize() { } }; -template +template > struct Handler : public HandlerHelper { }; @@ -153,28 +188,31 @@ private: typedef typename boost::mpl::deref::type handler_type; + handler_type _handler; + next_in_chain _next; + public: - static void handle(InputEvent const& evt) { - if(!handler_type::handle(evt)) { - next_in_chain::handle(evt); + void handle(InputEvent const& evt, InputEventContext const* context = 0) { + if(!_handler.handle(evt, context)) { + _next.handle(evt, context); } } - static void initialize() { - handler_type::initialize(); - next_in_chain::initialize(); + void initialize() { + _handler.initialize(); + _next.initialize(); + } } }; template struct InputEventHandlerChainHelper { -public: - static void handle(InputEvent const&) { + void handle(InputEvent const&, InputEventContext const* context = 0) { // do nothing } - static void initialize() { + void initialize() { // do nothing } }; diff --git a/src/input/inputHandlerChain.h b/src/input/inputHandlerChain.h new file mode 100644 index 0000000..4bb9fe5 --- /dev/null +++ b/src/input/inputHandlerChain.h @@ -0,0 +1,34 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # inputHandlerChain.h: + # - Definition of the input handler chain + # -------------------------------------------------------------------------- + */ + +#ifndef INPUTHANDLERCHAIN_H_ +#define INPUTHANDLERCHAIN_H_ + +#include +#include "inputEventHandler.h" + +#include "x11FakeKeyboardHandler.h" +#include "x11FakeMouseHandler.h" + +typedef boost::mpl::list< + Handler >, + Handler >, + Handler > +>::type unprivileged_handler_list; + +typedef InputEventHandlerChain unprivileged_handler_chain; + +#endif /* INPUTHANDLERCHAIN_H_ */ diff --git a/src/input/unprivilegedHandlerChain.h b/src/input/unprivilegedHandlerChain.h deleted file mode 100644 index 734720a..0000000 --- a/src/input/unprivilegedHandlerChain.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - # 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/ - # -------------------------------------------------------------------------- - # inputHandlerChain.h: - # - Definition of the input handler chain - # -------------------------------------------------------------------------- - */ - -#ifndef INPUTHANDLERCHAIN_H_ -#define INPUTHANDLERCHAIN_H_ - -#include -#include "inputEventHandler.h" - -#include "x11FakeKeyboardHandler.h" -#include "x11FakeMouseHandler.h" - -typedef boost::mpl::list< - Handler >, - Handler >, - Handler > ->::type unprivileged_handler_list; - -typedef InputEventHandlerChain unprivileged_handler_chain; - -#endif /* INPUTHANDLERCHAIN_H_ */ diff --git a/src/input/x11FakeKeyboardHandler.cpp b/src/input/x11FakeKeyboardHandler.cpp index 82cc437..3a0b864 100644 --- a/src/input/x11FakeKeyboardHandler.cpp +++ b/src/input/x11FakeKeyboardHandler.cpp @@ -20,6 +20,7 @@ // Qt headers need to be included before X11 headers #include #include +#include "x11FakeKeyboardHandler.h" // #include #include #include @@ -30,7 +31,6 @@ #include #include #include "x11InputUtils.h" -#include "x11FakeKeyboardHandler.h" //////////////////////// INPUT EVENT TRANSLATION ///////////////////////////////// @@ -766,7 +766,7 @@ void X11FakeKeyboardHandler::initialize() current_modifiers = 0; } -void X11FakeKeyboardHandler::handle(InputEvent const& evt) +void X11FakeKeyboardHandler::handle(InputEvent const& evt, InputEventContext const*) { Display* dpy = X11InputUtils::display(); diff --git a/src/input/x11FakeKeyboardHandler.h b/src/input/x11FakeKeyboardHandler.h index c888202..3dde7cc 100644 --- a/src/input/x11FakeKeyboardHandler.h +++ b/src/input/x11FakeKeyboardHandler.h @@ -22,8 +22,8 @@ class X11FakeKeyboardHandler : public DefaultInputEventHandler { public: - static void handle(InputEvent const&); - static void initialize(); + void handle(InputEvent const&, InputEventContext const* = 0); + void initialize(); }; #endif /* X11FAKEKEYBOARDHANDLER_H_ */ diff --git a/src/input/x11FakeMouseHandler.cpp b/src/input/x11FakeMouseHandler.cpp index 432e19f..58415d5 100644 --- a/src/input/x11FakeMouseHandler.cpp +++ b/src/input/x11FakeMouseHandler.cpp @@ -14,12 +14,12 @@ # -------------------------------------------------------------------------- */ +#include "x11FakeMouseHandler.h" // need to include before X headers #include #include #include "x11InputUtils.h" -#include "x11FakeMouseHandler.h" -void X11FakeMouseButtonHandler::handle(InputEvent const& evt) +void X11FakeMouseButtonHandler::handle(InputEvent const& evt, InputEventContext const*) { quint16 pressedButton = evt.pressedButton(); @@ -42,7 +42,7 @@ void X11FakeMouseButtonHandler::handle(InputEvent const& evt) XFlush(dpy); } -void X11FakeMouseMovementHandler::handle(InputEvent const& evt) +void X11FakeMouseMovementHandler::handle(InputEvent const& evt, InputEventContext const*) { ConsoleLog writeLine(QString("Received mouse motion event (%1,%2)").arg(evt.xCoord()).arg(evt.yCoord())); Display* dpy = X11InputUtils::display(); diff --git a/src/input/x11FakeMouseHandler.h b/src/input/x11FakeMouseHandler.h index 19ed29e..0e32256 100644 --- a/src/input/x11FakeMouseHandler.h +++ b/src/input/x11FakeMouseHandler.h @@ -22,13 +22,13 @@ class X11FakeMouseButtonHandler : public DefaultInputEventHandler { public: - static void handle(InputEvent const&); + void handle(InputEvent const&, InputEventContext const* = 0); }; class X11FakeMouseMovementHandler : public DefaultInputEventHandler { public: - static void handle(InputEvent const&); + void handle(InputEvent const&, InputEventContext const* = 0); }; #endif /* X11FAKEMOUSEHANDLER_H_ */ diff --git a/src/pvs.cpp b/src/pvs.cpp index e44d04d..911ed0d 100644 --- a/src/pvs.cpp +++ b/src/pvs.cpp @@ -16,7 +16,7 @@ #include "src/net/pvsServiceDiscovery.h" #include "src/net/pvsDiscoveredServer.h" #include "src/input/inputEvent.h" -#include "src/input/unprivilegedHandlerChain.h" +#include "src/input/inputHandlerChain.h" #include "src/input/x11InputUtils.h" // D-Bus @@ -643,11 +643,11 @@ void PVS::handleInputEvent(InputEvent const& evt) { std::string s = evt.toString(); ConsoleLog writeLine(QString("Received input event: %1").arg(s.c_str())); - unprivileged_handler_chain::handle(evt); + _inputEventHandlers.handle(evt); } void PVS::initializeInputEventHandling() { X11InputUtils::setDisplay(X11Info::display()); - unprivileged_handler_chain::initialize(); + _inputEventHandlers.initialize(); } diff --git a/src/pvs.h b/src/pvs.h index 8e94169..f4e53c0 100644 --- a/src/pvs.h +++ b/src/pvs.h @@ -24,6 +24,7 @@ #include "src/version.h" #include "src/util/consoleLogger.h" #include "src/util/clientGUIUtils.h" +#include "src/input/inputHandlerChain.h" class PVSServiceDiscovery; @@ -144,6 +145,7 @@ private: int _timerLockDelay; // input event handling: + unprivileged_handler_chain _inputEventHandlers; void handleInputEvent(InputEvent const& evt); void initializeInputEventHandling(); }; -- cgit v1.2.3-55-g7522 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/inputEventHandler.cpp | 36 +++++ src/input/inputEventHandler.h | 4 + src/input/pvsCheckPrivileges.cpp | 314 +++++++++++++++++++++++++++++++++++++++ src/input/pvsCheckPrivileges.h | 139 +++++++++++++++++ 4 files changed, 493 insertions(+) create mode 100644 src/input/inputEventHandler.cpp create mode 100644 src/input/pvsCheckPrivileges.cpp create mode 100644 src/input/pvsCheckPrivileges.h (limited to 'src/input/inputEventHandler.h') diff --git a/src/input/inputEventHandler.cpp b/src/input/inputEventHandler.cpp new file mode 100644 index 0000000..c16c358 --- /dev/null +++ b/src/input/inputEventHandler.cpp @@ -0,0 +1,36 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # inputEventHandler.h: + # - Common definitions for input event handlers - implementation + # -------------------------------------------------------------------------- + */ + +#include "inputEventHandler.h" +#include "pvsCheckPrivileges.h" + +bool policy::allowPrivilegedUser(InputEvent const& evt, InputEventContext const* ctx) +{ + if(ctx) + return PVSCheckPrivileges::instance()->require(PVSCheckPrivileges::SESSION_UNKNOWN, PVSCheckPrivileges::USER_PRIVILEGED, + ctx); + else + return false; +} + +bool policy::allowPhysicalSeat(InputEvent const& evt, InputEventContext const* ctx) +{ + if(ctx) + return PVSCheckPrivileges::instance()->require(PVSCheckPrivileges::SESSION_LOCAL, PVSCheckPrivileges::USER_UNKNOWN, + ctx); + else + return false; +} diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 330f5a7..a0ada2e 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -100,6 +100,10 @@ struct Security { bool allow(InputEvent const& evt, InputEventContext const* ctx) { + if((flags & SEC_PHYSICAL_SEAT) && !allowPhysicalSeat(evt, ctx)) + return false; + if((flags & SEC_PRIVILEGED_USER) && !allowPrivilegedUser(evt, ctx)) + return false; return true; } }; 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))); +} diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h new file mode 100644 index 0000000..e5cc9a4 --- /dev/null +++ b/src/input/pvsCheckPrivileges.h @@ -0,0 +1,139 @@ +/* + # Copyright (c) 2009,2010 - 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/ + # ----------------------------------------------------------------------------- + # src/net/pvsCheckPrivileges_linux.h + # - Linux implementation of privilege checking + # ----------------------------------------------------------------------------- + */ + +#ifndef PVSCHECKPRIVILEGES_H_ +#define PVSCHECKPRIVILEGES_H_ + +#include +#include +#include +#include "inputEventHandler.h" + +struct CachedInputContext +{ + CachedInputContext(InputEventContext const* source) + { + if(source) + { + pid = source->getSenderPid(); + uid = source->getSenderUid(); + gid = source->getSenderGid(); + } + else + { + pid = (pid_t)-1; + uid = (uid_t)-1; + gid = (gid_t)-1; + } + } + + CachedInputContext() + { + pid = (pid_t)-1; + uid = (uid_t)-1; + gid = (gid_t)-1; + } + + pid_t pid; + uid_t uid; + gid_t gid; + + bool isValid() const + { + return (pid != (pid_t)-1) && (uid != (uid_t)-1) && (gid != (gid_t)-1); + } + + bool operator==(CachedInputContext const& other) const + { + return (other.pid == pid) && (other.uid == uid) && (other.gid == gid); + } +}; +uint qHash(CachedInputContext const& p); + +class PVSCheckPrivileges +{ +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_UNKNOWN + } SessionKind; + static QString toString(SessionKind k) + { + switch(k) + { + case SESSION_LOOKUP_FAILURE: return "SESSION_LOOKUP_FAILURE"; + case SESSION_LOCAL: return "SESSION_LOCAL"; + case SESSION_NONLOCAL: return "SESSION_NONLOCAL"; + case SESSION_UNKNOWN: return "SESSION_UNKNOWN"; + default: return QString("unknown value (%1)").arg(k); + } + } + + 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_UNKNOWN + } UserPrivilege; + static QString toString(UserPrivilege k) + { + switch(k) + { + case USER_PRIVILEGED: return "USER_PRIVILEGED"; + case USER_UNPRIVILEGED: return "USER_UNPRIVILEGED"; + case USER_LOOKUP_FAILURE: return "USER_LOOKUP_FAILURE"; + case USER_UNKNOWN: return "USER_UNKNOWN"; + default: return QString("unknown value (%1)").arg(k); + } + } + + static PVSCheckPrivileges* instance(); + + bool require(SessionKind sessionKind, CachedInputContext const& sender); + bool require(UserPrivilege userPrivilege, CachedInputContext const& sender); + bool require(SessionKind sessionKind, UserPrivilege userPrivilege, CachedInputContext const& sender); + QString getX11SessionName(CachedInputContext const& sender); + QString getX11DisplayDevice(CachedInputContext const& sender); + +private: + PVSCheckPrivileges(); + virtual ~PVSCheckPrivileges(); + + typedef QPair > piduidgid; + piduidgid makePidUidGid(pid_t pid, uid_t uid, gid_t gid) + { + return qMakePair(pid, qMakePair(uid, gid)); + } + + QString getSessionReference(CachedInputContext const& sender); + SessionKind getSessionKind(CachedInputContext const& sender); + UserPrivilege getUserPrivilege(CachedInputContext const& sender); + + static PVSCheckPrivileges* _instance; + + QHash _savedUserPrivilege; + QHash _savedSessionKind; + QHash _savedConsoleKitSession; +}; + +#endif /* PVSCHECKPRIVILEGES_H_ */ -- cgit v1.2.3-55-g7522 From e3dcd9bc390bab4e650ec5bcbc1720cdcdea0247 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 5 Oct 2010 15:26:13 +0200 Subject: Add description to input event handlers so they can --- src/input/inputEventHandler.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'src/input/inputEventHandler.h') diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index a0ada2e..44713c2 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -18,6 +18,9 @@ #define INPUTEVENTHANDLER_H_ #include +#include +#include +#include #include #include #include @@ -57,6 +60,12 @@ template class DefaultInputEventHandler { +protected: + static QString tr(char const* string) + { + return QCoreApplication::translate("InputEventHandler", string); + } + public: virtual bool matches(InputEvent const& evt, InputEventContext const*) { if(Type != HANDLER_TYPE_DONT_CARE) { @@ -160,6 +169,11 @@ public: delegate.initialize(); } + static void describeInto(QList& list) + { + Delegate::describeInto(list); + } + private: Delegate delegate; SecurityPolicy securityPolicy; @@ -176,6 +190,10 @@ public: void initialize() { } + + static void describeInto(QList&) + { + } }; template > @@ -206,6 +224,18 @@ public: _handler.initialize(); _next.initialize(); } + + static void describeInto(QList& list) + { + handler_type::describeInto(list); + next_in_chain::describeInto(list); + } + + static QList describe() + { + QList list; + describeInto(list); + return list; } }; @@ -219,6 +249,16 @@ struct InputEventHandlerChainHelper void initialize() { // do nothing } + + static void describeInto(QList&) + { + // do nothing + } + + static QList describe() + { + return QList(); + } }; template -- cgit v1.2.3-55-g7522 From c5a99933202c91630edc2ddd97e0e964b27540d6 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 6 Oct 2010 17:56:59 +0200 Subject: Sanitize security model yet again The flags model was not satisfactory since it made it unnecessarily difficult to express the standard policy of "allow all to users that are physically sitting in front of the machine and to privileged users". The new model expressly knows different policies (two at the moment) and refrains from decomposing them. Additional policies are not difficult to add. --- src/input/CMakeLists.txt | 2 +- src/input/inputEventHandler.h | 58 +++++++++++++++++++++++++++++++------------ src/input/inputHandlerChain.h | 10 ++++---- 3 files changed, 48 insertions(+), 22 deletions(-) (limited to 'src/input/inputEventHandler.h') diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 398ca55..0e72c4c 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -2,7 +2,6 @@ include(${QT_USE_FILE}) set(pvsinput_SRCS inputEvent.cpp - inputEventHandler.cpp ) if(UNIX) @@ -23,6 +22,7 @@ if(UNIX) rebootSystemHandler.cpp killX11Handler.cpp sayHelloHandler.cpp + inputEventHandler.cpp ) set(pvsprivinputd_MOC_HDRS diff --git a/src/input/inputEventHandler.h b/src/input/inputEventHandler.h index 44713c2..52e3338 100644 --- a/src/input/inputEventHandler.h +++ b/src/input/inputEventHandler.h @@ -18,6 +18,7 @@ #define INPUTEVENTHANDLER_H_ #include +#include #include #include #include @@ -97,26 +98,33 @@ public: namespace policy { enum SecurityFlags { - SEC_PHYSICAL_SEAT = 1, - SEC_PRIVILEGED_USER = 2 + SEC_FREE_FOR_ALL, + SEC_PHYSICAL_OR_PRIVILEGED }; bool allowPhysicalSeat(InputEvent const& evt, InputEventContext const* ctx); bool allowPrivilegedUser(InputEvent const& evt, InputEventContext const* ctx); -template -struct Security +struct SecurityAllowAny { bool allow(InputEvent const& evt, InputEventContext const* ctx) { - if((flags & SEC_PHYSICAL_SEAT) && !allowPhysicalSeat(evt, ctx)) - return false; - if((flags & SEC_PRIVILEGED_USER) && !allowPrivilegedUser(evt, ctx)) - return false; return true; } }; +struct SecurityAllowPhysicalOrPrivileged +{ + bool allow(InputEvent const& evt, InputEventContext const* ctx) + { + if(allowPhysicalSeat(evt, ctx)) + return true; + else if(allowPrivilegedUser(evt, ctx)) + return true; + return false; + } +}; + struct UnixLike; struct Linux; struct Windows; @@ -154,6 +162,8 @@ public: bool handle(InputEvent const& evt, InputEventContext const* context = 0) { if(!securityPolicy.allow(evt, context)) { + std::string evtStr = evt.toString(); + qWarning("Input Event %s has been denied by security policy", evtStr.c_str()); return true; } if(delegate.matches(evt, context)) { @@ -196,19 +206,32 @@ public: } }; -template > +template struct Handler : public HandlerHelper { }; -template +template +struct ApplyDefaultSecurityPolicy +{ + typedef HandlerType type; +}; + +template +struct ApplyDefaultSecurityPolicy > +{ + typedef Handler type; +}; + +template struct InputEventHandlerChainHelper { private: typedef typename boost::mpl::next::type next_iterator_type; - typedef InputEventHandlerChainHelper next_in_chain; + typedef InputEventHandlerChainHelper next_in_chain; - typedef typename boost::mpl::deref::type handler_type; + typedef typename boost::mpl::deref::type handler_entry_type; + typedef typename ApplyDefaultSecurityPolicy::type handler_type; handler_type _handler; next_in_chain _next; @@ -239,8 +262,8 @@ public: } }; -template -struct InputEventHandlerChainHelper +template +struct InputEventHandlerChainHelper { void handle(InputEvent const&, InputEventContext const* context = 0) { // do nothing @@ -261,8 +284,11 @@ struct InputEventHandlerChainHelper } }; -template -struct InputEventHandlerChain : public InputEventHandlerChainHelper::type, typename boost::mpl::end::type> +template +struct InputEventHandlerChain : + public InputEventHandlerChainHelper::type, + typename boost::mpl::end::type> { }; diff --git a/src/input/inputHandlerChain.h b/src/input/inputHandlerChain.h index 8bcb1d8..b012aa6 100644 --- a/src/input/inputHandlerChain.h +++ b/src/input/inputHandlerChain.h @@ -34,14 +34,14 @@ typedef boost::mpl::list< Handler >::type unprivileged_handler_list; -typedef InputEventHandlerChain unprivileged_handler_chain; +typedef InputEventHandlerChain unprivileged_handler_chain; typedef boost::mpl::list< - Handler, - Handler, policy::Security >, - Handler, policy::Security > + Handler, + Handler >, + Handler > >::type privileged_handler_list; -typedef InputEventHandlerChain privileged_handler_chain; +typedef InputEventHandlerChain privileged_handler_chain; #endif /* INPUTHANDLERCHAIN_H_ */ -- cgit v1.2.3-55-g7522