📄 qtransportauth_qws.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtGui module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qtransportauth_qws.h"#include "qtransportauth_qws_p.h"#ifndef QT_NO_SXE#include "../../3rdparty/md5/md5.h"#include "../../3rdparty/md5/md5.cpp"#include "qwsutils_qws.h"#include "qwssocket_qws.h"#include "qwscommand_qws_p.h"#include "qwindowsystem_qws.h"#include "qbuffer.h"#include "qthread.h"#include "qabstractsocket.h"#include "qlibraryinfo.h"#include "qfile.h"#include "qdebug.h"#include <syslog.h>#include <unistd.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/file.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <time.h>#include <QtCore/qcache.h>#define BUF_SIZE 512/*! \internal memset for security purposes, guaranteed not to be optimized away http://www.faqs.org/docs/Linux-HOWTO/Secure-Programs-HOWTO.html*/Q_GUI_EXPORT void *guaranteed_memset(void *v,int c,size_t n){ volatile char *p = (char *)v; while (n--) *p++=c; return v;}/*! \class QTransportAuth \internal \brief Authenticate a message transport. For performance reasons, message authentication is tied to an individual message transport instance. For example in connection oriented transports the authentication cookie can be cached against the connection avoiding the overhead of authentication on every message. For each process there is one instance of the QTransportAuth object. For server processes it can determine the \link secure-exe-environ.html SXE Program Identity \endlink and provide access to policy data to determine if the message should be forwarded for action. If not actioned, the message may be treated as being from a flawed or malicious process. Retrieve the instance with the getInstance() method. The constructor is disabled and instances of QTransportAuth should never be constructed by calling classes. To make the Authentication easier to use a proxied QIODevice is provided which uses an internal QBuffer. In the server code first get a pointer to a QTransportAuth::Data object using the connectTransport() method: \code QTransportAuth::Data *conData; QTransportAuth *a = QTransportAuth::getInstance(); conData = a->connectTransport( QTransportAuth::Trusted | QTransportAuth::UnixStreamSock, socketDescriptor ); \endcode Here it is asserted that the transport is trusted. See the assumptions listed in the \link secure-exe-environ.html SXE documentation \endlink Then proxy in the authentication device: \code // mySocket can be any QIODevice subclass AuthDevice *ad = a->recvBuf( d, mySocket ); // proxy in the auth device where the socket would have gone connect( ad, SIGNAL(readyRead()), this, SLOT(mySocketReadyRead())); \endcode In the client code it is similar. Use the connectTransport() method just the same then proxy in the authentication device instead of the socket in write calls: \code AuthDevice *ad = a->authBuf( d, mySocket ); ad->write( someData ); \endcode*/static int hmac_md5( unsigned char* text, /* pointer to data stream */ int text_length, /* length of data stream */ const unsigned char* key, /* pointer to authentication key */ int key_length, /* length of authentication key */ unsigned char * digest /* caller digest to be filled in */ );#define KEY_CACHE_SIZE 30const char * const errorStrings[] = { "pending identity verification", "message too small to carry auth data", "cache miss on connection oriented transport", "no magic bytes on message", "key not found for prog id", "authorization key match failed", "key out of date"};const char *QTransportAuth::errorString( const Data &d ){ if (( d.status & ErrMask ) == Success ) return "success"; int e = d.status & ErrMask; if ( e > OutOfDate ) return "unknown"; return errorStrings[e];}SxeRegistryLocker::SxeRegistryLocker( QObject *reg ) : m_success( false ) , m_reg( 0 ){ if ( reg ) if ( !QMetaObject::invokeMethod( reg, "lockManifest", Q_RETURN_ARG(bool, m_success) )) m_success = false; m_reg = reg;}SxeRegistryLocker::~SxeRegistryLocker(){ if ( m_success ) QMetaObject::invokeMethod( m_reg, "unlockManifest" );}QTransportAuthPrivate::QTransportAuthPrivate() : keyInitialised(false) , m_packageRegistry( 0 ){}QTransportAuthPrivate::~QTransportAuthPrivate(){}/*! \internal Construct a new QTransportAuth*/QTransportAuth::QTransportAuth() : QObject(*new QTransportAuthPrivate){ // qDebug( "creating transport auth" );}/*! \internal Destructor*/QTransportAuth::~QTransportAuth(){ // qDebug( "deleting transport auth" );}/*! Set the process key for this currently running Qtopia process to the \a authdata. \a authdata should be sizeof(struct AuthCookie) in length and contain the key and program id. Use this method when setting or changing the SXE identity of the current program.*/void QTransportAuth::setProcessKey( const char *authdata ){ Q_D(QTransportAuth); ::memcpy(&d->authKey, authdata, sizeof(struct AuthCookie)); QFile proc_key( "/proc/self/lids_key" ); // where proc key exists use that instead if ( proc_key.open( QIODevice::ReadOnly )) { qint64 kb = proc_key.read( (char*)&d->authKey.key, QSXE_KEY_LEN );#ifdef QTRANSPORTAUTH_DEBUG qDebug( "Using %li bytes of /proc/%i/lids_key\n", (long int)kb, getpid() );#else Q_UNUSED( kb );#endif } d->keyInitialised = true;}/*! Apply \a key as the process key for the currently running application. \a prog is current ignored Deprecated function*/void QTransportAuth::setProcessKey( const char *key, const char *prog ){ Q_UNUSED(prog); setProcessKey( key );#ifdef QTRANSPORTAUTH_DEBUG char displaybuf[QSXE_KEY_LEN*2+1]; hexstring( displaybuf, (const unsigned char *)key, QSXE_KEY_LEN ); qDebug() << "key" << displaybuf << "set";#endif}/*! Register \a pr as a policy handler object. The object pointed to by \a pr should have a slot as follows \code policyCheck( QTransportAuth::Data &, const QString & ) \endcode All requests received by this server will then generate a call to this slot, and may be processed for policy compliance.*/void QTransportAuth::registerPolicyReceiver( QObject *pr ){ // not every policy receiver needs setup - no error if this fails QMetaObject::invokeMethod( pr, "setupPolicyCheck" ); connect( this, SIGNAL(policyCheck(QTransportAuth::Data&,QString)), pr, SLOT(policyCheck(QTransportAuth::Data&,QString)), Qt::DirectConnection );}/*! Unregister the \a pr from being a policy handler. No more policyCheck signals are received by this object.*/void QTransportAuth::unregisterPolicyReceiver( QObject *pr ){ disconnect( pr ); // not every policy receiver needs tear down - no error if this fails QMetaObject::invokeMethod( pr, "teardownPolicyCheck" );}/*! Record a new transport connection with \a properties and \a descriptor. The calling code is responsible for destroying the returned data when the tranport connection is closed.*/QTransportAuth::Data *QTransportAuth::connectTransport( unsigned char properties, int descriptor ){ Data *data = new Data(properties, descriptor); data->status = Pending; return data;}/*! Is the transport trusted. This is true iff data written into the transport medium cannot be intercepted or modified by another process. This is for example true for Unix Domain Sockets, but not for shared memory or UDP sockets. There is of course an underlying assumption that the kernel implementing the transport is sound, ie it cannot be compromised by writing to /dev/kmem or loading untrusted modules*/inline bool QTransportAuth::Data::trusted() const{ return (bool)(properties & Trusted);}/*! Assert that the transport is trusted. For example with respect to shared memory, if it is ensured that no untrusted root processes are running, and that unix permissions have been set such that any untrusted non-root processes do not have access rights, then a shared memory transport could be asserted to be trusted. \sa trusted()*/inline void QTransportAuth::Data::setTrusted( bool t ){ properties = t ? properties | Trusted : properties & ~Trusted;}/*! Is the transport connection oriented. This is true iff once a connection has been accepted, and state established, then further messages over the transport are guaranteed to have come from the original connecting entity. This is for example true for Unix Domain Sockets, but not for shared memory or UDP sockets. By extension if the transport is not trusted() then it should not be assumed to be connection oriented, since spoofed connection information could be created. For example if we assume the TCP/IP transport is trusted, it can be treated as connection oriented; but this is only the case if intervening routers are trusted. Connection oriented transports have authorization cached against the connection, and thus authorization is only done at connect time.*/inline bool QTransportAuth::Data::connection() const{ return (bool)(properties & Connection);}/*! Assert that the transport is connection oriented. \sa connection()*/inline void QTransportAuth::Data::setConnection( bool t ){ properties = t ? properties | Connection : properties & ~Connection;}/*! Return a pointer to the instance of this process's QTransportAuth object*/QTransportAuth *QTransportAuth::getInstance(){ static QTransportAuth theInstance; return &theInstance;}/*! Set the full path to the key file Since this is normally relative to Qtopia::qpeDir() this needs to be set within the qtopia framework. The keyfile should be protected by file permissions or by MAC rules such that it can only be read/written by the "qpe" server process*/void QTransportAuth::setKeyFilePath( const QString &path ){ Q_D(QTransportAuth); d->m_keyFilePath = path;}QString QTransportAuth::keyFilePath() const{ Q_D(const QTransportAuth); return d->m_keyFilePath;}void QTransportAuth::setLogFilePath( const QString &path ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -