📄 qtransportauth_qws.cpp
字号:
Q_D(QTransportAuth); d->m_logFilePath = path;}QString QTransportAuth::logFilePath() const{ Q_D(const QTransportAuth); return d->m_logFilePath;}void QTransportAuth::setPackageRegistry( QObject *registry ){ Q_D(QTransportAuth); d->m_packageRegistry = registry;}bool QTransportAuth::isDiscoveryMode() const{#if defined(SXE_DISCOVERY) static bool checked = false; static bool yesItIs = false; if ( checked ) return yesItIs; yesItIs = ( getenv( "SXE_DISCOVERY_MODE" ) != 0 ); if ( yesItIs ) { qWarning("SXE Discovery mode on, ALLOWING ALL requests and logging to %s", qPrintable(logFilePath())); QFile::remove( logFilePath() ); } checked = true; 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( client )) { return d->buffersByClient[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. The returned QIODevice will take ownership of \a data which will be deleted when the QIODevice is delected. \sa setTargetDevice()*/QAuthDevice *QTransportAuth::recvBuf( QTransportAuth::Data *data, QIODevice *iod ){ return new QAuthDevice( iod, data, QAuthDevice::Receive );}/*! 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. The returned QIODevice will take ownership of \a data which will be deleted when the QIODevice is delected. \sa setTargetDevice()*/QAuthDevice *QTransportAuth::authBuf( QTransportAuth::Data *data, QIODevice *iod ){ return new QAuthDevice( iod, data, QAuthDevice::Send );}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;}/* \internal Respond to the destroyed(QObject*) signal of the QAuthDevice's client object and remove it from the buffersByClient lookup hash.*/void QTransportAuth::bufferDestroyed( QObject *cli ){ Q_D(QTransportAuth); if ( cli == NULL ) return; if ( d->buffersByClient.contains( cli )) { d->buffersByClient.remove( cli ); // qDebug( "@@@@@@@ client %p removed @@@@@@@@@", cli ); } // qDebug( " client count %d", d->buffersByClient.count() );}bool QTransportAuth::authorizeRequest( QTransportAuth::Data &d, const QString &request ){ bool isAuthorized = true; if ( !request.isEmpty() && request != "Unknown" ) { d.status &= QTransportAuth::ErrMask; // clear the status emit policyCheck( d, request ); isAuthorized = (( d.status & QTransportAuth::StatusMask ) == QTransportAuth::Allow ); }#if defined(SXE_DISCOVERY) if (isDiscoveryMode()) {#ifndef QT_NO_TEXTSTREAM if (!logFilePath().isEmpty()) { QFile log( logFilePath() ); if (!log.open(QIODevice::WriteOnly | QIODevice::Append)) { qWarning("Could not write to log in discovery mode: %s", qPrintable(logFilePath())); } else { QTextStream ts( &log ); ts << d.progId << '\t' << ( isAuthorized ? "Allow" : "Deny" ) << '\t' << request << endl; } }#endif isAuthorized = true; }#endif if ( !isAuthorized ) { qWarning( "%s - denied: for Program Id %u [PID %d]" , qPrintable(request), d.progId, d.processId ); char linkTarget[BUF_SIZE]=""; char exeLink[BUF_SIZE]=""; char cmdlinePath[BUF_SIZE]=""; char cmdline[BUF_SIZE]=""; //get executable from /proc/pid/exe snprintf( exeLink, BUF_SIZE, "/proc/%d/exe", d.processId ); if ( -1 == ::readlink( exeLink, linkTarget, BUF_SIZE - 1 ) ) { qWarning( "SXE:- Error encountered in retrieving executable link target from /proc/%u/exe : %s", d.processId, strerror(errno) ); snprintf( linkTarget, BUF_SIZE, "%s", linkTarget ); } //get cmdline from proc/pid/cmdline snprintf( cmdlinePath, BUF_SIZE, "/proc/%d/cmdline", d.processId ); int cmdlineFd = open( cmdlinePath, O_RDONLY ); if ( cmdlineFd == -1 ) { qWarning( "SXE:- Error encountered in opening /proc/%u/cmdline: %s", d.processId, strerror(errno) ); snprintf( cmdline, BUF_SIZE, "%s", "Unknown" ); } else { if ( -1 == ::read(cmdlineFd, cmdline, BUF_SIZE - 1 ) ) { qWarning( "SXE:- Error encountered in reading /proc/%u/cmdline : %s", d.processId, strerror(errno) ); snprintf( cmdline, BUF_SIZE, "%s", "Unknown" ); } close( cmdlineFd ); } syslog( LOG_ERR | LOG_LOCAL6, "%s // PID:%u // ProgId:%u // Exe:%s // Request:%s // Cmdline:%s", "<SXE Breach>", d.processId, d.progId, linkTarget, qPrintable(request), cmdline); } return isAuthorized;}inline bool __fileOpen( QFile *f ){#ifdef QTRANSPORTAUTH_DEBUG if ( f->open( QIODevice::ReadOnly )) { qDebug( "Opened file: %s\n", qPrintable( f->fileName() )); return true; } else { qWarning( "Could not open file: %s\n", qPrintable( f->fileName() )); return false; }#else return ( f->open( QIODevice::ReadOnly ));#endif}/*! \internal Find client keys 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 keys is returned. The pointer is to storage allocated for the internal cache and must be used asap. The list returned is a sequence of one or more keys which match the progId. There is no separator, each 16 byte sequence represents a key. The sequence is followed by two iterations of the SXE magic bytes,eg 0xBA, 0xD4, 0xD4, 0xBA, 0xBA, 0xD4, 0xD4, 0xBA NULL is returned in the following cases: \list \o the keyfiles could not be accessed - error condition \o there was no key for the supplied program id - key auth failed \endlist Note that for the keyfiles, there is multi-thread and multi-process concurrency issues: they can be read by the qpe process when QTransportAuth calls getClientKey to verify a request, and they can be read or written by the packagemanager when updating package data. To protect against this, the keyfileMutex & SxeRegistryLocker is used. The sxe_installer tool can also update inode and device numbers in the manifest file, but this only occurs outside of normal operation, so qpe and packagemanager are never running when this occurs.*/const unsigned char *QTransportAuthPrivate::getClientKey(unsigned char progId){ int manifestMatchCount = 0; struct IdBlock mr; struct usr_key_entry kr; int total_size = 0; char *result = 0; char *result_ptr; int keysFound = 0; bool foundKey; int keysRead = 0; struct usr_key_entry keys_list[128]; if ( keyCache.contains( progId )) return (const unsigned char *)keyCache[progId]; SxeRegistryLocker rlock( m_packageRegistry ); // This is hacky - fix in 4.3 - see documentation for setKeyFilePath QString manifestPath = m_keyFilePath + QLatin1String( "/manifest" ); QString actualKeyPath( "/proc/lids/keys" ); bool noFailOnKeyMissing = true; if ( !QFile::exists( actualKeyPath )) { actualKeyPath = m_keyFilePath + QLatin1String( "/" QSXE_KEYFILE ); noFailOnKeyMissing = false; } QFile kf( actualKeyPath ); QFile mn( manifestPath ); if ( !__fileOpen( &mn )) goto key_not_found; // first find how much storage is needed while ( mn.read( (char*)&mr, sizeof(struct IdBlock)) != 0 ) if ( mr.progId == progId ) manifestMatchCount++; if ( manifestMatchCount == 0 ) goto key_not_found; if ( !__fileOpen( &kf )) { noFailOnKeyMissing = false; goto key_not_found; } total_size = 2 * QSXE_MAGIC_BYTES + manifestMatchCount * QSXE_KEY_LEN; result = (char*)malloc( total_size ); Q_CHECK_PTR( result ); mn.seek( 0 ); result_ptr = result; /* reading whole key array in is much more efficient, 99% case is this loop only executes once, should not have more than 128 keyed items */ while (( keysRead = kf.read( (char*)keys_list, sizeof(struct usr_key_entry)*128 )) != 0 ) { /* qDebug("PID %d: getClientKey() - read %d bytes = %d keys from %s", getpid(), keysRead, keysRead/sizeof(struct usr_key_entry), qPrintable(actualKeyPath)); */ keysRead /= sizeof(struct usr_key_entry); while ( mn.read( (char*)&mr, sizeof(struct IdBlock)) != 0 ) { if ( mr.progId == progId ) { foundKey = false; for ( int i = 0; i < keysRead; ++i ) { /* if ( i == 0 ) qDebug() << " pid" << getpid() << "looking for device" << (dev_t)mr.device << "inode" << (ino_t)mr.inode; qDebug() << " pid" << getpid() << "trying device" << keys_list[i].dev << "inode" << keys_list[i].ino; */ if ( keys_list[i].ino == (ino_t)mr.inode && keys_list[i].dev == (dev_t)mr.device ) { memcpy( result_ptr, keys_list[i].key, QSXE_KEY_LEN ); result_ptr += QSXE_KEY_LEN; foundKey = true; break; } } if ( foundKey ) { keysFound++; if ( keysFound == manifestMatchCount ) break; } } } } if ( result_ptr == result ) // nothing found! goto key_not_found; // 2 x magic bytes sentinel at end of sequence for ( int i = 0; i < 2; ++i ) for ( int j = 0; j < QSXE_MAGIC_BYTES; ++j ) *result_ptr++ = magic[j]; keyCache.insert( progId, result, total_size / 10 ); /* qDebug( "PID %d : Found %d client keys for prog %u", getpid(), keysFound, progId ); */ goto success_out;key_not_found: if ( noFailOnKeyMissing ) // return an "empty" set of keys in this case { if ( result == 0 ) { result = (char*)malloc( 2 * QSXE_MAGIC_BYTES ); Q_CHECK_PTR( result ); } result_ptr = result; for ( int i = 0; i < 2; ++i ) for ( int j = 0; j < QSXE_MAGIC_BYTES; ++j ) *result_ptr++ = magic[j]; return (unsigned char *)result; } qWarning( "PID %d : Not found client key for prog %u", getpid(), progId ); if ( result ) { free( result ); result = 0; }success_out: if ( mn.isOpen() ) mn.close(); if ( kf.isOpen() ) kf.close(); return (unsigned char *)result;}void QTransportAuthPrivate::invalidateClientKeyCache(){ keyfileMutex.lock(); keyCache.clear(); keyfileMutex.unlock();}//////////////////////////////////////////////////////////////////////////////// RequestAnalyzer definition////RequestAnalyzer::RequestAnalyzer()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -