summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/qws/transferserver.cpp1
1 files changed, 1 insertions, 0 deletions
diff --git a/core/qws/transferserver.cpp b/core/qws/transferserver.cpp
index 7bf6719..42ac917 100644
--- a/core/qws/transferserver.cpp
+++ b/core/qws/transferserver.cpp
@@ -1,798 +1,799 @@
1/********************************************************************** 1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. 2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3** 3**
4** This file is part of the Qtopia Environment. 4** This file is part of the Qtopia Environment.
5** 5**
6** This file may be distributed and/or modified under the terms of the 6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software 7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21/* OPIE */ 21/* OPIE */
22#include <opie2/odebug.h> 22#include <opie2/odebug.h>
23 23
24/* STD */ 24/* STD */
25#define _XOPEN_SOURCE 25#define _XOPEN_SOURCE
26#include <pwd.h> 26#include <pwd.h>
27#include <sys/types.h> 27#include <sys/types.h>
28#include <unistd.h> 28#include <unistd.h>
29#include <stdlib.h> 29#include <stdlib.h>
30#include <time.h> 30#include <time.h>
31#include <crypt.h>
31 32
32#ifndef Q_OS_MACX 33#ifndef Q_OS_MACX
33#include <shadow.h> 34#include <shadow.h>
34#endif /* Q_OS_MACX */ 35#endif /* Q_OS_MACX */
35 36
36/* we need the _OS_LINUX stuff first ! */ 37/* we need the _OS_LINUX stuff first ! */
37 38
38#ifndef _OS_LINUX_ 39#ifndef _OS_LINUX_
39// Is anybody able to review this ? The include "uuid/uuid.h" couldn't be found 40// Is anybody able to review this ? The include "uuid/uuid.h" couldn't be found
40// anywhere ? Therfore I removed it completely.. 41// anywhere ? Therfore I removed it completely..
41// I think it should be made permanentyl !? (eilers) 42// I think it should be made permanentyl !? (eilers)
42#warning "Where should uuid/uuid.h be found ? Removed this part .. (eilers)" 43#warning "Where should uuid/uuid.h be found ? Removed this part .. (eilers)"
43#if 0 44#if 0
44 45
45extern "C" 46extern "C"
46{ 47{
47#include <uuid/uuid.h> 48#include <uuid/uuid.h>
48#define UUID_H_INCLUDED 49#define UUID_H_INCLUDED
49} 50}
50 51
51#endif 52#endif
52 53
53#endif // not defined linux 54#endif // not defined linux
54 55
55#if defined(_OS_LINUX_) 56#if defined(_OS_LINUX_)
56#include <shadow.h> 57#include <shadow.h>
57#elif defined(Q_OS_MACX) 58#elif defined(Q_OS_MACX)
58#include <stdlib.h> 59#include <stdlib.h>
59#endif 60#endif
60 61
61#include <qtextstream.h> 62#include <qtextstream.h>
62#include <qmessagebox.h> 63#include <qmessagebox.h>
63//#include <qpe/qcopchannel_qws.h> 64//#include <qpe/qcopchannel_qws.h>
64#include <qpe/process.h> 65#include <qpe/process.h>
65#include <qpe/global.h> 66#include <qpe/global.h>
66#include <qpe/config.h> 67#include <qpe/config.h>
67#include <qpe/contact.h> 68#include <qpe/contact.h>
68#include <qpe/version.h> 69#include <qpe/version.h>
69#include <qpe/qcopenvelope_qws.h> 70#include <qpe/qcopenvelope_qws.h>
70 71
71#include "transferserver.h" 72#include "transferserver.h"
72#include <opie2/oprocess.h> 73#include <opie2/oprocess.h>
73using namespace Opie::Core; 74using namespace Opie::Core;
74 75
75const int block_size = 51200; 76const int block_size = 51200;
76 77
77TransferServer::TransferServer( Q_UINT16 port, QObject *parent , 78TransferServer::TransferServer( Q_UINT16 port, QObject *parent ,
78 const char* name ) 79 const char* name )
79 : QServerSocket( port, 1, parent, name ) 80 : QServerSocket( port, 1, parent, name )
80{ 81{
81 if ( !ok() ) 82 if ( !ok() )
82 owarn << "Failed to bind to port " << port << "" << oendl; 83 owarn << "Failed to bind to port " << port << "" << oendl;
83} 84}
84 85
85TransferServer::~TransferServer() 86TransferServer::~TransferServer()
86{ 87{
87} 88}
88 89
89void TransferServer::newConnection( int socket ) 90void TransferServer::newConnection( int socket )
90{ 91{
91 (void) new ServerPI( socket, this ); 92 (void) new ServerPI( socket, this );
92} 93}
93 94
94/* 95/*
95 * small class in anonymous namespace 96 * small class in anonymous namespace
96 * to generate a QUUid for us 97 * to generate a QUUid for us
97 */ 98 */
98namespace 99namespace
99{ 100{
100struct UidGen 101struct UidGen
101{ 102{
102 QString uuid(); 103 QString uuid();
103}; 104};
104#if defined(Q_OS_MACX) 105#if defined(Q_OS_MACX)
105QString UidGen::uuid() 106QString UidGen::uuid()
106{ 107{
107 srandom( random() ); 108 srandom( random() );
108 QString numStr = QString::number( random() ); 109 QString numStr = QString::number( random() );
109 110
110 return "{" + numStr + "}"; 111 return "{" + numStr + "}";
111} 112}
112#elif defined(_OS_LINUX_) 113#elif defined(_OS_LINUX_)
113/* 114/*
114* linux got a /proc/sys/kernel/random/uuid file 115* linux got a /proc/sys/kernel/random/uuid file
115* it'll generate the uuids for us 116* it'll generate the uuids for us
116*/ 117*/
117QString UidGen::uuid() 118QString UidGen::uuid()
118{ 119{
119 QFile file( "/proc/sys/kernel/random/uuid" ); 120 QFile file( "/proc/sys/kernel/random/uuid" );
120 if (!file.open(IO_ReadOnly ) ) 121 if (!file.open(IO_ReadOnly ) )
121 return QString::null; 122 return QString::null;
122 123
123 QTextStream stream(&file); 124 QTextStream stream(&file);
124 125
125 return "{" + stream.read().stripWhiteSpace() + "}"; 126 return "{" + stream.read().stripWhiteSpace() + "}";
126} 127}
127#else 128#else
128QString UidGen::uuid() 129QString UidGen::uuid()
129{ 130{
130 uuid_t uuid; 131 uuid_t uuid;
131 ::uuid_generate( uuid ); 132 ::uuid_generate( uuid );
132 return QUUid( uuid ).toString(); 133 return QUUid( uuid ).toString();
133} 134}
134#endif 135#endif
135} 136}
136 137
137QString SyncAuthentication::serverId() 138QString SyncAuthentication::serverId()
138{ 139{
139 Config cfg("Security"); 140 Config cfg("Security");
140 cfg.setGroup("Sync"); 141 cfg.setGroup("Sync");
141 QString r = cfg.readEntry("serverid"); 142 QString r = cfg.readEntry("serverid");
142 if ( r.isEmpty() ) { 143 if ( r.isEmpty() ) {
143 UidGen gen; 144 UidGen gen;
144 r = gen.uuid(); 145 r = gen.uuid();
145 cfg.writeEntry("serverid", r ); 146 cfg.writeEntry("serverid", r );
146 } 147 }
147 return r; 148 return r;
148} 149}
149 150
150QString SyncAuthentication::ownerName() 151QString SyncAuthentication::ownerName()
151{ 152{
152 QString vfilename = Global::applicationFileName("addressbook", 153 QString vfilename = Global::applicationFileName("addressbook",
153 "businesscard.vcf"); 154 "businesscard.vcf");
154 if (QFile::exists(vfilename)) { 155 if (QFile::exists(vfilename)) {
155 Contact c; 156 Contact c;
156 c = Contact::readVCard( vfilename )[0]; 157 c = Contact::readVCard( vfilename )[0];
157 return c.fullName(); 158 return c.fullName();
158 } 159 }
159 160
160 return ""; 161 return "";
161} 162}
162 163
163QString SyncAuthentication::loginName() 164QString SyncAuthentication::loginName()
164{ 165{
165 struct passwd *pw; 166 struct passwd *pw;
166 pw = getpwuid( geteuid() ); 167 pw = getpwuid( geteuid() );
167 return QString::fromLocal8Bit( pw->pw_name ); 168 return QString::fromLocal8Bit( pw->pw_name );
168} 169}
169 170
170int SyncAuthentication::isAuthorized(QHostAddress peeraddress) 171int SyncAuthentication::isAuthorized(QHostAddress peeraddress)
171{ 172{
172 Config cfg("Security"); 173 Config cfg("Security");
173 cfg.setGroup("Sync"); 174 cfg.setGroup("Sync");
174 // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0"); 175 // QString allowedstr = cfg.readEntry("auth_peer","192.168.1.0");
175 uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100); 176 uint auth_peer = cfg.readNumEntry("auth_peer", 0xc0a80100);
176 177
177 // QHostAddress allowed; 178 // QHostAddress allowed;
178 // allowed.setAddress(allowedstr); 179 // allowed.setAddress(allowedstr);
179 // uint auth_peer = allowed.ip4Addr(); 180 // uint auth_peer = allowed.ip4Addr();
180 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24); 181 uint auth_peer_bits = cfg.readNumEntry("auth_peer_bits", 24);
181 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined 182 uint mask = auth_peer_bits >= 32 // shifting by 32 is not defined
182 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits)); 183 ? 0xffffffff : (((1 << auth_peer_bits) - 1) << (32 - auth_peer_bits));
183 return (peeraddress.ip4Addr() & mask) == auth_peer; 184 return (peeraddress.ip4Addr() & mask) == auth_peer;
184} 185}
185 186
186bool SyncAuthentication::checkUser( const QString& user ) 187bool SyncAuthentication::checkUser( const QString& user )
187{ 188{
188 if ( user.isEmpty() ) 189 if ( user.isEmpty() )
189 return FALSE; 190 return FALSE;
190 QString euser = loginName(); 191 QString euser = loginName();
191 return user == euser; 192 return user == euser;
192} 193}
193 194
194bool SyncAuthentication::checkPassword( const QString& password ) 195bool SyncAuthentication::checkPassword( const QString& password )
195{ 196{
196#ifdef ALLOW_UNIX_USER_FTP 197#ifdef ALLOW_UNIX_USER_FTP
197 // First, check system password... 198 // First, check system password...
198 199
199 struct passwd *pw = 0; 200 struct passwd *pw = 0;
200 struct spwd *spw = 0; 201 struct spwd *spw = 0;
201 202
202 pw = getpwuid( geteuid() ); 203 pw = getpwuid( geteuid() );
203 spw = getspnam( pw->pw_name ); 204 spw = getspnam( pw->pw_name );
204 205
205 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd ); 206 QString cpwd = QString::fromLocal8Bit( pw->pw_passwd );
206 if ( cpwd == "x" && spw ) 207 if ( cpwd == "x" && spw )
207 cpwd = QString::fromLocal8Bit( spw->sp_pwdp ); 208 cpwd = QString::fromLocal8Bit( spw->sp_pwdp );
208 209
209 // Note: some systems use more than crypt for passwords. 210 // Note: some systems use more than crypt for passwords.
210 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) ); 211 QString cpassword = QString::fromLocal8Bit( crypt( password.local8Bit(), cpwd.local8Bit() ) );
211 if ( cpwd == cpassword ) 212 if ( cpwd == cpassword )
212 return TRUE; 213 return TRUE;
213#endif 214#endif
214 215
215 static int lastdenial = 0; 216 static int lastdenial = 0;
216 static int denials = 0; 217 static int denials = 0;
217 int now = time(0); 218 int now = time(0);
218 219
219 // Detect old Qtopia Desktop (no password) 220 // Detect old Qtopia Desktop (no password)
220 if ( password.isEmpty() ) { 221 if ( password.isEmpty() ) {
221 if ( denials < 1 || now > lastdenial + 600 ) { 222 if ( denials < 1 || now > lastdenial + 600 ) {
222 QMessageBox::warning( 0, tr("Sync Connection"), 223 QMessageBox::warning( 0, tr("Sync Connection"),
223 tr("<p>An unauthorized system is requesting access to this device." 224 tr("<p>An unauthorized system is requesting access to this device."
224 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, " 225 "<p>If you are using a version of Qtopia Desktop older than 1.5.1, "
225 "please upgrade."), 226 "please upgrade."),
226 tr("Deny") ); 227 tr("Deny") );
227 denials++; 228 denials++;
228 lastdenial = now; 229 lastdenial = now;
229 } 230 }
230 return FALSE; 231 return FALSE;
231 } 232 }
232 233
233 // Second, check sync password... 234 // Second, check sync password...
234 QString pass = password.left(6); 235 QString pass = password.left(6);
235 /* old QtopiaDesktops are sending 236 /* old QtopiaDesktops are sending
236 * rootme newer versions got a Qtopia 237 * rootme newer versions got a Qtopia
237 * prefixed. Qtopia prefix will suceed 238 * prefixed. Qtopia prefix will suceed
238 * until the sync software syncs up 239 * until the sync software syncs up
239 * FIXME 240 * FIXME
240 */ 241 */
241 if ( pass == "rootme" || pass == "Qtopia") { 242 if ( pass == "rootme" || pass == "Qtopia") {
242 243
243 QString cpassword = QString::fromLocal8Bit( crypt( password.mid(8).local8Bit(), "qp" ) ); 244 QString cpassword = QString::fromLocal8Bit( crypt( password.mid(8).local8Bit(), "qp" ) );
244 Config cfg("Security"); 245 Config cfg("Security");
245 cfg.setGroup("Sync"); 246 cfg.setGroup("Sync");
246 QString pwds = cfg.readEntry("Passwords"); 247 QString pwds = cfg.readEntry("Passwords");
247 if ( QStringList::split(QChar(' '), pwds).contains(cpassword) ) 248 if ( QStringList::split(QChar(' '), pwds).contains(cpassword) )
248 return TRUE; 249 return TRUE;
249 250
250 // Unrecognized system. Be careful... 251 // Unrecognized system. Be careful...
251 252
252 if ( (denials > 2 && now < lastdenial + 600) 253 if ( (denials > 2 && now < lastdenial + 600)
253 || QMessageBox::warning(0, tr("Sync Connection"), 254 || QMessageBox::warning(0, tr("Sync Connection"),
254 tr("<p>An unrecognized system is requesting access to this device." 255 tr("<p>An unrecognized system is requesting access to this device."
255 "<p>If you have just initiated a Sync for the first time, this is normal."), 256 "<p>If you have just initiated a Sync for the first time, this is normal."),
256 tr("Allow"), tr("Deny"), 0, 1, 1 ) == 1 ) { 257 tr("Allow"), tr("Deny"), 0, 1, 1 ) == 1 ) {
257 denials++; 258 denials++;
258 lastdenial = now; 259 lastdenial = now;
259 return FALSE; 260 return FALSE;
260 } 261 }
261 else { 262 else {
262 denials = 0; 263 denials = 0;
263 cfg.writeEntry("Passwords", pwds + " " + cpassword); 264 cfg.writeEntry("Passwords", pwds + " " + cpassword);
264 return TRUE; 265 return TRUE;
265 } 266 }
266 } 267 }
267 268
268 return FALSE; 269 return FALSE;
269} 270}
270 271
271ServerPI::ServerPI( int socket, QObject *parent , const char* name ) 272ServerPI::ServerPI( int socket, QObject *parent , const char* name )
272 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 ) 273 : QSocket( parent, name ) , dtp( 0 ), serversocket( 0 ), waitsocket( 0 )
273{ 274{
274 state = Connected; 275 state = Connected;
275 276
276 setSocket( socket ); 277 setSocket( socket );
277 278
278 peerport = peerPort(); 279 peerport = peerPort();
279 peeraddress = peerAddress(); 280 peeraddress = peerAddress();
280 281
281#ifndef INSECURE 282#ifndef INSECURE
282 283
283 if ( !SyncAuthentication::isAuthorized(peeraddress) ) { 284 if ( !SyncAuthentication::isAuthorized(peeraddress) ) {
284 state = Forbidden; 285 state = Forbidden;
285 startTimer( 0 ); 286 startTimer( 0 );
286 } 287 }
287 else 288 else
288#endif 289#endif
289 { 290 {
290 connect( this, SIGNAL( readyRead() ), SLOT( read() ) ); 291 connect( this, SIGNAL( readyRead() ), SLOT( read() ) );
291 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) ); 292 connect( this, SIGNAL( connectionClosed() ), SLOT( connectionClosed() ) );
292 293
293 passiv = FALSE; 294 passiv = FALSE;
294 for ( int i = 0; i < 4; i++ ) 295 for ( int i = 0; i < 4; i++ )
295 wait[i] = FALSE; 296 wait[i] = FALSE;
296 297
297 send( "220 Qtopia " QPE_VERSION " FTP Server" ); 298 send( "220 Qtopia " QPE_VERSION " FTP Server" );
298 state = Wait_USER; 299 state = Wait_USER;
299 300
300 dtp = new ServerDTP( this ); 301 dtp = new ServerDTP( this );
301 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) ); 302 connect( dtp, SIGNAL( completed() ), SLOT( dtpCompleted() ) );
302 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) ); 303 connect( dtp, SIGNAL( failed() ), SLOT( dtpFailed() ) );
303 connect( dtp, SIGNAL( error(int) ), SLOT( dtpError(int) ) ); 304 connect( dtp, SIGNAL( error(int) ), SLOT( dtpError(int) ) );
304 305
305 306
306 directory = QDir::currentDirPath(); 307 directory = QDir::currentDirPath();
307 308
308 static int p = 1024; 309 static int p = 1024;
309 310
310 while ( !serversocket || !serversocket->ok() ) { 311 while ( !serversocket || !serversocket->ok() ) {
311 delete serversocket; 312 delete serversocket;
312 serversocket = new ServerSocket( ++p, this ); 313 serversocket = new ServerSocket( ++p, this );
313 } 314 }
314 connect( serversocket, SIGNAL( newIncomming(int) ), 315 connect( serversocket, SIGNAL( newIncomming(int) ),
315 SLOT( newConnection(int) ) ); 316 SLOT( newConnection(int) ) );
316 } 317 }
317} 318}
318 319
319ServerPI::~ServerPI() 320ServerPI::~ServerPI()
320{ 321{
321} 322}
322 323
323void ServerPI::connectionClosed() 324void ServerPI::connectionClosed()
324{ 325{
325 // odebug << "Debug: Connection closed" << oendl; 326 // odebug << "Debug: Connection closed" << oendl;
326 delete this; 327 delete this;
327} 328}
328 329
329void ServerPI::send( const QString& msg ) 330void ServerPI::send( const QString& msg )
330{ 331{
331 QTextStream os( this ); 332 QTextStream os( this );
332 os << msg << endl; 333 os << msg << endl;
333 //odebug << "Reply: " << msg << "" << oendl; 334 //odebug << "Reply: " << msg << "" << oendl;
334} 335}
335 336
336void ServerPI::read() 337void ServerPI::read()
337{ 338{
338 while ( canReadLine() ) 339 while ( canReadLine() )
339 process( readLine().stripWhiteSpace() ); 340 process( readLine().stripWhiteSpace() );
340} 341}
341 342
342bool ServerPI::checkReadFile( const QString& file ) 343bool ServerPI::checkReadFile( const QString& file )
343{ 344{
344 QString filename; 345 QString filename;
345 346
346 if ( file[0] != "/" ) 347 if ( file[0] != "/" )
347 filename = directory.path() + "/" + file; 348 filename = directory.path() + "/" + file;
348 else 349 else
349 filename = file; 350 filename = file;
350 351
351 QFileInfo fi( filename ); 352 QFileInfo fi( filename );
352 return ( fi.exists() && fi.isReadable() ); 353 return ( fi.exists() && fi.isReadable() );
353} 354}
354 355
355bool ServerPI::checkWriteFile( const QString& file ) 356bool ServerPI::checkWriteFile( const QString& file )
356{ 357{
357 QString filename; 358 QString filename;
358 359
359 if ( file[0] != "/" ) 360 if ( file[0] != "/" )
360 filename = directory.path() + "/" + file; 361 filename = directory.path() + "/" + file;
361 else 362 else
362 filename = file; 363 filename = file;
363 364
364 QFileInfo fi( filename ); 365 QFileInfo fi( filename );
365 366
366 if ( fi.exists() ) 367 if ( fi.exists() )
367 if ( !QFile( filename ).remove() ) 368 if ( !QFile( filename ).remove() )
368 return FALSE; 369 return FALSE;
369 return TRUE; 370 return TRUE;
370} 371}
371 372
372void ServerPI::process( const QString& message ) 373void ServerPI::process( const QString& message )
373{ 374{
374 //odebug << "Command: " << message << "" << oendl; 375 //odebug << "Command: " << message << "" << oendl;
375 376
376 // split message using "," as separator 377 // split message using "," as separator
377 QStringList msg = QStringList::split( " ", message ); 378 QStringList msg = QStringList::split( " ", message );
378 if ( msg.isEmpty() ) 379 if ( msg.isEmpty() )
379 return ; 380 return ;
380 381
381 // command token 382 // command token
382 QString cmd = msg[0].upper(); 383 QString cmd = msg[0].upper();
383 384
384 // argument token 385 // argument token
385 QString arg; 386 QString arg;
386 if ( msg.count() >= 2 ) 387 if ( msg.count() >= 2 )
387 arg = msg[1]; 388 arg = msg[1];
388 389
389 // full argument string 390 // full argument string
390 QString args; 391 QString args;
391 if ( msg.count() >= 2 ) { 392 if ( msg.count() >= 2 ) {
392 QStringList copy( msg ); 393 QStringList copy( msg );
393 // FIXME: for Qt3 394 // FIXME: for Qt3
394 // copy.pop_front() 395 // copy.pop_front()
395 copy.remove( copy.begin() ); 396 copy.remove( copy.begin() );
396 args = copy.join( " " ); 397 args = copy.join( " " );
397 } 398 }
398 399
399 //odebug << "args: " << args << "" << oendl; 400 //odebug << "args: " << args << "" << oendl;
400 401
401 // we always respond to QUIT, regardless of state 402 // we always respond to QUIT, regardless of state
402 if ( cmd == "QUIT" ) { 403 if ( cmd == "QUIT" ) {
403 send( "211 Good bye!" ); 404 send( "211 Good bye!" );
404 delete this; 405 delete this;
405 return ; 406 return ;
406 } 407 }
407 408
408 // connected to client 409 // connected to client
409 if ( Connected == state ) 410 if ( Connected == state )
410 return ; 411 return ;
411 412
412 // waiting for user name 413 // waiting for user name
413 if ( Wait_USER == state ) { 414 if ( Wait_USER == state ) {
414 415
415 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) { 416 if ( cmd != "USER" || msg.count() < 2 || !SyncAuthentication::checkUser( arg ) ) {
416 send( "530 Please login with USER and PASS" ); 417 send( "530 Please login with USER and PASS" );
417 return ; 418 return ;
418 } 419 }
419 send( "331 User name ok, need password" ); 420 send( "331 User name ok, need password" );
420 state = Wait_PASS; 421 state = Wait_PASS;
421 return ; 422 return ;
422 } 423 }
423 424
424 // waiting for password 425 // waiting for password
425 if ( Wait_PASS == state ) { 426 if ( Wait_PASS == state ) {
426 427
427 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) { 428 if ( cmd != "PASS" || !SyncAuthentication::checkPassword( arg ) ) {
428 send( "530 Please login with USER and PASS" ); 429 send( "530 Please login with USER and PASS" );
429 return ; 430 return ;
430 } 431 }
431 send( "230 User logged in, proceed" ); 432 send( "230 User logged in, proceed" );
432 state = Ready; 433 state = Ready;
433 return ; 434 return ;
434 } 435 }
435 436
436 // ACCESS CONTROL COMMANDS 437 // ACCESS CONTROL COMMANDS
437 438
438 439
439 // account (ACCT) 440 // account (ACCT)
440 if ( cmd == "ACCT" ) { 441 if ( cmd == "ACCT" ) {
441 // even wu-ftp does not support it 442 // even wu-ftp does not support it
442 send( "502 Command not implemented" ); 443 send( "502 Command not implemented" );
443 } 444 }
444 445
445 // change working directory (CWD) 446 // change working directory (CWD)
446 else if ( cmd == "CWD" ) { 447 else if ( cmd == "CWD" ) {
447 448
448 if ( !args.isEmpty() ) { 449 if ( !args.isEmpty() ) {
449 if ( directory.cd( args, TRUE ) ) 450 if ( directory.cd( args, TRUE ) )
450 send( "250 Requested file action okay, completed" ); 451 send( "250 Requested file action okay, completed" );
451 else 452 else
452 send( "550 Requested action not taken" ); 453 send( "550 Requested action not taken" );
453 } 454 }
454 else 455 else
455 send( "500 Syntax error, command unrecognized" ); 456 send( "500 Syntax error, command unrecognized" );
456 } 457 }
457 458
458 // change to parent directory (CDUP) 459 // change to parent directory (CDUP)
459 else if ( cmd == "CDUP" ) { 460 else if ( cmd == "CDUP" ) {
460 if ( directory.cdUp() ) 461 if ( directory.cdUp() )
461 send( "250 Requested file action okay, completed" ); 462 send( "250 Requested file action okay, completed" );
462 else 463 else
463 send( "550 Requested action not taken" ); 464 send( "550 Requested action not taken" );
464 } 465 }
465 466
466 // structure mount (SMNT) 467 // structure mount (SMNT)
467 else if ( cmd == "SMNT" ) { 468 else if ( cmd == "SMNT" ) {
468 // even wu-ftp does not support it 469 // even wu-ftp does not support it
469 send( "502 Command not implemented" ); 470 send( "502 Command not implemented" );
470 } 471 }
471 472
472 // reinitialize (REIN) 473 // reinitialize (REIN)
473 else if ( cmd == "REIN" ) { 474 else if ( cmd == "REIN" ) {
474 // even wu-ftp does not support it 475 // even wu-ftp does not support it
475 send( "502 Command not implemented" ); 476 send( "502 Command not implemented" );
476 } 477 }
477 478
478 479
479 // TRANSFER PARAMETER COMMANDS 480 // TRANSFER PARAMETER COMMANDS
480 481
481 482
482 // data port (PORT) 483 // data port (PORT)
483 else if ( cmd == "PORT" ) { 484 else if ( cmd == "PORT" ) {
484 if ( parsePort( arg ) ) 485 if ( parsePort( arg ) )
485 send( "200 Command okay" ); 486 send( "200 Command okay" );
486 else 487 else
487 send( "500 Syntax error, command unrecognized" ); 488 send( "500 Syntax error, command unrecognized" );
488 } 489 }
489 490
490 // passive (PASV) 491 // passive (PASV)
491 else if ( cmd == "PASV" ) { 492 else if ( cmd == "PASV" ) {
492 passiv = TRUE; 493 passiv = TRUE;
493 send( "227 Entering Passive Mode (" 494 send( "227 Entering Passive Mode ("
494 + address().toString().replace( QRegExp( "\\." ), "," ) + "," 495 + address().toString().replace( QRegExp( "\\." ), "," ) + ","
495 + QString::number( ( serversocket->port() ) >> 8 ) + "," 496 + QString::number( ( serversocket->port() ) >> 8 ) + ","
496 + QString::number( ( serversocket->port() ) & 0xFF ) + ")" ); 497 + QString::number( ( serversocket->port() ) & 0xFF ) + ")" );
497 } 498 }
498 499
499 // representation type (TYPE) 500 // representation type (TYPE)
500 else if ( cmd == "TYPE" ) { 501 else if ( cmd == "TYPE" ) {
501 if ( arg.upper() == "A" || arg.upper() == "I" ) 502 if ( arg.upper() == "A" || arg.upper() == "I" )
502 send( "200 Command okay" ); 503 send( "200 Command okay" );
503 else 504 else
504 send( "504 Command not implemented for that parameter" ); 505 send( "504 Command not implemented for that parameter" );
505 } 506 }
506 507
507 // file structure (STRU) 508 // file structure (STRU)
508 else if ( cmd == "STRU" ) { 509 else if ( cmd == "STRU" ) {
509 if ( arg.upper() == "F" ) 510 if ( arg.upper() == "F" )
510 send( "200 Command okay" ); 511 send( "200 Command okay" );
511 else 512 else
512 send( "504 Command not implemented for that parameter" ); 513 send( "504 Command not implemented for that parameter" );
513 } 514 }
514 515
515 // transfer mode (MODE) 516 // transfer mode (MODE)
516 else if ( cmd == "MODE" ) { 517 else if ( cmd == "MODE" ) {
517 if ( arg.upper() == "S" ) 518 if ( arg.upper() == "S" )
518 send( "200 Command okay" ); 519 send( "200 Command okay" );
519 else 520 else
520 send( "504 Command not implemented for that parameter" ); 521 send( "504 Command not implemented for that parameter" );
521 } 522 }
522 523
523 524
524 // FTP SERVICE COMMANDS 525 // FTP SERVICE COMMANDS
525 526
526 527
527 // retrieve (RETR) 528 // retrieve (RETR)
528 else if ( cmd == "RETR" ) 529 else if ( cmd == "RETR" )
529 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) ) 530 if ( !args.isEmpty() && checkReadFile( absFilePath( args ) )
530 || backupRestoreGzip( absFilePath( args ) ) ) { 531 || backupRestoreGzip( absFilePath( args ) ) ) {
531 send( "150 File status okay" ); 532 send( "150 File status okay" );
532 sendFile( absFilePath( args ) ); 533 sendFile( absFilePath( args ) );
533 } 534 }
534 else { 535 else {
535 odebug << "550 Requested action not taken" << oendl; 536 odebug << "550 Requested action not taken" << oendl;
536 send( "550 Requested action not taken" ); 537 send( "550 Requested action not taken" );
537 } 538 }
538 539
539 // store (STOR) 540 // store (STOR)
540 else if ( cmd == "STOR" ) 541 else if ( cmd == "STOR" )
541 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) { 542 if ( !args.isEmpty() && checkWriteFile( absFilePath( args ) ) ) {
542 send( "150 File status okay" ); 543 send( "150 File status okay" );
543 retrieveFile( absFilePath( args ) ); 544 retrieveFile( absFilePath( args ) );
544 } 545 }
545 else 546 else
546 send( "550 Requested action not taken" ); 547 send( "550 Requested action not taken" );
547 548
548 // store unique (STOU) 549 // store unique (STOU)
549 else if ( cmd == "STOU" ) { 550 else if ( cmd == "STOU" ) {
550 send( "502 Command not implemented" ); 551 send( "502 Command not implemented" );
551 } 552 }
552 553
553 // append (APPE) 554 // append (APPE)
554 else if ( cmd == "APPE" ) { 555 else if ( cmd == "APPE" ) {
555 send( "502 Command not implemented" ); 556 send( "502 Command not implemented" );
556 } 557 }
557 558
558 // allocate (ALLO) 559 // allocate (ALLO)
559 else if ( cmd == "ALLO" ) { 560 else if ( cmd == "ALLO" ) {
560 send( "200 Command okay" ); 561 send( "200 Command okay" );
561 } 562 }
562 563
563 // restart (REST) 564 // restart (REST)
564 else if ( cmd == "REST" ) { 565 else if ( cmd == "REST" ) {
565 send( "502 Command not implemented" ); 566 send( "502 Command not implemented" );
566 } 567 }
567 568
568 // rename from (RNFR) 569 // rename from (RNFR)
569 else if ( cmd == "RNFR" ) { 570 else if ( cmd == "RNFR" ) {
570 renameFrom = QString::null; 571 renameFrom = QString::null;
571 if ( args.isEmpty() ) 572 if ( args.isEmpty() )
572 send( "500 Syntax error, command unrecognized" ); 573 send( "500 Syntax error, command unrecognized" );
573 else { 574 else {
574 QFile file( absFilePath( args ) ); 575 QFile file( absFilePath( args ) );
575 if ( file.exists() ) { 576 if ( file.exists() ) {
576 send( "350 File exists, ready for destination name" ); 577 send( "350 File exists, ready for destination name" );
577 renameFrom = absFilePath( args ); 578 renameFrom = absFilePath( args );
578 } 579 }
579 else 580 else
580 send( "550 Requested action not taken" ); 581 send( "550 Requested action not taken" );
581 } 582 }
582 } 583 }
583 584
584 // rename to (RNTO) 585 // rename to (RNTO)
585 else if ( cmd == "RNTO" ) { 586 else if ( cmd == "RNTO" ) {
586 if ( lastCommand != "RNFR" ) 587 if ( lastCommand != "RNFR" )
587 send( "503 Bad sequence of commands" ); 588 send( "503 Bad sequence of commands" );
588 else if ( args.isEmpty() ) 589 else if ( args.isEmpty() )
589 send( "500 Syntax error, command unrecognized" ); 590 send( "500 Syntax error, command unrecognized" );
590 else { 591 else {
591 QDir dir( absFilePath( args ) ); 592 QDir dir( absFilePath( args ) );
592 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) ) 593 if ( dir.rename( renameFrom, absFilePath( args ), TRUE ) )
593 send( "250 Requested file action okay, completed." ); 594 send( "250 Requested file action okay, completed." );
594 else 595 else
595 send( "550 Requested action not taken" ); 596 send( "550 Requested action not taken" );
596 } 597 }
597 } 598 }
598 599
599 // abort (ABOR) 600 // abort (ABOR)
600 else if ( cmd.contains( "ABOR" ) ) { 601 else if ( cmd.contains( "ABOR" ) ) {
601 dtp->close(); 602 dtp->close();
602 if ( dtp->dtpMode() != ServerDTP::Idle ) 603 if ( dtp->dtpMode() != ServerDTP::Idle )
603 send( "426 Connection closed; transfer aborted" ); 604 send( "426 Connection closed; transfer aborted" );
604 else 605 else
605 send( "226 Closing data connection" ); 606 send( "226 Closing data connection" );
606 } 607 }
607 608
608 // delete (DELE) 609 // delete (DELE)
609 else if ( cmd == "DELE" ) { 610 else if ( cmd == "DELE" ) {
610 if ( args.isEmpty() ) 611 if ( args.isEmpty() )
611 send( "500 Syntax error, command unrecognized" ); 612 send( "500 Syntax error, command unrecognized" );
612 else { 613 else {
613 QFile file( absFilePath( args ) ) ; 614 QFile file( absFilePath( args ) ) ;
614 if ( file.remove() ) { 615 if ( file.remove() ) {
615 send( "250 Requested file action okay, completed" ); 616 send( "250 Requested file action okay, completed" );
616 QCopEnvelope e("QPE/System", "linkChanged(QString)" ); 617 QCopEnvelope e("QPE/System", "linkChanged(QString)" );
617 e << file.name(); 618 e << file.name();
618 } 619 }
619 else { 620 else {
620 send( "550 Requested action not taken" ); 621 send( "550 Requested action not taken" );
621 } 622 }
622 } 623 }
623 } 624 }
624 625
625 // remove directory (RMD) 626 // remove directory (RMD)
626 else if ( cmd == "RMD" ) { 627 else if ( cmd == "RMD" ) {
627 if ( args.isEmpty() ) 628 if ( args.isEmpty() )
628 send( "500 Syntax error, command unrecognized" ); 629 send( "500 Syntax error, command unrecognized" );
629 else { 630 else {
630 QDir dir; 631 QDir dir;
631 if ( dir.rmdir( absFilePath( args ), TRUE ) ) 632 if ( dir.rmdir( absFilePath( args ), TRUE ) )
632 send( "250 Requested file action okay, completed" ); 633 send( "250 Requested file action okay, completed" );
633 else 634 else
634 send( "550 Requested action not taken" ); 635 send( "550 Requested action not taken" );
635 } 636 }
636 } 637 }
637 638
638 // make directory (MKD) 639 // make directory (MKD)
639 else if ( cmd == "MKD" ) { 640 else if ( cmd == "MKD" ) {
640 if ( args.isEmpty() ) { 641 if ( args.isEmpty() ) {
641 odebug << " Error: no arg" << oendl; 642 odebug << " Error: no arg" << oendl;
642 send( "500 Syntax error, command unrecognized" ); 643 send( "500 Syntax error, command unrecognized" );
643 } 644 }
644 else { 645 else {
645 QDir dir; 646 QDir dir;
646 if ( dir.mkdir( absFilePath( args ), TRUE ) ) 647 if ( dir.mkdir( absFilePath( args ), TRUE ) )
647 send( "250 Requested file action okay, completed." ); 648 send( "250 Requested file action okay, completed." );
648 else 649 else
649 send( "550 Requested action not taken" ); 650 send( "550 Requested action not taken" );
650 } 651 }
651 } 652 }
652 653
653 // print working directory (PWD) 654 // print working directory (PWD)
654 else if ( cmd == "PWD" ) { 655 else if ( cmd == "PWD" ) {
655 send( "257 \"" + directory.path() + "\"" ); 656 send( "257 \"" + directory.path() + "\"" );
656 } 657 }
657 658
658 // list (LIST) 659 // list (LIST)
659 else if ( cmd == "LIST" ) { 660 else if ( cmd == "LIST" ) {
660 if ( sendList( absFilePath( args ) ) ) 661 if ( sendList( absFilePath( args ) ) )
661 send( "150 File status okay" ); 662 send( "150 File status okay" );
662 else 663 else
663 send( "500 Syntax error, command unrecognized" ); 664 send( "500 Syntax error, command unrecognized" );
664 } 665 }
665 666
666 // size (SIZE) 667 // size (SIZE)
667 else if ( cmd == "SIZE" ) { 668 else if ( cmd == "SIZE" ) {
668 QString filePath = absFilePath( args ); 669 QString filePath = absFilePath( args );
669 QFileInfo fi( filePath ); 670 QFileInfo fi( filePath );
670 bool gzipfile = backupRestoreGzip( filePath ); 671 bool gzipfile = backupRestoreGzip( filePath );
671 if ( !fi.exists() && !gzipfile ) 672 if ( !fi.exists() && !gzipfile )
672 send( "500 Syntax error, command unrecognized" ); 673 send( "500 Syntax error, command unrecognized" );
673 else { 674 else {
674 if ( !gzipfile ) 675 if ( !gzipfile )
675 send( "213 " + QString::number( fi.size() ) ); 676 send( "213 " + QString::number( fi.size() ) );
676 else { 677 else {
677 Process duproc( QString("du") ); 678 Process duproc( QString("du") );
678 duproc.addArgument("-s"); 679 duproc.addArgument("-s");
679 QString in, out; 680 QString in, out;
680 if ( !duproc.exec(in, out) ) { 681 if ( !duproc.exec(in, out) ) {
681 odebug << "du process failed; just sending back 1K" << oendl; 682 odebug << "du process failed; just sending back 1K" << oendl;
682 send( "213 1024"); 683 send( "213 1024");
683 } 684 }
684 else { 685 else {
685 QString size = out.left( out.find("\t") ); 686 QString size = out.left( out.find("\t") );
686 int guess = size.toInt() / 5; 687 int guess = size.toInt() / 5;
687 if ( filePath.contains("doc") ) 688 if ( filePath.contains("doc") )
688 guess *= 1000; 689 guess *= 1000;
689 odebug << "sending back gzip guess of " << guess << "" << oendl; 690 odebug << "sending back gzip guess of " << guess << "" << oendl;
690 send( "213 " + QString::number(guess) ); 691 send( "213 " + QString::number(guess) );
691 } 692 }
692 } 693 }
693 } 694 }
694 } 695 }
695 // name list (NLST) 696 // name list (NLST)
696 else if ( cmd == "NLST" ) { 697 else if ( cmd == "NLST" ) {
697 send( "502 Command not implemented" ); 698 send( "502 Command not implemented" );
698 } 699 }
699 700
700 // site parameters (SITE) 701 // site parameters (SITE)
701 else if ( cmd == "SITE" ) { 702 else if ( cmd == "SITE" ) {
702 send( "502 Command not implemented" ); 703 send( "502 Command not implemented" );
703 } 704 }
704 705
705 // system (SYST) 706 // system (SYST)
706 else if ( cmd == "SYST" ) { 707 else if ( cmd == "SYST" ) {
707 send( "215 UNIX Type: L8" ); 708 send( "215 UNIX Type: L8" );
708 } 709 }
709 710
710 // status (STAT) 711 // status (STAT)
711 else if ( cmd == "STAT" ) { 712 else if ( cmd == "STAT" ) {
712 send( "502 Command not implemented" ); 713 send( "502 Command not implemented" );
713 } 714 }
714 715
715 // help (HELP ) 716 // help (HELP )
716 else if ( cmd == "HELP" ) { 717 else if ( cmd == "HELP" ) {
717 send( "502 Command not implemented" ); 718 send( "502 Command not implemented" );
718 } 719 }
719 720
720 // noop (NOOP) 721 // noop (NOOP)
721 else if ( cmd == "NOOP" ) { 722 else if ( cmd == "NOOP" ) {
722 send( "200 Command okay" ); 723 send( "200 Command okay" );
723 } 724 }
724 725
725 // not implemented 726 // not implemented
726 else 727 else
727 send( "502 Command not implemented" ); 728 send( "502 Command not implemented" );
728 729
729 lastCommand = cmd; 730 lastCommand = cmd;
730} 731}
731 732
732bool ServerPI::backupRestoreGzip( const QString &file ) 733bool ServerPI::backupRestoreGzip( const QString &file )
733{ 734{
734 return (file.find( "backup" ) != -1 && 735 return (file.find( "backup" ) != -1 &&
735 file.findRev( ".tgz" ) == (int)file.length() - 4 ); 736 file.findRev( ".tgz" ) == (int)file.length() - 4 );
736} 737}
737 738
738bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets ) 739bool ServerPI::backupRestoreGzip( const QString &file, QStringList &targets )
739{ 740{
740 if ( file.find( "backup" ) != -1 && 741 if ( file.find( "backup" ) != -1 &&
741 file.findRev( ".tgz" ) == (int)file.length() - 4 ) { 742 file.findRev( ".tgz" ) == (int)file.length() - 4 ) {
742 QFileInfo info( file ); 743 QFileInfo info( file );
743 targets = info.dirPath( TRUE ); 744 targets = info.dirPath( TRUE );
744 odebug << "ServerPI::backupRestoreGzip for " << file.latin1() << " = " 745 odebug << "ServerPI::backupRestoreGzip for " << file.latin1() << " = "
745 << targets.join(" ").latin1() << oendl; 746 << targets.join(" ").latin1() << oendl;
746 return true; 747 return true;
747 } 748 }
748 return false; 749 return false;
749} 750}
750 751
751void ServerPI::sendFile( const QString& file ) 752void ServerPI::sendFile( const QString& file )
752{ 753{
753 if ( passiv ) { 754 if ( passiv ) {
754 wait[SendFile] = TRUE; 755 wait[SendFile] = TRUE;
755 waitfile = file; 756 waitfile = file;
756 if ( waitsocket ) 757 if ( waitsocket )
757 newConnection( waitsocket ); 758 newConnection( waitsocket );
758 } 759 }
759 else { 760 else {
760 QStringList targets; 761 QStringList targets;
761 if ( backupRestoreGzip( file, targets ) ) 762 if ( backupRestoreGzip( file, targets ) )
762 dtp->sendGzipFile( file, targets, peeraddress, peerport ); 763 dtp->sendGzipFile( file, targets, peeraddress, peerport );
763 else 764 else
764 dtp->sendFile( file, peeraddress, peerport ); 765 dtp->sendFile( file, peeraddress, peerport );
765 } 766 }
766} 767}
767 768
768void ServerPI::retrieveFile( const QString& file ) 769void ServerPI::retrieveFile( const QString& file )
769{ 770{
770 if ( passiv ) { 771 if ( passiv ) {
771 wait[RetrieveFile] = TRUE; 772 wait[RetrieveFile] = TRUE;
772 waitfile = file; 773 waitfile = file;
773 if ( waitsocket ) 774 if ( waitsocket )
774 newConnection( waitsocket ); 775 newConnection( waitsocket );
775 } 776 }
776 else { 777 else {
777 QStringList targets; 778 QStringList targets;
778 if ( backupRestoreGzip( file, targets ) ) 779 if ( backupRestoreGzip( file, targets ) )
779 dtp->retrieveGzipFile( file, peeraddress, peerport ); 780 dtp->retrieveGzipFile( file, peeraddress, peerport );
780 else 781 else
781 dtp->retrieveFile( file, peeraddress, peerport ); 782 dtp->retrieveFile( file, peeraddress, peerport );
782 } 783 }
783} 784}
784 785
785bool ServerPI::parsePort( const QString& pp ) 786bool ServerPI::parsePort( const QString& pp )
786{ 787{
787 QStringList p = QStringList::split( ",", pp ); 788 QStringList p = QStringList::split( ",", pp );
788 if ( p.count() != 6 ) 789 if ( p.count() != 6 )
789 return FALSE; 790 return FALSE;
790 791
791 // h1,h2,h3,h4,p1,p2 792 // h1,h2,h3,h4,p1,p2
792 peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) + 793 peeraddress = QHostAddress( ( p[0].toInt() << 24 ) + ( p[1].toInt() << 16 ) +
793 ( p[2].toInt() << 8 ) + p[3].toInt() ); 794 ( p[2].toInt() << 8 ) + p[3].toInt() );
794 peerport = ( p[4].toInt() << 8 ) + p[5].toInt(); 795 peerport = ( p[4].toInt() << 8 ) + p[5].toInt();
795 return TRUE; 796 return TRUE;
796} 797}
797 798
798void ServerPI::dtpCompleted() 799void ServerPI::dtpCompleted()