author | zecke <zecke> | 2002-07-12 13:51:37 (UTC) |
---|---|---|
committer | zecke <zecke> | 2002-07-12 13:51:37 (UTC) |
commit | 716211b5e06bb25145cfbcf62a11a7c52c79dde5 (patch) (side-by-side diff) | |
tree | 595c4c15cb0ca31f2579be42ee029c1c30454b9c | |
parent | 7c12000481b535ce54951ef8a53b439814f8fcd6 (diff) | |
download | opie-716211b5e06bb25145cfbcf62a11a7c52c79dde5.zip opie-716211b5e06bb25145cfbcf62a11a7c52c79dde5.tar.gz opie-716211b5e06bb25145cfbcf62a11a7c52c79dde5.tar.bz2 |
Security fix by trolltech
-rw-r--r-- | core/launcher/desktop.cpp | 4 | ||||
-rw-r--r-- | core/launcher/launcher.pro | 2 | ||||
-rw-r--r-- | core/launcher/qcopbridge.cpp | 424 | ||||
-rw-r--r-- | core/launcher/qcopbridge.h | 7 | ||||
-rw-r--r-- | core/launcher/transferserver.cpp | 213 | ||||
-rw-r--r-- | core/launcher/transferserver.h | 23 |
6 files changed, 392 insertions, 281 deletions
diff --git a/core/launcher/desktop.cpp b/core/launcher/desktop.cpp index 24dce73..541b4be 100644 --- a/core/launcher/desktop.cpp +++ b/core/launcher/desktop.cpp @@ -563,14 +563,14 @@ void Desktop::execAutoStart() { delay = (cfg.readEntry("Delay", "0" )).toInt(); // If the time between suspend and resume was longer then the // value saved as delay, start the app if ( suspendTime.secsTo(now) >= (delay*60) ) { QCopEnvelope e("QPE/System", "execute(QString)"); e << QString(appName); - } else { - } + } //else { + //} } #if defined(QPE_HAVE_TOGGLELIGHT) #include <qpe/config.h> #include <sys/ioctl.h> diff --git a/core/launcher/launcher.pro b/core/launcher/launcher.pro index ccf8231..169edc1 100644 --- a/core/launcher/launcher.pro +++ b/core/launcher/launcher.pro @@ -96,13 +96,13 @@ INCLUDEPATH += $(OPIEDIR)/include DEPENDPATH += $(OPIEDIR)/include . INCLUDEPATH += $(OPIEDIR)/core/apps/calibrate DEPENDPATH += $(OPIEDIR)/core/apps/calibrate INCLUDEPATH += $(OPIEDIR)/rsync DEPENDPATH += $(OPIEDIR)/rsync TARGET = qpe -LIBS += -lqpe -lcrypt -lopie +LIBS += -lqpe -lcrypt -lopie -luuid TRANSLATIONS = ../../i18n/de/qpe.ts \ ../../i18n/en/qpe.ts \ ../../i18n/es/qpe.ts \ ../../i18n/fr/qpe.ts \ ../../i18n/hu/qpe.ts \ diff --git a/core/launcher/qcopbridge.cpp b/core/launcher/qcopbridge.cpp index 2d084fc..85993ee 100644 --- a/core/launcher/qcopbridge.cpp +++ b/core/launcher/qcopbridge.cpp @@ -1,10 +1,10 @@ /********************************************************************** -** Copyright (C) 2000 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** -** This file is part of Qtopia Environment. +** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** @@ -18,190 +18,222 @@ ** **********************************************************************/ #include "qcopbridge.h" #include "transferserver.h" +#ifdef QWS #include <qpe/qcopenvelope_qws.h> +#endif #include <qpe/qpeapplication.h> +#include <qpe/version.h> #include <qdir.h> #include <qfile.h> #include <qtextstream.h> #include <qdatastream.h> #include <qstringlist.h> #include <qfileinfo.h> #include <qregexp.h> +#ifdef QWS #include <qcopchannel_qws.h> +#endif -// actually this is wrong, _XOPEN_SOURCE should get defined on the commandline -// and it should have a proper value assigned. (Simon) -#if !defined(_XOPEN_SOURCE) #define _XOPEN_SOURCE -#endif #include <pwd.h> #include <sys/types.h> #include <unistd.h> #if defined(_OS_LINUX_) #include <shadow.h> #endif //#define INSECURE const int block_size = 51200; -QCopBridge::QCopBridge( Q_UINT16 port, QObject *parent, +QCopBridge::QCopBridge( Q_UINT16 port, QObject *parent , const char* name ) : QServerSocket( port, 1, parent, name ), desktopChannel( 0 ), cardChannel( 0 ) { if ( !ok() ) - qWarning( "Failed to bind to port %d", port ); + qWarning( "Failed to bind to port %d", port ); else { - desktopChannel = new QCopChannel( "QPE/Desktop", this ); - connect( desktopChannel, SIGNAL(received(const QCString &, const QByteArray &)), - this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); - cardChannel = new QCopChannel( "QPE/Card", this ); - connect( cardChannel, SIGNAL(received(const QCString &, const QByteArray &)), - this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); +#ifndef QT_NO_COP + desktopChannel = new QCopChannel( "QPE/Desktop", this ); + connect( desktopChannel, SIGNAL(received(const QCString &, const QByteArray &)), + this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); + cardChannel = new QCopChannel( "QPE/Card", this ); + connect( cardChannel, SIGNAL(received(const QCString &, const QByteArray &)), + this, SLOT(desktopMessage( const QCString &, const QByteArray &)) ); +#endif } sendSync = FALSE; } QCopBridge::~QCopBridge() { +#ifndef QT_NO_COP delete desktopChannel; +#endif } void QCopBridge::newConnection( int socket ) { QCopBridgePI *pi = new QCopBridgePI( socket, this ); openConnections.append( pi ); connect ( pi, SIGNAL( connectionClosed( QCopBridgePI *) ), this, SLOT( connectionClosed( QCopBridgePI *) ) ); +#ifndef QT_NO_COP QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::DisableSuspend; - +#endif + if ( sendSync ) { - pi ->startSync(); - sendSync = FALSE; + pi ->startSync(); + sendSync = FALSE; } } void QCopBridge::connectionClosed( QCopBridgePI *pi ) { openConnections.remove( pi ); if ( openConnections.count() == 0 ) { - QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::Enable; +#ifndef QT_NO_COP + QCopEnvelope( "QPE/System", "setScreenSaverMode(int)" ) << QPEApplication::Enable; +#endif } -} +} void QCopBridge::closeOpenConnections() { QCopBridgePI *pi; for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() ) - pi->close(); + pi->close(); } void QCopBridge::desktopMessage( const QCString &command, const QByteArray &args ) { command.stripWhiteSpace(); int paren = command.find( "(" ); if ( paren <= 0 ) { - qDebug("DesktopMessage: bad qcop syntax"); - return; + qDebug("DesktopMessage: bad qcop syntax"); + return; } QString params = command.mid( paren + 1 ); if ( params[params.length()-1] != ')' ) { - qDebug("DesktopMessage: bad qcop syntax"); - return; + qDebug("DesktopMessage: bad qcop syntax"); + return; } params.truncate( params.length()-1 ); QStringList paramList = QStringList::split( ",", params ); QString data; if ( paramList.count() ) { - QDataStream stream( args, IO_ReadOnly ); - for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { - QString str; - if ( *it == "QString" ) { - stream >> str; - } else if ( *it == "QCString" ) { - QCString cstr; - stream >> cstr; - str = QString::fromLocal8Bit( cstr ); - } else if ( *it == "int" ) { - int i; - stream >> i; - str = QString::number( i ); - } else if ( *it == "bool" ) { - int i; - stream >> i; - str = QString::number( i ); - } else { - qDebug(" cannot route the argument type %s through the qcop bridge", (*it).latin1() ); - return; - } - str.replace( QRegExp("&"), "&" ); - str.replace( QRegExp(" "), "&0x20;" ); - str.replace( QRegExp("\n"), "&0x0d;" ); - str.replace( QRegExp("\r"), "&0x0a;" ); - data += " " + str; - } + QDataStream stream( args, IO_ReadOnly ); + for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { + QString str; + if ( *it == "QString" ) { + stream >> str; + } else if ( *it == "QCString" ) { + QCString cstr; + stream >> cstr; + str = QString::fromLocal8Bit( cstr ); + } else if ( *it == "int" ) { + int i; + stream >> i; + str = QString::number( i ); + } else if ( *it == "bool" ) { + int i; + stream >> i; + str = QString::number( i ); + } else { + qDebug(" cannot route the argument type %s throught the qcop bridge", (*it).latin1() ); + return; + } + QString estr; + for (int i=0; i<(int)str.length(); i++) { + QChar ch = str[i]; + if ( ch.row() ) + goto quick; + switch (ch.cell()) { + case '&': + estr.append( "&" ); + break; + case ' ': + estr.append( "&0x20;" ); + break; + case '\n': + estr.append( "&0x0d;" ); + break; + case '\r': + estr.append( "&0x0a;" ); + break; + default: quick: + estr.append(ch); + } + } + data += " " + estr; + } } QString sendCommand = QString(command.data()) + data; // send the command to all open connections if ( command == "startSync()" ) { - // we need to buffer it a bit - sendSync = TRUE; - startTimer( 20000 ); - } - + // we need to buffer it a bit + sendSync = TRUE; + startTimer( 20000 ); + } + QCopBridgePI *pi; for ( pi = openConnections.first(); pi != 0; pi = openConnections.next() ) { - pi->sendDesktopMessage( sendCommand ); + pi->sendDesktopMessage( sendCommand ); } } void QCopBridge::timerEvent( QTimerEvent * ) { sendSync = FALSE; killTimers(); } -QCopBridgePI::QCopBridgePI( int socket, QObject *parent, const char* name ) - : QSocket( parent, name ) +QCopBridgePI::QCopBridgePI( int socket, QObject *parent , const char* name ) + : QSocket( parent, name ) { setSocket( socket ); peerport = peerPort(); peeraddress = peerAddress(); #ifndef INSECURE - if ( !accessAuthorized(peeraddress) ) { - state = Forbidden; - startTimer( 0 ); - } else -#endif + if ( !SyncAuthentication::isAuthorized(peeraddress) ) { + state = Forbidden; + startTimer( 0 ); + } else +#endif { - state = Connected; - sendSync = FALSE; - connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); - connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); - - send( "220 Qtopia QCop bridge ready!" ); - state = Wait_USER; - - // idle timer to close connections when not used anymore - startTimer( 60000 ); - connected = TRUE; + state = Connected; + sendSync = FALSE; + connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); + connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); + + QString intro="220 Qtopia "; + intro += QPE_VERSION; intro += ";"; + intro += "challenge="; intro += SyncAuthentication::serverId(); intro += ";"; + intro += "loginname="; intro += SyncAuthentication::loginName(); intro += ";"; + intro += "displayname="; intro += SyncAuthentication::ownerName(); intro += ";"; + send( intro ); + state = Wait_USER; + + // idle timer to close connections when not used anymore + startTimer( 60000 ); + connected = TRUE; } } QCopBridgePI::~QCopBridgePI() { @@ -229,44 +261,13 @@ void QCopBridgePI::send( const QString& msg ) //qDebug( "sending qcop message: %s", msg.latin1() ); } void QCopBridgePI::read() { while ( canReadLine() ) - process( readLine().stripWhiteSpace() ); -} - -bool QCopBridgePI::checkUser( const QString& user ) -{ - if ( user.isEmpty() ) return FALSE; - - struct passwd *pw; - pw = getpwuid( geteuid() ); - QString euser = QString::fromLocal8Bit( pw->pw_name ); - return user == euser; -} - -bool QCopBridgePI::checkPassword( const QString& password ) -{ - // ### HACK for testing on local host - return true; - - /* - struct passwd *pw = 0; - struct spwd *spw = 0; - - pw = getpwuid( geteuid() ); - spw = getspnam( pw->pw_name ); - - QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); - if ( cpwd == "x" && spw ) - cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); - - QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); - return cpwd == cpassword; -*/ + process( readLine().stripWhiteSpace() ); } void QCopBridgePI::process( const QString& message ) { //qDebug( "Command: %s", message.latin1() ); @@ -277,144 +278,147 @@ void QCopBridgePI::process( const QString& message ) // command token QString cmd = msg[0].upper(); // argument token QString arg; if ( msg.count() >= 2 ) - arg = msg[1]; - + arg = msg[1]; + // we always respond to QUIT, regardless of state if ( cmd == "QUIT" ) { - send( "211 Have a nice day!" ); - delete this; - return; + send( "211 Have a nice day!" ); + delete this; + return; } // connected to client if ( Connected == state ) - return; + return; // waiting for user name if ( Wait_USER == state ) { - if ( cmd != "USER" || msg.count() < 2 || !checkUser( arg ) ) { - send( "530 Please login with USER and PASS" ); - return; - } - send( "331 User name ok, need password" ); - state = Wait_PASS; - return; + if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { + send( "530 Please login with USER and PASS" ); + return; + } + send( "331 User name ok, need password" ); + state = Wait_PASS; + return; } // waiting for password if ( Wait_PASS == state ) { - if ( cmd != "PASS" || !checkPassword( arg ) ) { - //if ( cmd != "PASS" || msg.count() < 2 || !checkPassword( arg ) ) { - send( "530 Please login with USER and PASS" ); - return; - } - send( "230 User logged in, proceed" ); - state = Ready; - if ( sendSync ) { - sendDesktopMessage( "startSync()" ); - sendSync = FALSE; - } - return; + if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { + send( "530 Please login with USER and PASS" ); + return; + } + send( "230 User logged in, proceed" ); + state = Ready; + if ( sendSync ) { + sendDesktopMessage( "startSync()" ); + sendSync = FALSE; + } + return; } // noop (NOOP) else if ( cmd == "NOOP" ) { - connected = TRUE; - send( "200 Command okay" ); + connected = TRUE; + send( "200 Command okay" ); } - + // call (CALL) else if ( cmd == "CALL" ) { - // example: call QPE/System execute(QString) addressbook - - if ( msg.count() < 3 ) { - send( "500 Syntax error, command unrecognized" ); - } - else { - - QString channel = msg[1]; - QString command = msg[2]; - - command.stripWhiteSpace(); - - int paren = command.find( "(" ); - if ( paren <= 0 ) { - send( "500 Syntax error, command unrecognized" ); - return; - } - - QString params = command.mid( paren + 1 ); - if ( params[params.length()-1] != ')' ) { - send( "500 Syntax error, command unrecognized" ); - return; - } - - params.truncate( params.length()-1 ); - QByteArray buffer; - QDataStream ds( buffer, IO_WriteOnly ); - - int msgId = 3; - - QStringList paramList = QStringList::split( ",", params ); - if ( paramList.count() > msg.count() - 3 ) { - send( "500 Syntax error, command unrecognized" ); - return; - } - - for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { - - QString arg = msg[msgId]; - arg.replace( QRegExp("&0x20;"), " " ); - arg.replace( QRegExp("&"), "&" ); - arg.replace( QRegExp("&0x0d;"), "\n" ); - arg.replace( QRegExp("&0x0a;"), "\r" ); - if ( *it == "QString" ) - ds << arg; - else if ( *it == "QCString" ) - ds << arg.local8Bit(); - else if ( *it == "int" ) - ds << arg.toInt(); - else if ( *it == "bool" ) - ds << arg.toInt(); - else { - send( "500 Syntax error, command unrecognized" ); - return; - } - msgId++; - } - - if ( !QCopChannel::isRegistered( channel.latin1() ) ) { - // send message back about it - QString answer = "599 ChannelNotRegistered " + channel; - send( answer ); - return; - } - - if ( paramList.count() ) - QCopChannel::send( channel.latin1(), command.latin1(), buffer ); - else - QCopChannel::send( channel.latin1(), command.latin1() ); - - send( "200 Command okay" ); - } + // example: call QPE/System execute(QString) addressbook + + if ( msg.count() < 3 ) { + send( "500 Syntax error, command unrecognized" ); + } + else { + + QString channel = msg[1]; + QString command = msg[2]; + + command.stripWhiteSpace(); + + int paren = command.find( "(" ); + if ( paren <= 0 ) { + send( "500 Syntax error, command unrecognized" ); + return; + } + + QString params = command.mid( paren + 1 ); + if ( params[params.length()-1] != ')' ) { + send( "500 Syntax error, command unrecognized" ); + return; + } + + params.truncate( params.length()-1 ); + QByteArray buffer; + QDataStream ds( buffer, IO_WriteOnly ); + + int msgId = 3; + + QStringList paramList = QStringList::split( ",", params ); + if ( paramList.count() > msg.count() - 3 ) { + send( "500 Syntax error, command unrecognized" ); + return; + } + + for ( QStringList::Iterator it = paramList.begin(); it != paramList.end(); ++it ) { + + QString arg = msg[msgId]; + arg.replace( QRegExp("&0x20;"), " " ); + arg.replace( QRegExp("&"), "&" ); + arg.replace( QRegExp("&0x0d;"), "\n" ); + arg.replace( QRegExp("&0x0a;"), "\r" ); + if ( *it == "QString" ) + ds << arg; + else if ( *it == "QCString" ) + ds << arg.local8Bit(); + else if ( *it == "int" ) + ds << arg.toInt(); + else if ( *it == "bool" ) + ds << arg.toInt(); + else { + send( "500 Syntax error, command unrecognized" ); + return; + } + msgId++; + } + +#ifndef QT_NO_COP + if ( !QCopChannel::isRegistered( channel.latin1() ) ) { + // send message back about it + QString answer = "599 ChannelNotRegistered " + channel; + send( answer ); + return; + } +#endif + +#ifndef QT_NO_COP + if ( paramList.count() ) + QCopChannel::send( channel.latin1(), command.latin1(), buffer ); + else + QCopChannel::send( channel.latin1(), command.latin1() ); + + send( "200 Command okay" ); +#endif + } } // not implemented else - send( "502 Command not implemented" ); + send( "502 Command not implemented" ); } void QCopBridgePI::timerEvent( QTimerEvent * ) { if ( connected ) - connected = FALSE; + connected = FALSE; else - connectionClosed(); + connectionClosed(); } diff --git a/core/launcher/qcopbridge.h b/core/launcher/qcopbridge.h index 114b3ee..408d10d 100644 --- a/core/launcher/qcopbridge.h +++ b/core/launcher/qcopbridge.h @@ -1,10 +1,10 @@ /********************************************************************** -** Copyright (C) 2000 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** -** This file is part of Qtopia Environment. +** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** @@ -76,15 +76,12 @@ protected slots: void read(); void send( const QString& msg ); void process( const QString& command ); void connectionClosed(); protected: - bool checkUser( const QString& user ); - bool checkPassword( const QString& pw ); - void timerEvent( QTimerEvent *e ); private: State state; Q_UINT16 peerport; QHostAddress peeraddress; diff --git a/core/launcher/transferserver.cpp b/core/launcher/transferserver.cpp index 7294f9c..a6dab07 100644 --- a/core/launcher/transferserver.cpp +++ b/core/launcher/transferserver.cpp @@ -1,10 +1,10 @@ /********************************************************************** -** Copyright (C) 2000 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** -** This file is part of Qtopia Environment. +** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** @@ -19,12 +19,19 @@ **********************************************************************/ #define _XOPEN_SOURCE #include <pwd.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> +#include <time.h> +#include <shadow.h> + +extern "C" { +#include <uuid/uuid.h> +#define UUID_H_INCLUDED +} #if defined(_OS_LINUX_) #include <shadow.h> #endif #include <qdir.h> @@ -34,21 +41,27 @@ #include <qmessagebox.h> #include <qstringlist.h> #include <qfileinfo.h> #include <qregexp.h> //#include <qpe/qcopchannel_qws.h> #include <qpe/process.h> +#include <qpe/global.h> #include <qpe/config.h> +#include <qpe/contact.h> +#include <qpe/quuid.h> +#include <qpe/version.h> +#ifdef QWS #include <qpe/qcopenvelope_qws.h> +#endif #include "transferserver.h" #include "qprocess.h" const int block_size = 51200; -TransferServer::TransferServer( Q_UINT16 port, QObject *parent, +TransferServer::TransferServer( Q_UINT16 port, QObject *parent , const char* name ) : QServerSocket( port, 1, parent, name ) { if ( !ok() ) qWarning( "Failed to bind to port %d", port ); } @@ -60,55 +73,161 @@ TransferServer::~TransferServer() void TransferServer::newConnection( int socket ) { (void) new ServerPI( socket, this ); } -bool accessAuthorized(QHostAddress peeraddress) +QString SyncAuthentication::serverId() { Config cfg("Security"); cfg.setGroup("Sync"); - uint auth_peer = cfg.readNumEntry("auth_peer",0xc0a80100); + QString r=cfg.readEntry("serverid"); + if ( r.isEmpty() ) { + uuid_t uuid; + uuid_generate( uuid ); + cfg.writeEntry("serverid",(r = QUuid( uuid ).toString())); + } + return r; +} + +QString SyncAuthentication::ownerName() +{ + QString vfilename = Global::applicationFileName("addressbook", + "businesscard.vcf"); + if (QFile::exists(vfilename)) { + Contact c; + c = Contact::readVCard( vfilename )[0]; + return c.fullName(); + } + + return ""; +} + +QString SyncAuthentication::loginName() +{ + struct passwd *pw; + pw = getpwuid( geteuid() ); + return QString::fromLocal8Bit( pw->pw_name ); +} + +int SyncAuthentication::isAuthorized(QHostAddress peeraddress) +{ + Config cfg("Security"); + cfg.setGroup("Sync"); + QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0"); + QHostAddress allowed; + allowed.setAddress(allowedstr); + uint auth_peer = allowed.ip4Addr(); uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits",24); - bool ok = (peeraddress.ip4Addr() & (((1<<auth_peer_bits)-1)<<(32-auth_peer_bits))) - == auth_peer; - /* Allows denial-of-service attack. - if ( !ok ) { - QMessageBox::warning(0,tr("Security"), - tr("<p>An attempt to access this device from %1 has been denied.") - .arg(peeraddress.toString())); - } - */ - return ok; + uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined + ? 0xffffffff : (((1<<auth_peer_bits)-1)<<(32-auth_peer_bits)); + return (peeraddress.ip4Addr() & mask) == auth_peer; +} + +bool SyncAuthentication::checkUser( const QString& user ) +{ + if ( user.isEmpty() ) return FALSE; + QString euser = loginName(); + return user == euser; } -ServerPI::ServerPI( int socket, QObject *parent, const char* name ) +bool SyncAuthentication::checkPassword( const QString& password ) +{ +#ifdef ALLOW_UNIX_USER_FTP + // First, check system password... + + struct passwd *pw = 0; + struct spwd *spw = 0; + + pw = getpwuid( geteuid() ); + spw = getspnam( pw->pw_name ); + + QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); + if ( cpwd == "x" && spw ) + cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); + + // Note: some systems use more than crypt for passwords. + QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); + if ( cpwd == cpassword ) + return TRUE; +#endif + + static int lastdenial=0; + static int denials=0; + int now = time(0); + + // Detect old Qtopia Desktop (no password) + if ( password.isEmpty() ) { + if ( denials < 1 || now > lastdenial+600 ) { + QMessageBox::warning( 0,tr("Sync Connection"), + tr("<p>An unauthorized system is requesting access to this device." + "<p>If you are using a version of Qtopia Desktop older than 1.5.1, " + "please upgrade."), + tr("Deny") ); + denials++; + lastdenial=now; + } + return FALSE; + } + + // Second, check sync password... + if ( password.left(6) == "Qtopia" ) { + QString cpassword = QString::fromLocal8Bit( crypt( password.mid(8).local8Bit(), "qp" ) ); + Config cfg("Security"); + cfg.setGroup("Sync"); + QString pwds = cfg.readEntry("Passwords"); + if ( QStringList::split(QChar(' '),pwds).contains(cpassword) ) + return TRUE; + + // Unrecognized system. Be careful... + + if ( (denials > 2 && now < lastdenial+600) + || QMessageBox::warning(0,tr("Sync Connection"), + tr("<p>An unrecognized system is requesting access to this device." + "<p>If you have just initiated a Sync for the first time, this is normal."), + tr("Allow"),tr("Deny"))==1 ) + { + denials++; + lastdenial=now; + return FALSE; + } else { + denials=0; + cfg.writeEntry("Passwords",pwds+" "+cpassword); + return TRUE; + } + } + + return FALSE; +} + + +ServerPI::ServerPI( int socket, QObject *parent , const char* name ) : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ) { state = Connected; setSocket( socket ); peerport = peerPort(); peeraddress = peerAddress(); #ifndef INSECURE - if ( !accessAuthorized(peeraddress) ) { + if ( !SyncAuthentication::isAuthorized(peeraddress) ) { state = Forbidden; startTimer( 0 ); } else #endif { connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); passiv = FALSE; for( int i = 0; i < 4; i++ ) wait[i] = FALSE; - send( "220 Qtopia transfer service ready!" ); + send( "220 Qtopia " QPE_VERSION " FTP Server" ); state = Wait_USER; dtp = new ServerDTP( this ); connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) ); connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) ); connect( dtp, SIGNAL( error( int ) ), SLOT( dtpError( int ) ) ); @@ -148,43 +267,12 @@ void ServerPI::send( const QString& msg ) void ServerPI::read() { while ( canReadLine() ) process( readLine().stripWhiteSpace() ); } -bool ServerPI::checkUser( const QString& user ) -{ - if ( user.isEmpty() ) return FALSE; - - struct passwd *pw; - pw = getpwuid( geteuid() ); - QString euser = QString::fromLocal8Bit( pw->pw_name ); - return user == euser; -} - -bool ServerPI::checkPassword( const QString& /* password */ ) -{ - // ### HACK for testing on local host - return true; - - /* - struct passwd *pw = 0; - struct spwd *spw = 0; - - pw = getpwuid( geteuid() ); - spw = getspnam( pw->pw_name ); - - QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); - if ( cpwd == "x" && spw ) - cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); - - QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); - return cpwd == cpassword; -*/ -} - bool ServerPI::checkReadFile( const QString& file ) { QString filename; if ( file[0] != "/" ) filename = directory.path() + "/" + file; @@ -251,26 +339,25 @@ void ServerPI::process( const QString& message ) if ( Connected == state ) return; // waiting for user name if ( Wait_USER == state ) { - if ( cmd != "USER" || msg.count() < 2 || !checkUser( arg ) ) { + if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { send( "530 Please login with USER and PASS" ); return; } send( "331 User name ok, need password" ); state = Wait_PASS; return; } // waiting for password if ( Wait_PASS == state ) { - if ( cmd != "PASS" || !checkPassword( arg ) ) { - //if ( cmd != "PASS" || msg.count() < 2 || !checkPassword( arg ) ) { + if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { send( "530 Please login with USER and PASS" ); return; } send( "230 User logged in, proceed" ); state = Ready; return; @@ -451,16 +538,19 @@ void ServerPI::process( const QString& message ) // delete (DELE) else if ( cmd == "DELE" ) { if ( args.isEmpty() ) send( "500 Syntax error, command unrecognized" ); else { QFile file( absFilePath( args ) ) ; - if ( file.remove() ) + if ( file.remove() ) { send( "250 Requested file action okay, completed" ); - else + QCopEnvelope e("QPE/System", "linkChanged(QString)" ); + e << file.name(); + } else { send( "550 Requested action not taken" ); + } } } // remove directory (RMD) else if ( cmd == "RMD" ) { if ( args.isEmpty() ) @@ -631,15 +721,22 @@ bool ServerPI::parsePort( const QString& pp ) peerport = ( p[4].toInt() << 8 ) + p[5].toInt(); return TRUE; } void ServerPI::dtpCompleted() { - dtp->close(); - waitsocket = 0; send( "226 Closing data connection, file transfer successful" ); + if ( dtp->dtpMode() == ServerDTP::RetrieveFile ) { + QString fn = dtp->fileName(); + if ( fn.right(8)==".desktop" && fn.find("/Documents/")>=0 ) { + QCopEnvelope e("QPE/System", "linkChanged(QString)" ); + e << fn; + } + } + waitsocket = 0; + dtp->close(); } void ServerPI::dtpFailed() { dtp->close(); waitsocket = 0; @@ -849,13 +946,13 @@ QString ServerPI::absFilePath( const QString& file ) void ServerPI::timerEvent( QTimerEvent * ) { connectionClosed(); } -ServerDTP::ServerDTP( QObject *parent, const char* name ) +ServerDTP::ServerDTP( QObject *parent = 0, const char* name = 0) : QSocket( parent, name ), mode( Idle ), createTargzProc( 0 ), retrieveTargzProc( 0 ), gzipProc( 0 ) { connect( this, SIGNAL( connected() ), SLOT( connected() ) ); connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); @@ -888,14 +985,16 @@ ServerDTP::~ServerDTP() createTargzProc->kill(); } void ServerDTP::extractTarDone() { qDebug("extract done"); +#ifndef QT_NO_COP QCopEnvelope e( "QPE/Desktop", "restoreDone(QString)" ); e << file.name(); +#endif } void ServerDTP::connected() { // send file mode switch ( mode ) { diff --git a/core/launcher/transferserver.h b/core/launcher/transferserver.h index 076e460..a3bb060 100644 --- a/core/launcher/transferserver.h +++ b/core/launcher/transferserver.h @@ -1,10 +1,10 @@ /********************************************************************** -** Copyright (C) 2000 Trolltech AS. All rights reserved. +** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** -** This file is part of Qtopia Environment. +** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** @@ -33,12 +33,26 @@ public: TransferServer( Q_UINT16 port, QObject *parent = 0, const char* name = 0 ); virtual ~TransferServer(); void newConnection( int socket ); }; +class SyncAuthentication : QObject +{ + Q_OBJECT + +public: + static int isAuthorized(QHostAddress peeraddress); + static bool checkPassword(const QString& pw); + static bool checkUser(const QString& user); + + static QString serverId(); + static QString loginName(); + static QString ownerName(); +}; + class ServerDTP : public QSocket { Q_OBJECT public: @@ -62,12 +76,13 @@ public: void retrieveGzipFile( const QString &fn, const QHostAddress& host, Q_UINT16 port ); void retrieveByteArray(); void retrieveByteArray( const QHostAddress& host, Q_UINT16 port ); Mode dtpMode() { return mode; } QByteArray buffer() { return buf.buffer(); } + QString fileName() const { return file.name(); } void setSocket( int socket ); signals: void completed(); void failed(); @@ -128,14 +143,12 @@ protected slots: void dtpCompleted(); void dtpFailed(); void dtpError( int ); void newConnection( int socket ); protected: - bool checkUser( const QString& user ); - bool checkPassword( const QString& pw ); bool checkReadFile( const QString& file ); bool checkWriteFile( const QString& file ); bool parsePort( const QString& pw ); bool backupRestoreGzip( const QString &file, QStringList &targets ); bool backupRestoreGzip( const QString &file ); @@ -161,8 +174,6 @@ private: QDir directory; QByteArray waitarray; QString renameFrom; QString lastCommand; int waitsocket; }; - -bool accessAuthorized(QHostAddress peeraddress); |