Qt 4.8
qtransportauth_qws.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qtransportauth_qws.h"
43 #include "qtransportauth_qws_p.h"
44 
45 #ifndef QT_NO_SXE
46 
47 #include "../../3rdparty/md5/md5.h"
48 #include "../../3rdparty/md5/md5.cpp"
49 #include "qwsutils_qws.h"
50 #include "qwssocket_qws.h"
51 #include "qwscommand_qws_p.h"
52 #include "qwindowsystem_qws.h"
53 #include "qbuffer.h"
54 #include "qthread.h"
55 #include "qabstractsocket.h"
56 #include "qlibraryinfo.h"
57 #include "qfile.h"
58 #include "qdebug.h"
59 #include <private/qcore_unix_p.h> // overrides QT_OPEN
60 
61 #include <syslog.h>
62 #include <unistd.h>
63 #include <fcntl.h>
64 #include <sys/stat.h>
65 #include <sys/types.h>
66 #include <sys/socket.h>
67 #include <sys/file.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <errno.h>
71 #include <time.h>
72 
73 #include <QtCore/qcache.h>
74 
75 #define BUF_SIZE 512
76 
78 
84 Q_GUI_EXPORT void *guaranteed_memset(void *v,int c,size_t n)
85 {
86  volatile char *p = (char *)v; while (n--) *p++=c; return v;
87 }
88 
135 static int hmac_md5(
136  unsigned char* text, /* pointer to data stream */
137  int text_length, /* length of data stream */
138  const unsigned char* key, /* pointer to authentication key */
139  int key_length, /* length of authentication key */
140  unsigned char * digest /* caller digest to be filled in */
141  );
142 
143 
144 
145 #define KEY_CACHE_SIZE 30
146 
147 const char * const errorStrings[] = {
148  "pending identity verification",
149  "message too small to carry auth data",
150  "cache miss on connection oriented transport",
151  "no magic bytes on message",
152  "key not found for prog id",
153  "authorization key match failed",
154  "key out of date"
155 };
156 
157 const char *QTransportAuth::errorString( const Data &d )
158 {
159  if (( d.status & ErrMask ) == Success )
160  return "success";
161  int e = d.status & ErrMask;
162  if ( e > OutOfDate )
163  return "unknown";
164  return errorStrings[e];
165 }
166 
168  : m_success( false )
169  , m_reg( 0 )
170 {
171  if ( reg )
172  if ( !QMetaObject::invokeMethod( reg, "lockManifest", Q_RETURN_ARG(bool, m_success) ))
173  m_success = false;
174  m_reg = reg;
175 }
176 
178 {
179  if ( m_success )
180  QMetaObject::invokeMethod( m_reg, "unlockManifest" );
181 }
182 
183 
185  : keyInitialised(false)
186  , m_packageRegistry( 0 )
187 {
188 }
189 
191 {
192 }
193 
199 {
200  // qDebug( "creating transport auth" );
201 }
202 
208 {
209  // qDebug( "deleting transport auth" );
210 }
211 
218 void QTransportAuth::setProcessKey( const char *authdata )
219 {
221  ::memcpy(&d->authKey, authdata, sizeof(struct AuthCookie));
222  QFile proc_key( QLatin1String("/proc/self/lids_key") );
223  // where proc key exists use that instead
224  if ( proc_key.open( QIODevice::ReadOnly ))
225  {
226  qint64 kb = proc_key.read( (char*)&d->authKey.key, QSXE_KEY_LEN );
227 #ifdef QTRANSPORTAUTH_DEBUG
228  qDebug( "Using %li bytes of /proc/%i/lids_key\n", (long int)kb, getpid() );
229 #else
230  Q_UNUSED( kb );
231 #endif
232  }
233  d->keyInitialised = true;
234 }
235 
236 
244 void QTransportAuth::setProcessKey( const char *key, const char *prog )
245 {
246  Q_UNUSED(prog);
247  setProcessKey( key );
248 #ifdef QTRANSPORTAUTH_DEBUG
249  char displaybuf[QSXE_KEY_LEN*2+1];
250  hexstring( displaybuf, (const unsigned char *)key, QSXE_KEY_LEN );
251  qDebug() << "key" << displaybuf << "set";
252 #endif
253 }
254 
263 {
264  // not every policy receiver needs setup - no error if this fails
265  QMetaObject::invokeMethod( pr, "setupPolicyCheck" );
266 
269 }
270 
276 {
277  disconnect( pr );
278  // not every policy receiver needs tear down - no error if this fails
279  QMetaObject::invokeMethod( pr, "teardownPolicyCheck" );
280 }
281 
289 {
290  Data *data = new Data(properties, descriptor);
291  data->status = Pending;
292  return data;
293 }
294 
305 inline bool QTransportAuth::Data::trusted() const
306 {
307  return (bool)(properties & Trusted);
308 }
309 
320 inline void QTransportAuth::Data::setTrusted( bool t )
321 {
323 }
324 
342 {
343  return (bool)(properties & Connection);
344 }
345 
352 {
354 }
355 
360 {
361  static QTransportAuth theInstance;
362 
363  return &theInstance;
364 }
365 
376 {
378  d->m_keyFilePath = path;
379 }
380 
382 {
383  Q_D(const QTransportAuth);
384  return d->m_keyFilePath;
385 }
386 
388 {
390  d->m_logFilePath = path;
391 }
392 
394 {
395  Q_D(const QTransportAuth);
396  return d->m_logFilePath;
397 }
398 
400 {
402  d->m_packageRegistry = registry;
403 }
404 
406 {
407 #if defined(SXE_DISCOVERY)
408  static bool checked = false;
409  static bool yesItIs = false;
410 
411  if ( checked ) return yesItIs;
412 
413  yesItIs = ( getenv( "SXE_DISCOVERY_MODE" ) != 0 );
414  if ( yesItIs )
415  {
416  qWarning("SXE Discovery mode on, ALLOWING ALL requests and logging to %s",
419  }
420  checked = true;
421  return yesItIs;
422 #else
423  return false;
424 #endif
425 }
426 
436 {
437  Q_D(const QTransportAuth);
438 
439  if ( client == 0 ) return 0;
440  if ( d->buffersByClient.contains( client ))
441  {
442  return d->buffersByClient[client];
443  }
444  // qWarning( "buffer not found for client %p", client );
445  return 0;
446 }
447 
471 {
472  return new QAuthDevice( iod, data, QAuthDevice::Receive );
473 }
474 
494 {
495  return new QAuthDevice( iod, data, QAuthDevice::Send );
496 }
497 
498 const unsigned char *QTransportAuth::getClientKey( unsigned char progId )
499 {
501  return d->getClientKey( progId );
502 }
503 
505 {
507  d->invalidateClientKeyCache();
508 }
509 
511 {
513  return &d->keyfileMutex;
514 }
515 
516 /*
517  \internal
518  Respond to the destroyed(QObject*) signal of the QAuthDevice's
519  client object and remove it from the buffersByClient lookup hash.
520 */
522 {
524  if ( cli == NULL ) return;
525 
526  if ( d->buffersByClient.contains( cli ))
527  {
528  d->buffersByClient.remove( cli );
529  // qDebug( "@@@@@@@ client %p removed @@@@@@@@@", cli );
530  }
531  // qDebug( " client count %d", d->buffersByClient.count() );
532 }
533 
535 {
536  bool isAuthorized = true;
537 
538  if ( !request.isEmpty() && request != QLatin1String("Unknown") )
539  {
540  d.status &= QTransportAuth::ErrMask; // clear the status
541  emit policyCheck( d, request );
542  isAuthorized = (( d.status & QTransportAuth::StatusMask ) == QTransportAuth::Allow );
543  }
544 #if defined(SXE_DISCOVERY)
545  if (isDiscoveryMode()) {
546 #ifndef QT_NO_TEXTSTREAM
547  if (!logFilePath().isEmpty()) {
548  QFile log( logFilePath() );
550  qWarning("Could not write to log in discovery mode: %s",
552  } else {
553  QTextStream ts( &log );
554  ts << d.progId << '\t' << ( isAuthorized ? "Allow" : "Deny" ) << '\t' << request << endl;
555  }
556  }
557 #endif
558  isAuthorized = true;
559  }
560 #endif
561  if ( !isAuthorized )
562  {
563  qWarning( "%s - denied: for Program Id %u [PID %d]"
564  , qPrintable(request), d.progId, d.processId );
565 
566  char linkTarget[BUF_SIZE]="";
567  char exeLink[BUF_SIZE]="";
568  char cmdlinePath[BUF_SIZE]="";
569  char cmdline[BUF_SIZE]="";
570 
571  //get executable from /proc/pid/exe
572  snprintf( exeLink, BUF_SIZE, "/proc/%d/exe", d.processId );
573  if ( -1 == ::readlink( exeLink, linkTarget, BUF_SIZE - 1 ) )
574  {
575  qWarning( "SXE:- Error encountered in retrieving executable link target from /proc/%u/exe : %s",
576  d.processId, strerror(errno) );
577  snprintf( linkTarget, BUF_SIZE, "%s", linkTarget );
578  }
579 
580  //get cmdline from proc/pid/cmdline
581  snprintf( cmdlinePath, BUF_SIZE, "/proc/%d/cmdline", d.processId );
582  int cmdlineFd = QT_OPEN( cmdlinePath, O_RDONLY );
583  if ( cmdlineFd == -1 )
584  {
585  qWarning( "SXE:- Error encountered in opening /proc/%u/cmdline: %s",
586  d.processId, strerror(errno) );
587  snprintf( cmdline, BUF_SIZE, "%s", "Unknown" );
588  }
589  else
590  {
591  if ( -1 == QT_READ(cmdlineFd, cmdline, BUF_SIZE - 1 ) )
592  {
593  qWarning( "SXE:- Error encountered in reading /proc/%u/cmdline : %s",
594  d.processId, strerror(errno) );
595  snprintf( cmdline, BUF_SIZE, "%s", "Unknown" );
596  }
597  QT_CLOSE( cmdlineFd );
598  }
599 
600  syslog( LOG_ERR | LOG_LOCAL6, "%s // PID:%u // ProgId:%u // Exe:%s // Request:%s // Cmdline:%s",
601  "<SXE Breach>", d.processId, d.progId, linkTarget, qPrintable(request), cmdline);
602  }
603 
604  return isAuthorized;
605 }
606 
607 inline bool __fileOpen( QFile *f )
608 {
609 #ifdef QTRANSPORTAUTH_DEBUG
610  if ( f->open( QIODevice::ReadOnly ))
611  {
612  qDebug( "Opened file: %s\n", qPrintable( f->fileName() ));
613  return true;
614  }
615  else
616  {
617  qWarning( "Could not open file: %s\n", qPrintable( f->fileName() ));
618  return false;
619  }
620 #else
621  return ( f->open( QIODevice::ReadOnly ));
622 #endif
623 }
624 
658 const unsigned char *QTransportAuthPrivate::getClientKey(unsigned char progId)
659 {
660  int manifestMatchCount = 0;
661  struct IdBlock mr;
662  int total_size = 0;
663  char *result = 0;
664  char *result_ptr;
665  int keysFound = 0;
666  bool foundKey;
667  int keysRead = 0;
668  struct usr_key_entry keys_list[128];
669 
670  if ( keyCache.contains( progId ))
671  return (const unsigned char *)keyCache[progId];
672 
673  SxeRegistryLocker rlock( m_packageRegistry );
674 
675  // ### Qt 4.3: this is hacky - see documentation for setKeyFilePath
676  QString manifestPath = m_keyFilePath + QLatin1String("/manifest");
677  QString actualKeyPath = QLatin1String("/proc/lids/keys");
678  bool noFailOnKeyMissing = true;
679  if ( !QFile::exists( actualKeyPath )) {
680  actualKeyPath = m_keyFilePath + QLatin1String( "/" QSXE_KEYFILE );
681  }
682  QFile kf( actualKeyPath );
683  QFile mn( manifestPath );
684  if ( !__fileOpen( &mn ))
685  goto key_not_found;
686  // first find how much storage is needed
687  while ( mn.read( (char*)&mr, sizeof(struct IdBlock)) > 0 )
688  if ( mr.progId == progId )
689  manifestMatchCount++;
690  if ( manifestMatchCount == 0 )
691  goto key_not_found;
692  if ( !__fileOpen( &kf ))
693  {
694  noFailOnKeyMissing = false;
695  goto key_not_found;
696  }
697  total_size = 2 * QSXE_MAGIC_BYTES + manifestMatchCount * QSXE_KEY_LEN;
698  result = (char*)malloc( total_size );
699  Q_CHECK_PTR( result );
700  mn.seek( 0 );
701  result_ptr = result;
702  /* reading whole key array in is much more efficient, 99% case is this loop only
703  executes once, should not have more than 128 keyed items */
704  while (( keysRead = kf.read( (char*)keys_list, sizeof(struct usr_key_entry)*128 )) > 0 )
705  {
706  /* qDebug("PID %d: getClientKey() - read %d bytes = %d keys from %s", getpid(), keysRead,
707  keysRead/sizeof(struct usr_key_entry), qPrintable(actualKeyPath)); */
708  keysRead /= sizeof(struct usr_key_entry);
709  while ( mn.read( (char*)&mr, sizeof(struct IdBlock)) > 0 )
710  {
711  if ( mr.progId == progId )
712  {
713  foundKey = false;
714  for ( int i = 0; i < keysRead; ++i )
715  {
716  /* if ( i == 0 )
717  qDebug() << " pid" << getpid() << "looking for device" << (dev_t)mr.device << "inode" << (ino_t)mr.inode;
718  qDebug() << " pid" << getpid() << "trying device" << keys_list[i].dev << "inode" << keys_list[i].ino; */
719  if ( keys_list[i].ino == (ino_t)mr.inode && keys_list[i].dev == (dev_t)mr.device )
720  {
721  memcpy( result_ptr, keys_list[i].key, QSXE_KEY_LEN );
722  result_ptr += QSXE_KEY_LEN;
723  foundKey = true;
724  break;
725  }
726  }
727  if ( foundKey )
728  {
729  keysFound++;
730  if ( keysFound == manifestMatchCount )
731  break;
732  }
733  }
734  }
735  }
736  if ( result_ptr == result ) // nothing found!
737  goto key_not_found;
738  // 2 x magic bytes sentinel at end of sequence
739  for ( int i = 0; i < 2; ++i )
740  for ( int j = 0; j < QSXE_MAGIC_BYTES; ++j )
741  *result_ptr++ = magic[j];
742  keyCache.insert( progId, result, total_size / 10 );
743  /* qDebug( "PID %d : Found %d client keys for prog %u", getpid(), keysFound, progId ); */
744  goto success_out;
745 
746 key_not_found:
747  if ( noFailOnKeyMissing ) // return an "empty" set of keys in this case
748  {
749  if ( result == 0 )
750  {
751  result = (char*)malloc( 2 * QSXE_MAGIC_BYTES );
752  Q_CHECK_PTR( result );
753  }
754  result_ptr = result;
755  for ( int i = 0; i < 2; ++i )
756  for ( int j = 0; j < QSXE_MAGIC_BYTES; ++j )
757  *result_ptr++ = magic[j];
758  return (unsigned char *)result;
759  }
760  qWarning( "PID %d : Not found client key for prog %u", getpid(), progId );
761  if ( result )
762  {
763  free( result );
764  result = 0;
765  }
766 success_out:
767  if ( mn.isOpen() )
768  mn.close();
769  if ( kf.isOpen() )
770  kf.close();
771  return (unsigned char *)result;
772 }
773 
775 {
776  keyfileMutex.lock();
777  keyCache.clear();
778  keyfileMutex.unlock();
779 }
780 
785 
786 
788  : moreData( false )
789  , dataSize( 0 )
790 {
791 }
792 
794 {
795 }
796 
820 {
821 #ifdef Q_WS_QWS
822  dataSize = 0;
823  moreData = false;
824  QBuffer cmdBuf( msgQueue );
826  QWSCommand::Type command_type = (QWSCommand::Type)(qws_read_uint( &cmdBuf ));
827  QWSCommand *command = QWSCommand::factory(command_type);
828  // if NULL, factory will have already printed warning for bogus
829  // command_type just purge the bad stuff and attempt to recover
830  if ( command == NULL )
831  {
832  *msgQueue = msgQueue->mid( sizeof(int) );
833  return QString();
834  }
835  QString request = QLatin1String(qws_getCommandTypeString(command_type));
836 #ifndef QT_NO_COP
837  if ( !command->read( &cmdBuf ))
838  {
839  // not all command arrived yet - come back later
840  delete command;
841  moreData = true;
842  return QString();
843  }
844  if ( command_type == QWSCommand::QCopSend )
845  {
846  QWSQCopSendCommand *sendCommand = static_cast<QWSQCopSendCommand*>(command);
847  request += QString::fromLatin1("/QCop/%1/%2").arg( sendCommand->channel ).arg( sendCommand->message );
848  }
849  if ( command_type == QWSCommand::QCopRegisterChannel )
850  {
851  QWSQCopRegisterChannelCommand *registerCommand = static_cast<QWSQCopRegisterChannelCommand*>(command);
852  request += QString::fromLatin1("/QCop/RegisterChannel/%1").arg( registerCommand->channel );
853  }
854 #endif
855  dataSize = QWS_PROTOCOL_ITEM_SIZE( *command );
856  delete command;
857  return request;
858 #else
859  Q_UNUSED(msgQueue);
860  return QString();
861 #endif
862 }
863 
868 
878  : QIODevice( parent )
879  , d( data )
880  , way( dir )
881  , m_target( parent )
882  , m_client( 0 )
883  , m_bytesAvailable( 0 )
884  , m_skipWritten( 0 )
885  , analyzer( 0 )
886 {
887  if ( dir == Receive ) // server side
888  {
890  this, SLOT(recvReadyRead()));
891  } else {
893  this, SIGNAL(readyRead()));
894  }
896  this, SLOT(targetBytesWritten(qint64)) );
898 }
899 
901 {
902  if ( analyzer )
903  delete analyzer;
904  delete d;
905 }
906 
913 {
914  m_client = cli;
915  QTransportAuth::getInstance()->d_func()->buffersByClient[cli] = this;
917  QTransportAuth::getInstance(), SLOT(bufferDestroyed(QObject*)) );
918  // qDebug( "@@@@@@@@@@@@ client set %p @@@@@@@@@", cli );
919  // qDebug( " client count %d", QTransportAuth::getInstance()->d_func()->buffersByClient.count() );
920 }
921 
923 {
924  return m_client;
925 }
926 
927 /*
928  \fn void QAuthDevice::authViolation(QTransportAuth::Data &)
929 
930  This signal is emitted if an authorization failure is generated, as
931  described in checkAuth();
932 
933  \sa checkAuth()
934 */
935 
936 
937 /*
938  \fn void QAuthDevice::policyCheck(QTransportAuth::Data &transport, const QString &request )
939 
940  This signal is emitted when a transport successfully delivers a request
941  and gives the opportunity to either deny or accept the request.
942 
943  This signal must be connected in the same thread, ie it cannot be queued.
944 
945  As soon as all handlers connected to this signal are processed the Allow or
946  Deny state on the \a transport is checked, and the request is allowed or denied
947  accordingly.
948 
949  \sa checkAuth()
950 */
951 
967 {
968  if ( way == Receive ) // server
969  return m_target->write( data, len );
970  // client
971 #ifdef QTRANSPORTAUTH_DEBUG
972  char displaybuf[1024];
973 #endif
974  char header[QSXE_HEADER_LEN];
975  ::memset( header, 0, QSXE_HEADER_LEN );
976  qint64 bytes = 0;
977  if ( QTransportAuth::getInstance()->authToMessage( *d, header, data, len ))
978  {
979  m_target->write( header, QSXE_HEADER_LEN );
980 #ifdef QTRANSPORTAUTH_DEBUG
981  hexstring( displaybuf, (const unsigned char *)header, QSXE_HEADER_LEN );
982  qDebug( "%d QAuthDevice::writeData - CLIENT: Header written: %s", getpid(), displaybuf );
983 #endif
985  }
986  m_target->write( data, len );
987  bytes += len;
988 #ifdef QTRANSPORTAUTH_DEBUG
989  int bytesToDisplay = bytes;
990  const unsigned char *dataptr = (const unsigned char *)data;
991  while ( bytesToDisplay > 0 )
992  {
993  int amt = bytes < 500 ? bytes : 500;
994  hexstring( displaybuf, dataptr, amt );
995  qDebug( "%d QAuthDevice::writeData - CLIENT: %s", getpid(), bytes > 0 ? displaybuf : "(null)" );
996  dataptr += 500;
997  bytesToDisplay -= 500;
998  }
999 #endif
1000  if ( m_target->inherits( "QAbstractSocket" ))
1001  static_cast<QAbstractSocket*>(m_target)->flush();
1002  return bytes;
1003 }
1004 
1014 {
1015  if ( way == Send ) // client
1016  return m_target->read( data, maxSize );
1017  if ( msgQueue.size() == 0 )
1018  return 0;
1019 #ifdef QTRANSPORTAUTH_DEBUG
1020  char displaybuf[1024];
1021  hexstring( displaybuf, reinterpret_cast<const unsigned char *>(msgQueue.constData()),
1022  msgQueue.size() > 500 ? 500 : msgQueue.size() );
1023  qDebug() << getpid() << "QAuthDevice::readData() buffered/requested/avail"
1024  << msgQueue.size() << maxSize << m_bytesAvailable << displaybuf;
1025 #endif
1027  qint64 bytes = ( maxSize > m_bytesAvailable ) ? m_bytesAvailable : maxSize;
1028  ::memcpy( data, msgQueue.constData(), bytes );
1029  msgQueue = msgQueue.mid( bytes );
1030  m_bytesAvailable -= bytes;
1031  return bytes;
1032 }
1033 
1052 {
1053  qint64 bytes = m_target->bytesAvailable();
1054  if ( bytes <= 0 ) return;
1056  QUnixSocket *usock = static_cast<QUnixSocket*>(m_target);
1057  QUnixSocketMessage msg = usock->read();
1058  msgQueue.append( msg.bytes() );
1059  d->processId = msg.processId();
1060  // if "fragmented" packet 1/2 way through start of a command, ie
1061  // in the QWS msg type, cant do anything, come back later when
1062  // there's more of the packet
1063  if ( msgQueue.size() < (int)sizeof(int) )
1064  {
1065  // qDebug() << "returning: msg size too small" << msgQueue.size();
1066  return;
1067  }
1068 #ifdef QTRANSPORTAUTH_DEBUG
1069  char displaybuf[1024];
1070  hexstring( displaybuf, reinterpret_cast<const unsigned char *>(msgQueue.constData()),
1071  msgQueue.size() > 500 ? 500 : msgQueue.size() );
1072  qDebug( "%d ***** SERVER read %lli bytes - msg %s", getpid(), bytes, displaybuf );
1073 #endif
1074 
1075  bool bufHasMessages = msgQueue.size() >= (int)sizeof(int);
1076  while ( bufHasMessages )
1077  {
1078  unsigned char saveStatus = d->status;
1080  {
1082  break;
1083  }
1084  if ( !QTransportAuth::getInstance()->authFromMessage( *d, msgQueue, msgQueue.size() ))
1085  {
1086  // not all arrived yet? come back later
1088  {
1089  d->status = saveStatus;
1090  return;
1091  }
1092  }
1094  {
1095  // no msg auth header, don't change the success status for connections
1096  if ( d->connection() )
1097  d->status = saveStatus;
1098  }
1099  else
1100  {
1101  // msg auth header detected and auth determined, remove hdr
1103  }
1104  if ( !authorizeMessage() )
1105  break;
1106  bufHasMessages = msgQueue.size() >= (int)sizeof(int);
1107  }
1108 }
1109 
1116 {
1117  if ( m_skipWritten >= bytes ) {
1118  m_skipWritten -= bytes;
1119  bytes = 0;
1120  } else if ( m_skipWritten > 0 ) {
1121  bytes -= m_skipWritten;
1122  m_skipWritten = 0;
1123  }
1124  if ( bytes > 0 ) {
1125  emit bytesWritten( bytes );
1126  }
1127 }
1128 
1141 {
1142  if ( analyzer == NULL )
1143  analyzer = new RequestAnalyzer();
1144  QString request = (*analyzer)( &msgQueue );
1145  if ( analyzer->requireMoreData() )
1146  return false;
1147  bool isAuthorized = true;
1148 
1149  if ( !request.isEmpty() && request != QLatin1String("Unknown") )
1150  {
1151  isAuthorized = QTransportAuth::getInstance()->authorizeRequest( *d, request );
1152  }
1153 
1154  bool moreToProcess = ( msgQueue.size() - analyzer->bytesAnalyzed() ) > (int)sizeof(int);
1155  if ( isAuthorized )
1156  {
1157 #ifdef QTRANSPORTAUTH_DEBUG
1158  qDebug() << getpid() << "SERVER authorized: releasing" << analyzer->bytesAnalyzed() << "byte command" << request;
1159 #endif
1162  return moreToProcess;
1163  }
1164  else
1165  {
1167  }
1168 
1169  return true;
1170 }
1171 
1173 {
1174  Q_ASSERT( ra );
1175  if ( analyzer )
1176  delete analyzer;
1177  analyzer = ra;
1178 }
1179 
1199 bool QTransportAuth::authToMessage( QTransportAuth::Data &d, char *hdr, const char *msg, int msgLen )
1200 {
1201  // qDebug( "authToMessage(): prog id %u", d.progId );
1202  // only authorize connection oriented transports once, unless key has changed
1204  d_func()->authKey.progId == d.progId )
1205  return false;
1206  d.progId = d_func()->authKey.progId;
1207  // If Unix socket credentials are being used the key wont be set
1208  if ( !d_func()->keyInitialised )
1209  return false;
1210  unsigned char digest[QSXE_KEY_LEN];
1211  char *msgPtr = hdr;
1212  // magic always goes on the beginning
1213  for ( int m = 0; m < QSXE_MAGIC_BYTES; ++m )
1214  *msgPtr++ = magic[m];
1215  hdr[ QSXE_LEN_IDX ] = (unsigned char)msgLen;
1216  if ( !d.trusted())
1217  {
1218  // Use HMAC
1219  int rc = hmac_md5( (unsigned char *)msg, msgLen, d_func()->authKey.key, QSXE_KEY_LEN, digest );
1220  if ( rc == -1 )
1221  return false;
1222  memcpy( hdr + QSXE_KEY_IDX, digest, QSXE_KEY_LEN );
1223  }
1224  else
1225  {
1226  memcpy( hdr + QSXE_KEY_IDX, d_func()->authKey.key, QSXE_KEY_LEN );
1227  }
1228 
1229  hdr[ QSXE_PROG_IDX ] = d_func()->authKey.progId;
1230 
1231 #ifdef QTRANSPORTAUTH_DEBUG
1232  char keydisplay[QSXE_KEY_LEN*2+1];
1233  hexstring( keydisplay, d_func()->authKey.key, QSXE_KEY_LEN );
1234 
1235  qDebug( "%d CLIENT Auth to message %s against prog id %u and key %s\n",
1236  getpid(), msg, d_func()->authKey.progId, keydisplay );
1237 #endif
1238 
1239  // TODO implement sequence to prevent replay attack, not required
1240  // for trusted transports
1241  hdr[ QSXE_SEQ_IDX ] = 1; // dummy sequence
1242 
1244  return true;
1245 }
1246 
1247 
1294 bool QTransportAuth::authFromMessage( QTransportAuth::Data &d, const char *msg, int msgLen )
1295 {
1296  if ( msgLen < QSXE_MAGIC_BYTES )
1297  {
1299  return false;
1300  }
1301  // if no magic bytes, exit straight away
1302  int m;
1303  const unsigned char *mptr = reinterpret_cast<const unsigned char *>(msg);
1304  for ( m = 0; m < QSXE_MAGIC_BYTES; ++m )
1305  {
1306  if ( *mptr++ != magic[m] )
1307  {
1309  return false;
1310  }
1311  }
1312 
1313  if ( msgLen < AUTH_SPACE(1) )
1314  {
1316  return false;
1317  }
1318 
1319  // At this point we know the header is at least long enough to contain valid auth
1320  // data, however the data may be spoofed. If it is not verified then the status will
1321  // be set to uncertified so the spoofed data will not be relied on. However we want to
1322  // know the program id which is being reported (even if it might be spoofed) for
1323  // policy debugging purposes. So set it here, rather than after verification.
1324  d.progId = msg[QSXE_PROG_IDX];
1325 
1326 #ifdef QTRANSPORTAUTH_DEBUG
1327  char authhdr[QSXE_HEADER_LEN*2+1];
1328  hexstring( authhdr, reinterpret_cast<const unsigned char *>(msg), QSXE_HEADER_LEN );
1329  qDebug( "%d SERVER authFromMessage(): message header is %s",
1330  getpid(), authhdr );
1331 #endif
1332 
1333  unsigned char authLen = (unsigned char)(msg[ QSXE_LEN_IDX ]);
1334 
1335  if ( msgLen < AUTH_SPACE(authLen) )
1336  {
1338  return false;
1339  }
1340 
1341  bool isCached = d_func()->keyCache.contains( d.progId );
1342  const unsigned char *clientKey = d_func()->getClientKey( d.progId );
1343  if ( clientKey == NULL )
1344  {
1346  return false;
1347  }
1348 
1349 #ifdef QTRANSPORTAUTH_DEBUG
1350  char keydisplay[QSXE_KEY_LEN*2+1];
1351  hexstring( keydisplay, clientKey, QSXE_KEY_LEN );
1352  qDebug( "\t\tauthFromMessage(): message %s against prog id %u and key %s\n",
1353  AUTH_DATA(msg), ((unsigned int)d.progId), keydisplay );
1354 #endif
1355 
1356  const unsigned char *auth_tok;
1357  unsigned char digest[QSXE_KEY_LEN];
1358  bool multi_tok = false;
1359 
1360  bool need_to_recheck=false;
1361  do
1362  {
1363  if ( !d.trusted())
1364  {
1365  hmac_md5( AUTH_DATA(msg), authLen, clientKey, QSXE_KEY_LEN, digest );
1366  auth_tok = digest;
1367  }
1368  else
1369  {
1370  auth_tok = clientKey;
1371  multi_tok = true; // 1 or more keys are in the clientKey
1372  }
1373  while( true )
1374  {
1375  if ( memcmp( auth_tok, magic, QSXE_MAGIC_BYTES ) == 0
1376  && memcmp( auth_tok + QSXE_MAGIC_BYTES, magic, QSXE_MAGIC_BYTES ) == 0 )
1377  break;
1378  if ( memcmp( msg + QSXE_KEY_IDX, auth_tok, QSXE_KEY_LEN ) == 0 )
1379  {
1381  return true;
1382  }
1383  if ( !multi_tok )
1384  break;
1385  auth_tok += QSXE_KEY_LEN;
1386  }
1387  //the keys cached on d.progId may not contain the binary key because the cache entry was made
1388  //before the binary had first started, must search for client key again.
1389  if ( isCached )
1390  {
1391  d_func()->keyCache.remove(d.progId);
1392  isCached = false;
1393 
1394 #ifdef QTRANSPORTAUTH_DEBUG
1395  qDebug() << "QTransportAuth::authFromMessage(): key not found in set of keys cached"
1396  << "against prog Id =" << d.progId << ". Re-obtaining client key. ";
1397 #endif
1398  clientKey = d_func()->getClientKey( d.progId );
1399  if ( clientKey == NULL )
1400  {
1402  return false;
1403  }
1404  need_to_recheck = true;
1405  }
1406  else
1407  {
1408  need_to_recheck = false;
1409  }
1410  } while( need_to_recheck );
1411 
1413  qWarning() << "QTransportAuth::authFromMessage():failed authentication";
1415  emit authViolation( d );
1416  return false;
1417 }
1418 
1419 
1420 #ifdef QTRANSPORTAUTH_DEBUG
1421 
1426 void hexstring( char *buf, const unsigned char* key, size_t key_len )
1427 {
1428  unsigned int i, p;
1429  for ( i = 0, p = 0; i < key_len; i++, p+=2 )
1430  {
1431  unsigned char lo_nibble = key[i] & 0x0f;
1432  unsigned char hi_nibble = key[i] >> 4;
1433  buf[p] = (int)hi_nibble > 9 ? hi_nibble-10 + 'A' : hi_nibble + '0';
1434  buf[p+1] = (int)lo_nibble > 9 ? lo_nibble-10 + 'A' : lo_nibble + '0';
1435  }
1436  buf[p] = '\0';
1437 }
1438 #endif
1439 
1440 /*
1441  HMAC MD5 as listed in RFC 2104
1442 
1443  This code is taken from:
1444 
1445  http://www.faqs.org/rfcs/rfc2104.html
1446 
1447  with the allowance for keys other than length 16 removed, but otherwise
1448  a straight cut-and-paste.
1449 
1450  The HMAC_MD5 transform looks like:
1451 
1452  \snippet doc/src/snippets/code/src.gui.embedded.qtransportauth_qws.cpp 5
1453 
1454  \list
1455  <li> where K is an n byte key
1456  <li> ipad is the byte 0x36 repeated 64 times
1457  <li> opad is the byte 0x5c repeated 64 times
1458  <li> and text is the data being protected
1459  \endlist
1460 
1461  Hardware is available with accelerated implementations of HMAC-MD5 and
1462  HMAC-SHA1. Where this hardware is available, this routine should be
1463  replaced with a call into the accelerated version.
1464 */
1465 
1466 static int hmac_md5(
1467  unsigned char* text, /* pointer to data stream */
1468  int text_length, /* length of data stream */
1469  const unsigned char* key, /* pointer to authentication key */
1470  int key_length, /* length of authentication key */
1471  unsigned char * digest /* caller digest to be filled in */
1472  )
1473 {
1474  MD5Context context;
1475  unsigned char k_ipad[65]; /* inner padding - * key XORd with ipad */
1476  unsigned char k_opad[65]; /* outer padding - * key XORd with opad */
1477  int i;
1478 
1479  /* in this implementation key_length == 16 */
1480  if ( key_length != 16 )
1481  {
1482  fprintf( stderr, "Key length was %d - must be 16 bytes", key_length );
1483  return 0;
1484  }
1485 
1486  /* start out by storing key in pads */
1487  memset( k_ipad, 0, sizeof k_ipad );
1488  memset( k_opad, 0, sizeof k_opad );
1489  memcpy( k_ipad, key, key_length );
1490  memcpy( k_opad, key, key_length );
1491 
1492  /* XOR key with ipad and opad values */
1493  for (i=0; i<64; i++) {
1494  k_ipad[i] ^= 0x36;
1495  k_opad[i] ^= 0x5c;
1496  }
1497 
1498  /* perform inner MD5 */
1499  MD5Init(&context); /* init context for 1st pass */
1500  MD5Update(&context, k_ipad, 64); /* start with inner pad */
1501  MD5Update(&context, text, text_length); /* then text of datagram */
1502  MD5Final(&context, digest); /* finish up 1st pass */
1503 
1504  /* perform outer MD5 */
1505  MD5Init(&context); /* init context for 2nd pass */
1506  MD5Update(&context, k_opad, 64); /* start with outer pad */
1507  MD5Update(&context, digest, 16); /* then results of 1st * hash */
1508  MD5Final(&context, digest); /* finish up 2nd pass */
1509  return 1;
1510 }
1511 
1512 
1513 const int FAREnforcer::minutelyRate = 4; //allowed number of false authentication attempts per minute
1514 const QString FAREnforcer::FARMessage = QLatin1String("FAR_Exceeded");
1515 const QString FAREnforcer::SxeTag = QLatin1String("<SXE Breach>");
1516 const int FAREnforcer::minute = 60;
1517 
1519 {
1520  QDateTime nullDateTime = QDateTime();
1521  for (int i = 0; i < minutelyRate; i++ )
1522  authAttempts << nullDateTime;
1523 }
1524 
1525 
1527 {
1528  static FAREnforcer theInstance;
1529  return &theInstance;
1530 }
1531 
1533 {
1535 
1536  authAttempts.append( time );
1537  if ( dt.secsTo( authAttempts.last() ) <= minute )
1538  {
1539 #if defined(SXE_DISCOVERY)
1541  static QBasicAtomicInt reported = Q_BASIC_ATOMIC_INITIALIZER(0);
1542  if ( reported.testAndSetRelaxed(0,1) ) {
1543 #ifndef QT_NO_TEXTSTREAM
1544  QString logFilePath = QTransportAuth::getInstance()->logFilePath();
1545  if ( !logFilePath.isEmpty() ) {
1546  QFile log( logFilePath );
1548  qWarning("Could not write to log in discovery mode: %s",
1549  qPrintable(logFilePath) );
1550  } else {
1551  QTextStream ts( &log );
1552  ts << "\t\tWarning: False Authentication Rate of " << minutelyRate << "\n"
1553  << "\t\tserver connections/authentications per minute has been exceeded,\n"
1554  << "\t\tno further warnings will be issued\n";
1555  }
1556  }
1557  }
1558 #endif
1559  reset();
1560  return;
1561  }
1562 #endif
1563  syslog( LOG_ERR | LOG_LOCAL6, "%s %s",
1564  qPrintable( FAREnforcer::SxeTag ),
1565  qPrintable( FAREnforcer::FARMessage ) );
1566  reset();
1567  }
1568 }
1569 
1571 {
1572  QDateTime nullDateTime = QDateTime();
1573  for (int i = 0; i < minutelyRate; i++ )
1574  authAttempts[i] = nullDateTime;
1575 }
1576 
1578 
1579 #include "moc_qtransportauth_qws_p.cpp"
1580 
1581 #endif // QT_NO_SXE
bool authFromMessage(QTransportAuth::Data &d, const char *msg, int msgLen)
Check authorization on the msg, which must be of size msgLen, for the transport d.
#define BUF_SIZE
double d
Definition: qnumeric_p.h:62
QString fileName() const
Returns the name set by setFileName() or to the QFile constructors.
Definition: qfile.cpp:470
QTransportAuth::Data * d
const unsigned char magic[QSXE_MAGIC_BYTES]
void setTrusted(bool)
Assert that the transport is trusted.
void setRequestAnalyzer(RequestAnalyzer *)
qint64 bytesAnalyzed() const
qint64 writeData(const char *, qint64)
Reimplement QIODevice writeData method.
unsigned char c[8]
Definition: qnumeric_p.h:62
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
bool __fileOpen(QFile *f)
bool authorizeRequest(QTransportAuth::Data &d, const QString &request)
The QUnixSocket class provides a Unix domain socket.
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
QAuthDevice * authBuf(QTransportAuth::Data *, QIODevice *)
Return a QIODevice pointer (to an internal QBuffer) which can be used to write data onto...
qint64 read(char *data, qint64 maxSize)
#define QSXE_KEY_IDX
static QWSCommand * factory(int type)
bool open(OpenMode flags)
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition: qfile.cpp:1064
QByteArray & append(char c)
Appends the character ch to this byte array.
void policyCheck(QTransportAuth::Data &, const QString &)
virtual QString analyze(QByteArray *)
Analzye the data in themsgQueue according to some protocol and produce a request string for policy an...
const char *const errorStrings[]
bool open(OpenMode openMode)
Reimplemented Function
Definition: qbuffer.cpp:338
QTransportAuth::Data * connectTransport(unsigned char, int)
Record a new transport connection with properties and descriptor.
#define Q_GUI_EXPORT
Definition: qglobal.h:1450
QObject * client() const
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void setPackageRegistry(QObject *registry)
static const char * errorString(const QTransportAuth::Data &)
#define SLOT(a)
Definition: qobjectdefs.h:226
#define O_RDONLY
#define AUTH_SPACE(x)
AuthDirection way
Pass-through QIODevice sub-class for authentication.
Data record for the manifest file.
static const QString SxeTag
int qws_read_uint(QIODevice *socket)
Definition: qwsutils_qws.h:73
Q_GUI_EXPORT void * guaranteed_memset(void *v, int c, size_t n)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
#define QSXE_KEY_LEN
void bytesWritten(qint64 bytes)
This signal is emitted every time a payload of data has been written to the device.
The QBuffer class provides a QIODevice interface for a QByteArray.
Definition: qbuffer.h:57
The QString class provides a Unicode character string.
Definition: qstring.h:83
const unsigned char * getClientKey(unsigned char progId)
Find client keys for the progId.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_BASIC_ATOMIC_INITIALIZER(a)
Definition: qbasicatomic.h:218
#define Q_D(Class)
Definition: qglobal.h:2482
void targetBytesWritten(qint64)
void registerPolicyReceiver(QObject *)
Register pr as a policy handler object.
#define QSXE_PROG_IDX
QList< QDateTime > authAttempts
#define QT_READ
Definition: qcore_unix_p.h:280
QIODevice * m_target
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
Definition: qiodevice.cpp:791
bool exists() const
Returns true if the file specified by fileName() exists; otherwise returns false. ...
Definition: qfile.cpp:626
Q_CORE_EXPORT void qDebug(const char *,...)
#define SIGNAL(a)
Definition: qobjectdefs.h:227
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
bool trusted() const
Is the transport trusted.
#define QSXE_KEYFILE
bool testAndSetRelaxed(int expectedValue, int newValue)
#define AUTH_DATA(x)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
#define QSXE_SEQ_IDX
bool isOpen() const
Returns true if the device is open; otherwise returns false.
Definition: qiodevice.cpp:530
void destroyed(QObject *=0)
This signal is emitted immediately before the object obj is destroyed, and can not be blocked...
static FAREnforcer * getInstance()
RequestAnalyzer * analyzer
QObject * m_client
QByteArray msgQueue
bool read(QIODevice *s)
T takeFirst()
Removes the first item in the list and returns it.
Definition: qlist.h:489
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
static const int minutelyRate
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
This comes from the SXE kernel patch file include/linux/lidsif.
#define emit
Definition: qobjectdefs.h:76
int secsTo(const QDateTime &) const
Returns the number of seconds from this datetime to the other datetime.
Definition: qdatetime.cpp:2914
Q_CORE_EXPORT void qWarning(const char *,...)
static const QString FARMessage
static const char * data(const QByteArray &arr)
#define Q_RETURN_ARG(type, data)
Definition: qobjectdefs.h:247
void logAuthAttempt(QDateTime time=QDateTime::currentDateTime())
__int64 qint64
Definition: qglobal.h:942
QAuthDevice * recvBuf(QTransportAuth::Data *, QIODevice *)
Return a QIODevice pointer (to an internal QBuffer) which can be used to receive data after authoriza...
QByteArray mid(int index, int len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos...
#define QSXE_LEN_IDX
bool inherits(const char *classname) const
Returns true if this object is an instance of a class that inherits className or a QObject subclass t...
Definition: qobject.h:275
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
Disconnects signal in object sender from method in object receiver.
Definition: qobject.cpp:2895
Enforces the False Authentication Rate.
#define Q_CHECK_PTR(p)
Definition: qglobal.h:1853
void setProcessKey(const char *)
Set the process key for this currently running Qt Extended process to the authdata.
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
bool authToMessage(QTransportAuth::Data &d, char *hdr, const char *msg, int msgLen)
Add authentication header to the beginning of a message.
#define QT_OPEN
Definition: qcore_unix_p.h:186
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
void recvReadyRead()
Receive readyRead signal from the target recv device.
#define QWS_PROTOCOL_ITEM_SIZE(item)
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:73
pid_t processId() const
Returns the process id credential associated with this message.
QAuthDevice(QIODevice *, QTransportAuth::Data *, AuthDirection)
Constructs a new auth device for the transport data and I/O device parent.
#define QSXE_HEADER_LEN
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
QString logFilePath() const
void setConnection(bool)
Assert that the transport is connection oriented.
friend class QAuthDevice
void setKeyFilePath(const QString &)
Set the full path to the key file.
void unregisterPolicyReceiver(QObject *)
Unregister the pr from being a policy handler.
static const int minute
int key
T & last()
Returns a reference to the last item in the list.
Definition: qlist.h:284
virtual qint64 bytesAvailable() const
Returns the number of bytes that are available for reading.
Definition: qiodevice.cpp:752
static QDateTime currentDateTime()
Returns the current datetime, as reported by the system clock, in the local time zone.
Definition: qdatetime.cpp:3138
void setClient(QObject *)
#define QSXE_MAGIC_BYTES
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
static const QCssKnownValue properties[NumProperties - 1]
Definition: qcssparser.cpp:67
QString keyFilePath() const
void bufferDestroyed(QObject *)
virtual bool open(OpenMode mode)
Opens the device and sets its OpenMode to mode.
Definition: qiodevice.cpp:570
const char * qws_getCommandTypeString(QWSCommand::Type tp)
bool remove()
Removes the file specified by fileName().
Definition: qfile.cpp:715
ino_t ino
bool connection() const
Is the transport connection oriented.
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(0), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
Invokes the member (a signal or a slot name) on the object obj.
const QByteArray & bytes() const
Return the data portion of the message.
Authenticate a message transport.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
void readyRead()
This signal is emitted once every time new data is available for reading from the device...
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
QIODevice * passThroughByClient(QWSClient *) const
virtual void close()
Calls QFile::flush() and closes the file.
Definition: qfile.cpp:1680
const unsigned char * getClientKey(unsigned char progId)
#define qPrintable(string)
Definition: qglobal.h:1750
bool seek(qint64 offset)
For random-access devices, this function sets the current position to pos, returning true on success...
Definition: qfile.cpp:1784
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
The QWSClient class encapsulates a client process in Qt for Embedded Linux.
QMutex * getKeyFileMutex()
void setLogFilePath(const QString &)
static int hmac_md5(unsigned char *text, int text_length, const unsigned char *key, int key_length, unsigned char *digest)
The QUnixSocketMessage class encapsulates a message sent or received through the QUnixSocket class...
Definition: qunixsocket_p.h:92
qint64 readData(char *, qint64)
Reimplement from QIODevice.
#define text
Definition: qobjectdefs.h:80
static QTransportAuth * getInstance()
Return a pointer to the instance of this process&#39;s QTransportAuth object.
int errno
#define QT_CLOSE
Definition: qcore_unix_p.h:304
bool isDiscoveryMode() const
Q_CORE_EXPORT QTextStream & endl(QTextStream &s)
bool requireMoreData() const