00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
#include "kpasswdserver.h"
00026
00027
#include <time.h>
00028
00029
#include <qtimer.h>
00030
00031
#include <kapplication.h>
00032
#include <klocale.h>
00033
#include <kmessagebox.h>
00034
#include <kdebug.h>
00035
#include <kio/passdlg.h>
00036
#include <kwallet.h>
00037
00038
#include "config.h"
00039
#ifdef Q_WS_X11
00040
#include <X11/X.h>
00041
#include <X11/Xlib.h>
00042
#endif
00043
00044
extern "C" {
00045 KDE_EXPORT KDEDModule *create_kpasswdserver(
const QCString &name)
00046 {
00047
return new KPasswdServer(name);
00048 }
00049 }
00050
00051
int
00052 KPasswdServer::AuthInfoList::compareItems(QPtrCollection::Item n1, QPtrCollection::Item n2)
00053 {
00054
if (!n1 || !n2)
00055
return 0;
00056
00057
AuthInfo *i1 = (
AuthInfo *) n1;
00058
AuthInfo *i2 = (
AuthInfo *) n2;
00059
00060
int l1 = i1->directory.length();
00061
int l2 = i2->directory.length();
00062
00063
if (l1 > l2)
00064
return -1;
00065
if (l1 < l2)
00066
return 1;
00067
return 0;
00068 }
00069
00070
00071 KPasswdServer::KPasswdServer(
const QCString &name)
00072 : KDEDModule(
name)
00073 {
00074 m_authDict.setAutoDelete(
true);
00075 m_authPending.setAutoDelete(
true);
00076 m_seqNr = 0;
00077 connect(
this, SIGNAL(windowUnregistered(
long)),
00078
this, SLOT(removeAuthForWindowId(
long)));
00079 }
00080
00081 KPasswdServer::~KPasswdServer()
00082 {
00083 }
00084
00085
KIO::AuthInfo
00086 KPasswdServer::checkAuthInfo(
KIO::AuthInfo info,
long windowId)
00087 {
00088
kdDebug(130) <<
"KPasswdServer::checkAuthInfo: User= " << info.
username
00089 <<
", WindowId = " << windowId <<
endl;
00090
00091
QString key = createCacheKey(info);
00092
00093 Request *request = m_authPending.first();
00094
QString path2 = info.
url.
directory(
false,
false);
00095
for(; request; request = m_authPending.next())
00096 {
00097
if (request->key !=
key)
00098
continue;
00099
00100
if (info.
verifyPath)
00101 {
00102
QString path1 = request->info.url.directory(
false,
false);
00103
if (!path2.
startsWith(path1))
00104
continue;
00105 }
00106
00107 request =
new Request;
00108 request->client = callingDcopClient();
00109 request->transaction = request->client->beginTransaction();
00110 request->key =
key;
00111 request->info = info;
00112 m_authWait.append(request);
00113
return info;
00114 }
00115
00116
const AuthInfo *result = findAuthInfoItem(key, info);
00117
if (!result || result->isCanceled)
00118 {
00119
if (!result &&
00120 (info.
username.
isEmpty() || info.
password.
isEmpty()) &&
00121 !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(),
00122 KWallet::Wallet::PasswordFolder(), key))
00123 {
00124
QMap<QString, QString> knownLogins;
00125 KWallet::Wallet *wallet = KWallet::Wallet::openWallet(
00126 KWallet::Wallet::NetworkWallet(), windowId);
00127
if (wallet &&
00128 readFromWallet(wallet, key, info.
username, info.
password,
00129 info.
readOnly, knownLogins))
00130 {
00131 info.
setModified(
true);
00132
return info;
00133 }
00134 }
00135
00136 info.
setModified(
false);
00137
return info;
00138 }
00139
00140 updateAuthExpire(key, result, windowId,
false);
00141
00142
return copyAuthInfo(result);
00143 }
00144
00145
KIO::AuthInfo
00146 KPasswdServer::queryAuthInfo(
KIO::AuthInfo info,
QString errorMsg,
long windowId,
long seqNr)
00147 {
00148
kdDebug(130) <<
"KPasswdServer::queryAuthInfo: User= " << info.
username
00149 <<
", Message= " << info.
prompt <<
", WindowId = " << windowId <<
endl;
00150
QString key = createCacheKey(info);
00151 Request *request =
new Request;
00152 request->client = callingDcopClient();
00153 request->transaction = request->client->beginTransaction();
00154 request->key =
key;
00155 request->info = info;
00156 request->windowId = windowId;
00157 request->seqNr = seqNr;
00158
if (errorMsg ==
"<NoAuthPrompt>")
00159 {
00160 request->errorMsg = QString::null;
00161 request->
prompt =
false;
00162 }
00163
else
00164 {
00165 request->errorMsg = errorMsg;
00166 request->prompt =
true;
00167 }
00168 m_authPending.
append(request);
00169
00170
if (m_authPending.count() == 1)
00171
QTimer::singleShot(0,
this, SLOT(processRequest()));
00172
00173
return info;
00174 }
00175
00176
void
00177 KPasswdServer::addAuthInfo(
KIO::AuthInfo info,
long windowId)
00178 {
00179
kdDebug(130) <<
"KPasswdServer::addAuthInfo: User= " << info.
username
00180 <<
", RealmValue= " << info.
realmValue <<
", WindowId = " << windowId <<
endl;
00181
QString key = createCacheKey(info);
00182
00183 m_seqNr++;
00184
00185 addAuthInfoItem(key, info, windowId, m_seqNr,
false);
00186 }
00187
00188
void
00189 KPasswdServer::processRequest()
00190 {
00191 Request *request = m_authPending.first();
00192
if (!request)
00193
return;
00194
00195
KIO::AuthInfo &info = request->info;
00196
00197
kdDebug(130) <<
"KPasswdServer::processRequest: User= " << info.
username
00198 <<
", Message= " << info.
prompt <<
endl;
00199
00200
const AuthInfo *result = findAuthInfoItem(request->key, request->info);
00201
00202
if (result && (request->seqNr < result->seqNr))
00203 {
00204
kdDebug(130) <<
"KPasswdServer::processRequest: auto retry!" <<
endl;
00205
if (result->isCanceled)
00206 {
00207 info.
setModified(
false);
00208 }
00209
else
00210 {
00211 updateAuthExpire(request->key, result, request->windowId,
false);
00212 info = copyAuthInfo(result);
00213 }
00214 }
00215
else
00216 {
00217 m_seqNr++;
00218
bool askPw = request->prompt;
00219
if (result && !info.
username.
isEmpty() &&
00220 !request->errorMsg.isEmpty())
00221 {
00222
QString prompt = request->errorMsg;
00223 prompt += i18n(
" Do you want to retry?");
00224
int dlgResult =
KMessageBox::warningContinueCancel(0, prompt,
00225 i18n(
"Authentication"), i18n(
"Retry"));
00226
if (dlgResult != KMessageBox::Continue)
00227 askPw =
false;
00228 }
00229
00230
int dlgResult = QDialog::Rejected;
00231
if (askPw)
00232 {
00233
QString username = info.
username;
00234
QString password = info.
password;
00235
bool hasWalletData =
false;
00236
QMap<QString, QString> knownLogins;
00237
00238 KWallet::Wallet* wallet = 0;
00239
if ( ( username.
isEmpty() || password.
isEmpty() )
00240 && !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder(), request->key) )
00241 {
00242
00243 wallet = KWallet::Wallet::openWallet(
00244 KWallet::Wallet::NetworkWallet(), request->windowId );
00245
if ( wallet )
00246 hasWalletData = readFromWallet( wallet, request->key, username, password, info.
readOnly, knownLogins );
00247 }
00248
00249
KIO::PasswordDialog dlg( info.
prompt, username, info.
keepPassword );
00250
if (info.
caption.
isEmpty())
00251 dlg.
setPlainCaption( i18n(
"Authorization Dialog") );
00252
else
00253 dlg.
setPlainCaption( info.
caption );
00254
00255
if ( !info.
comment.
isEmpty() )
00256 dlg.
addCommentLine( info.
commentLabel, info.
comment );
00257
00258
if ( !password.
isEmpty() )
00259 dlg.
setPassword( password );
00260
00261
if (info.
readOnly)
00262 dlg.
setUserReadOnly(
true );
00263
else
00264 dlg.
setKnownLogins( knownLogins );
00265
00266
if (hasWalletData)
00267 dlg.
setKeepPassword(
true );
00268
00269
#ifdef Q_WS_X11
00270
XSetTransientForHint( qt_xdisplay(), dlg.winId(), request->windowId);
00271
#endif
00272
00273 dlgResult = dlg.
exec();
00274
00275
if (dlgResult == QDialog::Accepted)
00276 {
00277 info.
username = dlg.
username();
00278 info.
password = dlg.
password();
00279 info.
keepPassword = dlg.
keepPassword();
00280
00281
00282
00283
00284
00285
if ( info.
keepPassword ) {
00286
if ( !wallet )
00287 wallet = KWallet::Wallet::openWallet(
00288 KWallet::Wallet::NetworkWallet(), request->windowId );
00289
if ( wallet ) {
00290
if ( storeInWallet( wallet, request->key, info ) )
00291
00292 info.
keepPassword =
false;
00293 }
00294 }
00295 }
00296
delete wallet;
00297 }
00298
if ( dlgResult != QDialog::Accepted )
00299 {
00300 addAuthInfoItem(request->key, info, 0, m_seqNr,
true);
00301 info.
setModified(
false );
00302 }
00303
else
00304 {
00305 addAuthInfoItem(request->key, info, request->windowId, m_seqNr,
false);
00306 info.
setModified(
true );
00307 }
00308 }
00309
00310
QCString replyType;
00311
QByteArray replyData;
00312
00313
QDataStream stream2(replyData, IO_WriteOnly);
00314 stream2 << info << m_seqNr;
00315 replyType =
"KIO::AuthInfo";
00316 request->client->endTransaction( request->transaction,
00317 replyType, replyData);
00318
00319 m_authPending.remove((
unsigned int) 0);
00320
00321
00322
for(Request *waitRequest = m_authWait.first();
00323 waitRequest; )
00324 {
00325
bool keepQueued =
false;
00326
QString key = waitRequest->key;
00327
00328 request = m_authPending.first();
00329
QString path2 = waitRequest->info.url.directory(
false,
false);
00330
for(; request; request = m_authPending.next())
00331 {
00332
if (request->key !=
key)
00333
continue;
00334
00335
if (info.
verifyPath)
00336 {
00337
QString path1 = request->info.url.directory(
false,
false);
00338
if (!path2.
startsWith(path1))
00339
continue;
00340 }
00341
00342 keepQueued =
true;
00343
break;
00344 }
00345
if (keepQueued)
00346 {
00347 waitRequest = m_authWait.next();
00348 }
00349
else
00350 {
00351
const AuthInfo *result = findAuthInfoItem(waitRequest->key, waitRequest->info);
00352
00353
QCString replyType;
00354
QByteArray replyData;
00355
00356
QDataStream stream2(replyData, IO_WriteOnly);
00357
00358
if (!result || result->isCanceled)
00359 {
00360 waitRequest->info.setModified(
false);
00361 stream2 << waitRequest->info;
00362 }
00363
else
00364 {
00365 updateAuthExpire(waitRequest->key, result, waitRequest->windowId,
false);
00366
KIO::AuthInfo info = copyAuthInfo(result);
00367 stream2 << info;
00368 }
00369
00370 replyType =
"KIO::AuthInfo";
00371 waitRequest->client->endTransaction( waitRequest->transaction,
00372 replyType, replyData);
00373
00374 m_authWait.remove();
00375 waitRequest = m_authWait.current();
00376 }
00377 }
00378
00379
if (m_authPending.count())
00380
QTimer::singleShot(0,
this, SLOT(processRequest()));
00381
00382 }
00383
00384
bool KPasswdServer::storeInWallet( KWallet::Wallet* wallet,
const QString& key,
const KIO::AuthInfo &info )
00385 {
00386
if ( !wallet->hasFolder( KWallet::Wallet::PasswordFolder() ) )
00387
if ( !wallet->createFolder( KWallet::Wallet::PasswordFolder() ) )
00388
return false;
00389 wallet->setFolder( KWallet::Wallet::PasswordFolder() );
00390
00391
00392
typedef QMap<QString,QString> Map;
00393
int entryNumber = 1;
00394 Map map;
00395
kdDebug() <<
k_funcinfo <<
"key=" <<
key <<
" reading existing map" <<
endl;
00396
if ( wallet->readMap( key, map ) == 0 ) {
00397 Map::ConstIterator
end = map.end();
00398 Map::ConstIterator it = map.find(
"login" );
00399
while ( it !=
end ) {
00400
if ( it.data() == info.
username ) {
00401
break;
00402 }
00403
00404 it = map.find(
QString(
"login-" ) + QString::number( ++entryNumber ) );
00405 }
00406
00407 }
00408
QString loginKey =
"login";
00409
QString passwordKey =
"password";
00410
if ( entryNumber > 1 ) {
00411
const QString suffix =
"-" +
QString::number( entryNumber );
00412 loginKey += suffix;
00413 passwordKey += suffix;
00414 }
00415
kdDebug() <<
k_funcinfo <<
"writing to " << loginKey <<
"," << passwordKey <<
endl;
00416
00417 map.insert( loginKey, info.
username );
00418 map.insert( passwordKey, info.
password );
00419 wallet->writeMap( key, map );
00420
return true;
00421 }
00422
00423
bool KPasswdServer::readFromWallet( KWallet::Wallet* wallet,
const QString& key,
QString& username,
QString& password,
bool userReadOnly,
QMap<QString,QString>& knownLogins )
00424 {
00425
if ( wallet->hasFolder( KWallet::Wallet::PasswordFolder() ) )
00426 {
00427 wallet->setFolder( KWallet::Wallet::PasswordFolder() );
00428
QMap<QString,QString> map;
00429
kdDebug() <<
k_funcinfo <<
"reading with key=" <<
key <<
endl;
00430
if ( wallet->readMap( key, map ) == 0 )
00431 {
00432
typedef QMap<QString,QString> Map;
00433
int entryNumber = 1;
00434 Map::ConstIterator
end = map.
end();
00435 Map::ConstIterator it = map.
find(
"login" );
00436
while ( it !=
end ) {
00437
QString passwordKey =
"password";
00438
if ( entryNumber > 1 )
00439 passwordKey +=
"-" +
QString::number( entryNumber );
00440 Map::ConstIterator pwdit = map.
find( passwordKey );
00441
if ( pwdit !=
end ) {
00442
if ( it.data() == username )
00443 password = pwdit.data();
00444 knownLogins.
insert( it.data(), pwdit.data() );
00445 }
00446
00447 it = map.
find(
QString(
"login-" ) + QString::number( ++entryNumber ) );
00448 }
00449
00450
if ( !userReadOnly && username.
isEmpty() ) {
00451
00452 username = knownLogins.
begin().key();
00453 password = knownLogins.
begin().data();
00454 }
00455
00456
return true;
00457 }
00458 }
00459
return false;
00460 }
00461
00462
QString KPasswdServer::createCacheKey(
const KIO::AuthInfo &info )
00463 {
00464
if( !info.
url.
isValid() ) {
00465
00466
kdWarning(130) <<
"createCacheKey: invalid URL " << info.
url <<
endl;
00467
return QString::null;
00468 }
00469
00470
00471
QString key = info.
url.
protocol();
00472
key +=
'-';
00473
if (!info.
url.
user().
isEmpty())
00474 {
00475
key += info.
url.
user();
00476
key +=
"@";
00477 }
00478
key += info.
url.
host();
00479
int port = info.
url.
port();
00480
if( port )
00481 {
00482
key +=
':';
00483
key +=
QString::number(port);
00484 }
00485
00486
return key;
00487 }
00488
00489
KIO::AuthInfo
00490 KPasswdServer::copyAuthInfo(
const AuthInfo *i)
00491 {
00492
KIO::AuthInfo result;
00493 result.
url = i->
url;
00494 result.
username = i->
username;
00495 result.
password = i->
password;
00496 result.
realmValue = i->
realmValue;
00497 result.
digestInfo = i->
digestInfo;
00498 result.
setModified(
true);
00499
00500
return result;
00501 }
00502
00503
const KPasswdServer::AuthInfo *
00504 KPasswdServer::findAuthInfoItem(
const QString &key,
const KIO::AuthInfo &info)
00505 {
00506 AuthInfoList *authList = m_authDict.find(key);
00507
if (!authList)
00508
return 0;
00509
00510
QString path2 = info.
url.
directory(
false,
false);
00511
for(
AuthInfo *current = authList->first();
00512 current; )
00513 {
00514
if ((current->expire == AuthInfo::expTime) &&
00515 (difftime(time(0), current->expireTime) > 0))
00516 {
00517 authList->remove();
00518 current = authList->current();
00519
continue;
00520 }
00521
00522
if (info.
verifyPath)
00523 {
00524
QString path1 = current->directory;
00525
if (path2.
startsWith(path1) &&
00526 (info.
username.
isEmpty() || info.
username == current->
username))
00527
return current;
00528 }
00529
else
00530 {
00531
if (current->
realmValue == info.
realmValue &&
00532 (info.
username.
isEmpty() || info.
username == current->
username))
00533
return current;
00534 }
00535
00536 current = authList->next();
00537 }
00538
return 0;
00539 }
00540
00541
void
00542 KPasswdServer::removeAuthInfoItem(
const QString &key,
const KIO::AuthInfo &info)
00543 {
00544 AuthInfoList *authList = m_authDict.find(key);
00545
if (!authList)
00546
return;
00547
00548
for(
AuthInfo *current = authList->first();
00549 current; )
00550 {
00551
if (current->
realmValue == info.
realmValue)
00552 {
00553 authList->remove();
00554 current = authList->current();
00555 }
00556
else
00557 {
00558 current = authList->next();
00559 }
00560 }
00561
if (authList->isEmpty())
00562 {
00563 m_authDict.remove(key);
00564 }
00565 }
00566
00567
00568
void
00569 KPasswdServer::addAuthInfoItem(
const QString &key,
const KIO::AuthInfo &info,
long windowId,
long seqNr,
bool canceled)
00570 {
00571 AuthInfoList *authList = m_authDict.find(key);
00572
if (!authList)
00573 {
00574 authList =
new AuthInfoList;
00575 m_authDict.insert(key, authList);
00576 }
00577
AuthInfo *current = authList->first();
00578
for(; current; current = authList->next())
00579 {
00580
if (current->
realmValue == info.
realmValue)
00581 {
00582 authList->take();
00583
break;
00584 }
00585 }
00586
00587
if (!current)
00588 {
00589 current =
new AuthInfo;
00590 current->expire = AuthInfo::expTime;
00591
kdDebug(130) <<
"Creating AuthInfo" <<
endl;
00592 }
00593
else
00594 {
00595
kdDebug(130) <<
"Updating AuthInfo" <<
endl;
00596 }
00597
00598 current->
url = info.
url;
00599 current->directory = info.
url.
directory(
false,
false);
00600 current->
username = info.
username;
00601 current->
password = info.
password;
00602 current->
realmValue = info.
realmValue;
00603 current->
digestInfo = info.
digestInfo;
00604 current->seqNr = seqNr;
00605 current->isCanceled = canceled;
00606
00607 updateAuthExpire(key, current, windowId, info.
keepPassword && !canceled);
00608
00609
00610 authList->inSort(current);
00611 }
00612
00613
void
00614 KPasswdServer::updateAuthExpire(
const QString &key,
const AuthInfo *auth,
long windowId,
bool keep)
00615 {
00616
AuthInfo *current = const_cast<AuthInfo *>(auth);
00617
if (keep)
00618 {
00619 current->expire = AuthInfo::expNever;
00620 }
00621
else if (windowId && (current->expire != AuthInfo::expNever))
00622 {
00623 current->expire = AuthInfo::expWindowClose;
00624
if (!current->windowList.contains(windowId))
00625 current->windowList.append(windowId);
00626 }
00627
else if (current->expire == AuthInfo::expTime)
00628 {
00629 current->expireTime = time(0)+10;
00630 }
00631
00632
00633
if (windowId)
00634 {
00635
QStringList *keysChanged = mWindowIdList.find(windowId);
00636
if (!keysChanged)
00637 {
00638 keysChanged =
new QStringList;
00639 mWindowIdList.insert(windowId, keysChanged);
00640 }
00641
if (!keysChanged->contains(key))
00642 keysChanged->append(key);
00643 }
00644 }
00645
00646
void
00647 KPasswdServer::removeAuthForWindowId(
long windowId)
00648 {
00649
QStringList *keysChanged = mWindowIdList.find(windowId);
00650
if (!keysChanged)
return;
00651
00652
for(QStringList::ConstIterator it = keysChanged->begin();
00653 it != keysChanged->end(); ++it)
00654 {
00655
QString key = *it;
00656 AuthInfoList *authList = m_authDict.find(key);
00657
if (!authList)
00658
continue;
00659
00660
AuthInfo *current = authList->first();
00661
for(; current; )
00662 {
00663
if (current->expire == AuthInfo::expWindowClose)
00664 {
00665
if (current->windowList.remove(windowId) && current->windowList.isEmpty())
00666 {
00667 authList->remove();
00668 current = authList->current();
00669
continue;
00670 }
00671 }
00672 current = authList->next();
00673 }
00674 }
00675 }
00676
00677
#include "kpasswdserver.moc"