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 + -
显示快捷键?