qtransportauth_qws.cpp
来自「QT 开发环境里面一个很重要的文件」· C++ 代码 · 共 1,368 行 · 第 1/3 页
CPP
1,368 行
return yesItIs;#else return false;#endif}/*! \internal Return the authorizer device mapped to this client. Note that this could probably all be void* instead of QWSClient* for generality. Until the need for that rears its head its QWSClient* to save the casts. #### OK the need has arrived, but the public API is frozen.*/QIODevice *QTransportAuth::passThroughByClient( QWSClient *client ) const{ Q_D(const QTransportAuth); if ( client == 0 ) return 0; if ( d->buffersByClient.contains( reinterpret_cast<void*>( client ))) { return d->buffersByClient[reinterpret_cast<void*>(client)]; } // qWarning( "buffer not found for client %p", client ); return 0;}/*! \internal Return a QIODevice pointer (to an internal QBuffer) which can be used to receive data after authorisation on transport \a d. The return QIODevice will act as a pass-through. The data will be consumed from \a iod and forwarded on to the returned QIODevice which can be connected to readyRead() signal handlers in place of the original QIODevice \a iod. This will be called in the server process to handle incoming authenticated requests. \sa setTargetDevice()*/QAuthDevice *QTransportAuth::recvBuf( QTransportAuth::Data *data, QIODevice *iod ){ Q_D(QTransportAuth); if (d->buffers.contains(data)) return d->buffers[data]; QAuthDevice *authBuf = new QAuthDevice( iod, data, QAuthDevice::Receive ); for ( int i = 0; i < d->policyReceivers.count(); ++i ) { connect( authBuf, SIGNAL(policyCheck(QTransportAuth::Data&,QString)), d->policyReceivers[i], SLOT(policyCheck(QTransportAuth::Data&,QString))); } // qDebug( "created new authbuf %p", authBuf ); d->buffers[data] = authBuf; return authBuf;}/*! Return a QIODevice pointer (to an internal QBuffer) which can be used to write data onto, for authorisation on transport \a d. The return QIODevice will act as a pass-through. The data written to the return QIODevice will be forwarded on to the returned QIODevice. In the case of a QTcpSocket, this will cause it to send out the data with the authentication information on it. This will be called in the client process to generate outgoing authenticated requests. \sa setTargetDevice()*/QAuthDevice *QTransportAuth::authBuf( QTransportAuth::Data *data, QIODevice *iod ){ Q_D(QTransportAuth); if (d->buffers.contains(data)) return d->buffers[data]; QAuthDevice *authBuf = new QAuthDevice( iod, data, QAuthDevice::Send ); d->buffers[data] = authBuf; return authBuf;}const unsigned char *QTransportAuth::getClientKey( unsigned char progId ){ Q_D(QTransportAuth); return d->getClientKey( progId );}void QTransportAuth::invalidateClientKeyCache(){ Q_D(QTransportAuth); d->invalidateClientKeyCache();}QMutex *QTransportAuth::getKeyFileMutex(){ Q_D(QTransportAuth); return &d->keyfileMutex;}static struct AuthRecord *keyCache[ KEY_CACHE_SIZE ] = { 0 };/*! \internal Free the key cache on destruction of this objectTODO: reimplement this using Qt structures*/void QTransportAuthPrivate::freeCache(){ int i; for ( i = 0; i < KEY_CACHE_SIZE; ++i ) { if ( keyCache[i] == NULL ) break; ::free( keyCache[i] ); keyCache[i] = NULL; }}/*! \internal Find the client key for the \a progId. If it is cached should be very fast, otherwise requires a read of the secret key file In the success case a pointer to the key is returned. The pointer is to storage owned by this class, and should be used immediately. NULL is returned in the following cases: \list \o the keyfile could not be accessed - error condition \o there was no key for the supplied program id - key auth failed \endlist Note that for the Keyfile, there is multi-thread concurrency issues: the Keyfile can be read by the qpe process when QTransportAuth is verifying a request, and it can be read or written by the Monitor thread within the qpe process when monitor rekeying is being done. To protect against this, the keyfileMutex is used.Invariant: qpe is the only process which can access the Keyfile, there are no multi-process concurrency issues (file locking is not required).*/const unsigned char *QTransportAuthPrivate::getClientKey(unsigned char progId){ int fd, i; struct AuthRecord kr; for ( i = 0; i < KEY_CACHE_SIZE; ++i ) { if ( keyCache[i] == NULL ) break; if ( keyCache[i]->auth.progId == progId ) { return (unsigned char *)(keyCache[i]); } } if ( i == KEY_CACHE_SIZE ) // cache buffer has wrapped i = 0; ::memset( &kr, 0, sizeof( kr )); fd = ::open( m_keyFilePath.toLocal8Bit().constData(), O_RDONLY ); if ( fd == -1 ) { perror( "couldnt open keyfile" ); qWarning( "check keyfile path %s", qPrintable(m_keyFilePath) ); return NULL; } QMutexLocker keyfileLocker( &keyfileMutex ); while ( ::read( fd, &kr, sizeof( struct AuthRecord )) != 0 ) { if ( kr.auth.progId == progId ) { if ( keyCache[i] == NULL ) keyCache[i] = (AuthRecord*)(malloc( sizeof( kr )));#ifdef QTRANSPORTAUTH_DEBUG qDebug( "%li Found client key for prog %u", getpid(), progId );#endif memcpy( (char*)(keyCache[i]), &kr, sizeof( kr )); ::close( fd ); return (unsigned char *)(keyCache[i]); } } ::close( fd );#ifdef QTRANSPORTAUTH_DEBUG qWarning( "No valid key found for prog %u", progId );#endif return NULL;}void QTransportAuthPrivate::invalidateClientKeyCache(){ QMutexLocker keyfileLocker( &keyfileMutex ); for ( int i = 0; i < KEY_CACHE_SIZE; i++ ) { if ( keyCache[i] == NULL ) break; free( keyCache[i] ); keyCache[i] = 0; }}//////////////////////////////////////////////////////////////////////////////// RequestAnalyzer definition////RequestAnalyzer::RequestAnalyzer() : moreData( false ) , dataSize( 0 ){}RequestAnalyzer::~RequestAnalyzer(){}/*! Analzye the data in the\a msgQueue according to some protocol and produce a request string for policy analysis. If enough data is in the queue for analysis of a complete message, return a non-null string, and set a flag so requireMoreData() will return false; otherwise return a null string and requireMoreData() return true. The amount of bytes analyzed is then available via bytesAnalyzed(). A null string is also returned in the case where the message was corrupt and could not be analyzed. In this case requireMoreData() returns false.Note: this method will modify the msgQueue and pull off the data deemed to be corrupt, in the case of corrupt data. In all other cases the msgQueue is left alone. The calling code should then pull off the analyzed data. Use bytesAnalzyed() to find how much data to pull off the queue.*/QString RequestAnalyzer::analyze( QByteArray *msgQueue ){ dataSize = 0; moreData = false; QBuffer cmdBuf( msgQueue ); cmdBuf.open( QIODevice::ReadOnly | QIODevice::Unbuffered ); QWSCommand::Type command_type = (QWSCommand::Type)(qws_read_uint( &cmdBuf )); QWSCommand *command = QWSCommand::factory(command_type); // if NULL, factory will have already printed warning for bogus // command_type just purge the bad stuff and attempt to recover if ( command == NULL ) { *msgQueue = msgQueue->mid( sizeof(int) ); return QString(); } QString request( qws_getCommandTypeString( command_type ));#ifndef QT_NO_COP if ( !command->read( &cmdBuf )) { // not all command arrived yet - come back later delete command; moreData = true; return QString(); } if ( command_type == QWSCommand::QCopSend ) { QWSQCopSendCommand *sendCommand = static_cast<QWSQCopSendCommand*>(command); request += QString( "/QCop/%1/%2" ).arg( sendCommand->channel ).arg( sendCommand->message ); } if ( command_type == QWSCommand::QCopRegisterChannel ) { QWSQCopRegisterChannelCommand *registerCommand = static_cast<QWSQCopRegisterChannelCommand*>(command); request += QString( "/QCop/RegisterChannel/%1" ).arg( registerCommand->channel ); }#endif dataSize = QWS_PROTOCOL_ITEM_SIZE( *command ); delete command; return request;}//////////////////////////////////////////////////////////////////////////////// AuthDevice definition////QAuthDevice::QAuthDevice( QIODevice *parent, QTransportAuth::Data *data, AuthDirection dir ) : QIODevice( parent ) , d( data ) , way( dir ) , m_target( parent ) , m_client( 0 ) , m_bytesAvailable( 0 ) , m_skipWritten( 0 ) , analyzer( 0 ){ if ( dir == Receive ) // server side { connect( m_target, SIGNAL(readyRead()), this, SLOT(recvReadyRead())); } else { connect( m_target, SIGNAL(readyRead()), this, SIGNAL(readyRead())); } connect( m_target, SIGNAL(bytesWritten(qint64)), this, SLOT(targetBytesWritten(qint64)) ); open( QIODevice::ReadWrite | QIODevice::Unbuffered );}QAuthDevice::~QAuthDevice(){ if ( analyzer ) delete analyzer;}/*! \internal Store a pointer to the related device or instance which this authorizer is proxying for*/void QAuthDevice::setClient( void *cli ){ m_client = cli; QTransportAuth::getInstance()->d_func()->buffersByClient[cli] = this;}void *QAuthDevice::client() const{ return m_client;}/* \fn void QAuthDevice::authViolation(QTransportAuth::Data &) This signal is emitted if an authorization failure is generated, as described in checkAuth(); \sa checkAuth()*//* \fn void QAuthDevice::policyCheck(QTransportAuth::Data &transport, const QString &request ) This signal is emitted when a transport successfully delivers a request and gives the opportunity to either deny or accept the request. This signal must be connected in the same thread, ie it cannot be queued. As soon as all handlers connected to this signal are processed the Allow or Deny state on the \a transport is checked, and the request is allowed or denied accordingly. \sa checkAuth()*//*! \internal Reimplement QIODevice writeData method. For client end, when the device is written to the incoming data is processed and an authentication header calculated. This is pushed into the target device, followed by the actual incoming data (the payload). For server end, it is a fatal error to write to the device.*/qint64 QAuthDevice::writeData(const char *data, qint64 len){ if ( way == Receive ) // server return m_target->write( data, len ); // client#ifdef QTRANSPORTAUTH_DEBUG char displaybuf[1024];#endif char header[QSXE_HEADER_LEN]; ::memset( header, 0, QSXE_HEADER_LEN ); qint64 bytes = 0; if ( authToMessage( *d, header, data, len )) { m_target->write( header, QSXE_HEADER_LEN );#ifdef QTRANSPORTAUTH_DEBUG hexstring( displaybuf, (const unsigned char *)header, QSXE_HEADER_LEN ); qDebug( "%li QAuthDevice::writeData - CLIENT: Header written: %s", getpid(), displaybuf );#endif m_skipWritten += QSXE_HEADER_LEN; } m_target->write( data, len ); bytes += len;#ifdef QTRANSPORTAUTH_DEBUG int bytesToDisplay = bytes; const unsigned char *dataptr = (const unsigned char *)data; while ( bytesToDisplay > 0 ) { int amt = bytes < 500 ? bytes : 500; hexstring( displaybuf, dataptr, amt ); qDebug( "%li QAuthDevice::writeData - CLIENT: %s", getpid(), bytes > 0 ? displaybuf : "(null)" ); dataptr += 500; bytesToDisplay -= 500; }#endif if ( m_target->inherits( "QAbstractSocket" )) static_cast<QAbstractSocket*>(m_target)->flush(); return bytes;}/*! Reimplement from QIODevice Read data out of the internal message queue, reduce the queue by the amount read. Note that the amount available is only ever the size of a command (although a command can be very big) since we need to check at command boundaries for new authentication headers.*/qint64 QAuthDevice::readData( char *data, qint64 maxSize ){ if ( way == Send ) // client return m_target->read( data, maxSize ); if ( msgQueue.size() == 0 ) return 0;#ifdef QTRANSPORTAUTH_DEBUG char displaybuf[1024]; hexstring( displaybuf, reinterpret_cast<const unsigned char *>(msgQueue.constData()), msgQueue.size() > 500 ? 500 : msgQueue.size() ); qDebug() << getpid() << "QAuthDevice::readData() buffered/requested/avail" << msgQueue.size() << maxSize << m_bytesAvailable << displaybuf;#endif Q_ASSERT( m_bytesAvailable <= msgQueue.size() ); qint64 bytes = ( maxSize > m_bytesAvailable ) ? m_bytesAvailable : maxSize; ::memcpy( data, msgQueue.constData(), bytes ); msgQueue = msgQueue.mid( bytes ); m_bytesAvailable -= bytes; return bytes;}/*! \internal Receive readyRead signal from the target recv device. In response authorize the data, and write results out to the recvBuf() device for processing by the application. Trigger the readyRead signal. Authorizing involves first checking the transport is valid, ie the handshake has either already been done and is cached on a trusted transport, or was valid with this message; then second passing the string representation of the service request up to any policyReceivers If either of these fail, the message is denied. In discovery mode denied messages are allowed, but the message is logged.*/void QAuthDevice::recvReadyRead(){ qint64 bytes = m_target->bytesAvailable(); if ( bytes <= 0 ) return; open( QIODevice::ReadWrite | QIODevice::Unbuffered );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?