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 <time.h>
00026
00027
#include <qtimer.h>
00028
00029
#include <kapplication.h>
00030
#include <klocale.h>
00031
#include <kmessagebox.h>
00032
#include <kdebug.h>
00033
#include <kio/passdlg.h>
00034
#include <kwallet.h>
00035
00036
#include "config.h"
00037
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
00038
#include <X11/X.h>
00039
#include <X11/Xlib.h>
00040
#endif
00041
00042
#include "kpasswdserver.h"
00043
00044
extern "C" {
00045 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 info.
setModified(
false);
00120
return info;
00121 }
00122
00123 updateAuthExpire(key, result, windowId,
false);
00124
00125
return copyAuthInfo(result);
00126 }
00127
00128
KIO::AuthInfo
00129 KPasswdServer::queryAuthInfo(
KIO::AuthInfo info,
QString errorMsg,
long windowId,
long seqNr)
00130 {
00131
kdDebug(130) <<
"KPasswdServer::queryAuthInfo: User= " << info.
username
00132 <<
", Message= " << info.
prompt <<
", WindowId = " << windowId <<
endl;
00133
QString key = createCacheKey(info);
00134 Request *request =
new Request;
00135 request->client = callingDcopClient();
00136 request->transaction = request->client->beginTransaction();
00137 request->key =
key;
00138 request->info = info;
00139 request->windowId = windowId;
00140 request->seqNr = seqNr;
00141
if (errorMsg ==
"<NoAuthPrompt>")
00142 {
00143 request->errorMsg = QString::null;
00144 request->
prompt =
false;
00145 }
00146
else
00147 {
00148 request->errorMsg = errorMsg;
00149 request->prompt =
true;
00150 }
00151 m_authPending.
append(request);
00152
00153
if (m_authPending.count() == 1)
00154
QTimer::singleShot(0,
this, SLOT(processRequest()));
00155
00156
return info;
00157 }
00158
00159
void
00160 KPasswdServer::addAuthInfo(
KIO::AuthInfo info,
long windowId)
00161 {
00162
kdDebug(130) <<
"KPasswdServer::addAuthInfo: User= " << info.
username
00163 <<
", RealmValue= " << info.
realmValue <<
", WindowId = " << windowId <<
endl;
00164
QString key = createCacheKey(info);
00165
00166 m_seqNr++;
00167
00168 addAuthInfoItem(key, info, windowId, m_seqNr,
false);
00169 }
00170
00171
void
00172 KPasswdServer::processRequest()
00173 {
00174 Request *request = m_authPending.first();
00175
if (!request)
00176
return;
00177
00178
KIO::AuthInfo &info = request->info;
00179
00180
kdDebug(130) <<
"KPasswdServer::processRequest: User= " << info.
username
00181 <<
", Message= " << info.
prompt <<
endl;
00182
00183
const AuthInfo *result = findAuthInfoItem(request->key, request->info);
00184
00185
if (result && (request->seqNr < result->seqNr))
00186 {
00187
kdDebug(130) <<
"KPasswdServer::processRequest: auto retry!" <<
endl;
00188
if (result->isCanceled)
00189 {
00190 info.
setModified(
false);
00191 }
00192
else
00193 {
00194 updateAuthExpire(request->key, result, request->windowId,
false);
00195 info = copyAuthInfo(result);
00196 }
00197 }
00198
else
00199 {
00200 m_seqNr++;
00201
bool askPw = request->prompt;
00202
if (result && !info.
username.
isEmpty() &&
00203 !request->errorMsg.isEmpty())
00204 {
00205
QString prompt = request->errorMsg;
00206 prompt += i18n(
" Do you want to retry?");
00207
int dlgResult =
KMessageBox::warningContinueCancel(0, prompt,
00208 i18n(
"Authentication"), i18n(
"Retry"));
00209
if (dlgResult != KMessageBox::Continue)
00210 askPw =
false;
00211 }
00212
00213
int dlgResult = QDialog::Rejected;
00214
if (askPw)
00215 {
00216
QString username = info.
username;
00217
QString password = info.
password;
00218
bool hasWalletData =
false;
00219
00220 KWallet::Wallet* wallet = 0;
00221
if ( ( username.
isEmpty() || password.
isEmpty() )
00222 && !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder(), request->key) )
00223 {
00224
00225 wallet = KWallet::Wallet::openWallet(
00226 KWallet::Wallet::NetworkWallet(), request->windowId );
00227
if ( wallet && wallet->hasFolder( KWallet::Wallet::PasswordFolder() ) )
00228 {
00229 wallet->setFolder( KWallet::Wallet::PasswordFolder() );
00230
QMap<QString,QString> map;
00231
if ( wallet->readMap( request->key, map ) == 0 )
00232 {
00233
QMap<QString, QString>::ConstIterator it = map.
find(
"password" );
00234
if ( it != map.
end() )
00235 password = it.data();
00236
00237
if ( !info.
readOnly ) {
00238 it = map.
find(
"login" );
00239
if ( it != map.
end() )
00240 username = it.data();
00241 }
00242 hasWalletData =
true;
00243 }
00244 }
00245 }
00246
00247
KIO::PasswordDialog dlg( info.
prompt, username, info.
keepPassword );
00248
if (info.
caption.
isEmpty())
00249 dlg.
setPlainCaption( i18n(
"Authorization Dialog") );
00250
else
00251 dlg.
setPlainCaption( info.
caption );
00252
00253
if ( !info.
comment.
isEmpty() )
00254 dlg.
addCommentLine( info.
commentLabel, info.
comment );
00255
00256
if ( !password.
isEmpty() )
00257 dlg.
setPassword( password );
00258
00259
if (info.
readOnly)
00260 dlg.
setUserReadOnly(
true );
00261
00262
if (hasWalletData)
00263 dlg.
setKeepPassword(
true );
00264
00265
#if defined Q_WS_X11 && ! defined K_WS_QTONLY
00266
XSetTransientForHint( qt_xdisplay(), dlg.winId(), request->windowId);
00267
#endif
00268
00269 dlgResult = dlg.
exec();
00270
00271
if (dlgResult == QDialog::Accepted)
00272 {
00273 info.
username = dlg.
username();
00274 info.
password = dlg.
password();
00275 info.
keepPassword = dlg.
keepPassword();
00276
00277
00278
00279
if ( info.
keepPassword ) {
00280
if ( !wallet )
00281 wallet = KWallet::Wallet::openWallet(
00282 KWallet::Wallet::NetworkWallet(), request->windowId );
00283
QString password;
00284
if ( wallet ) {
00285
bool ok =
true;
00286
if ( !wallet->hasFolder( KWallet::Wallet::PasswordFolder() ) )
00287 ok = wallet->createFolder( KWallet::Wallet::PasswordFolder() );
00288
if ( ok )
00289 {
00290 wallet->setFolder( KWallet::Wallet::PasswordFolder() );
00291
QMap<QString,QString> map;
00292 map.
insert(
"login", info.
username );
00293 map.
insert(
"password", info.
password );
00294 wallet->writeMap( request->key, map );
00295 }
00296 }
00297 }
00298 }
00299
delete wallet;
00300 }
00301
if ( dlgResult != QDialog::Accepted )
00302 {
00303 addAuthInfoItem(request->key, info, 0, m_seqNr,
true);
00304 info.
setModified(
false );
00305 }
00306
else
00307 {
00308 addAuthInfoItem(request->key, info, request->windowId, m_seqNr,
false);
00309 info.
setModified(
true );
00310 }
00311 }
00312
00313
QCString replyType;
00314
QByteArray replyData;
00315
00316
QDataStream stream2(replyData, IO_WriteOnly);
00317 stream2 << info << m_seqNr;
00318 replyType =
"KIO::AuthInfo";
00319 request->client->endTransaction( request->transaction,
00320 replyType, replyData);
00321
00322 m_authPending.remove((
unsigned int) 0);
00323
00324
00325
for(Request *waitRequest = m_authWait.first();
00326 waitRequest; )
00327 {
00328
bool keepQueued =
false;
00329
QString key = waitRequest->key;
00330
00331 request = m_authPending.first();
00332
QString path2 = waitRequest->info.url.directory(
false,
false);
00333
for(; request; request = m_authPending.next())
00334 {
00335
if (request->key !=
key)
00336
continue;
00337
00338
if (info.
verifyPath)
00339 {
00340
QString path1 = request->info.url.directory(
false,
false);
00341
if (!path2.
startsWith(path1))
00342
continue;
00343 }
00344
00345 keepQueued =
true;
00346
break;
00347 }
00348
if (keepQueued)
00349 {
00350 waitRequest = m_authWait.next();
00351 }
00352
else
00353 {
00354
const AuthInfo *result = findAuthInfoItem(waitRequest->key, waitRequest->info);
00355
00356
QCString replyType;
00357
QByteArray replyData;
00358
00359
QDataStream stream2(replyData, IO_WriteOnly);
00360
00361
if (!result || result->isCanceled)
00362 {
00363 waitRequest->info.setModified(
false);
00364 stream2 << waitRequest->info;
00365 }
00366
else
00367 {
00368 updateAuthExpire(waitRequest->key, result, waitRequest->windowId,
false);
00369
KIO::AuthInfo info = copyAuthInfo(result);
00370 stream2 << info;
00371 }
00372
00373 replyType =
"KIO::AuthInfo";
00374 waitRequest->client->endTransaction( waitRequest->transaction,
00375 replyType, replyData);
00376
00377 m_authWait.remove();
00378 waitRequest = m_authWait.current();
00379 }
00380 }
00381
00382
if (m_authPending.count())
00383
QTimer::singleShot(0,
this, SLOT(processRequest()));
00384
00385 }
00386
00387
QString KPasswdServer::createCacheKey(
const KIO::AuthInfo &info )
00388 {
00389
if( !info.
url.
isValid() )
00390
return QString::null;
00391
00392
00393
QString key = info.
url.
protocol();
00394
key +=
'-';
00395
if (!info.
url.
user().
isEmpty())
00396 {
00397
key += info.
url.
user();
00398
key +=
"@";
00399 }
00400
key += info.
url.
host();
00401
int port = info.
url.
port();
00402
if( port )
00403 {
00404
key +=
':';
00405
key +=
QString::number(port);
00406 }
00407
00408
return key;
00409 }
00410
00411
KIO::AuthInfo
00412 KPasswdServer::copyAuthInfo(
const AuthInfo *i)
00413 {
00414
KIO::AuthInfo result;
00415 result.
url = i->
url;
00416 result.
username = i->
username;
00417 result.
password = i->
password;
00418 result.
realmValue = i->
realmValue;
00419 result.
digestInfo = i->
digestInfo;
00420 result.
setModified(
true);
00421
00422
return result;
00423 }
00424
00425
const KPasswdServer::AuthInfo *
00426 KPasswdServer::findAuthInfoItem(
const QString &key,
const KIO::AuthInfo &info)
00427 {
00428 AuthInfoList *authList = m_authDict.find(key);
00429
if (!authList)
00430
return 0;
00431
00432
QString path2 = info.
url.
directory(
false,
false);
00433
for(
AuthInfo *current = authList->first();
00434 current; )
00435 {
00436
if ((current->expire == AuthInfo::expTime) &&
00437 (difftime(time(0), current->expireTime) > 0))
00438 {
00439 authList->remove();
00440 current = authList->current();
00441
continue;
00442 }
00443
00444
if (info.
verifyPath)
00445 {
00446
QString path1 = current->directory;
00447
if (path2.
startsWith(path1) &&
00448 (info.
username.
isEmpty() || info.
username == current->
username))
00449
return current;
00450 }
00451
else
00452 {
00453
if (current->
realmValue == info.
realmValue &&
00454 (info.
username.
isEmpty() || info.
username == current->
username))
00455
return current;
00456 }
00457
00458 current = authList->next();
00459 }
00460
return 0;
00461 }
00462
00463
void
00464 KPasswdServer::removeAuthInfoItem(
const QString &key,
const KIO::AuthInfo &info)
00465 {
00466 AuthInfoList *authList = m_authDict.find(key);
00467
if (!authList)
00468
return;
00469
00470
for(
AuthInfo *current = authList->first();
00471 current; )
00472 {
00473
if (current->
realmValue == info.
realmValue)
00474 {
00475 authList->remove();
00476 current = authList->current();
00477 }
00478
else
00479 {
00480 current = authList->next();
00481 }
00482 }
00483
if (authList->isEmpty())
00484 {
00485 m_authDict.remove(key);
00486 }
00487 }
00488
00489
00490
void
00491 KPasswdServer::addAuthInfoItem(
const QString &key,
const KIO::AuthInfo &info,
long windowId,
long seqNr,
bool canceled)
00492 {
00493 AuthInfoList *authList = m_authDict.find(key);
00494
if (!authList)
00495 {
00496 authList =
new AuthInfoList;
00497 m_authDict.insert(key, authList);
00498 }
00499
AuthInfo *current = authList->first();
00500
for(; current; current = authList->next())
00501 {
00502
if (current->
realmValue == info.
realmValue)
00503 {
00504 authList->take();
00505
break;
00506 }
00507 }
00508
00509
if (!current)
00510 {
00511 current =
new AuthInfo;
00512 current->expire = AuthInfo::expTime;
00513
kdDebug(130) <<
"Creating AuthInfo" <<
endl;
00514 }
00515
else
00516 {
00517
kdDebug(130) <<
"Updating AuthInfo" <<
endl;
00518 }
00519
00520 current->
url = info.
url;
00521 current->directory = info.
url.
directory(
false,
false);
00522 current->
username = info.
username;
00523 current->
password = info.
password;
00524 current->
realmValue = info.
realmValue;
00525 current->
digestInfo = info.
digestInfo;
00526 current->seqNr = seqNr;
00527 current->isCanceled = canceled;
00528
00529 updateAuthExpire(key, current, windowId, info.
keepPassword && !canceled);
00530
00531
00532 authList->inSort(current);
00533 }
00534
00535
void
00536 KPasswdServer::updateAuthExpire(
const QString &key,
const AuthInfo *auth,
long windowId,
bool keep)
00537 {
00538
AuthInfo *current = const_cast<AuthInfo *>(auth);
00539
if (keep)
00540 {
00541 current->expire = AuthInfo::expNever;
00542 }
00543
else if (windowId && (current->expire != AuthInfo::expNever))
00544 {
00545 current->expire = AuthInfo::expWindowClose;
00546
if (!current->windowList.contains(windowId))
00547 current->windowList.append(windowId);
00548 }
00549
else if (current->expire == AuthInfo::expTime)
00550 {
00551 current->expireTime = time(0)+10;
00552 }
00553
00554
00555
if (windowId)
00556 {
00557
QStringList *keysChanged = mWindowIdList.find(windowId);
00558
if (!keysChanged)
00559 {
00560 keysChanged =
new QStringList;
00561 mWindowIdList.insert(windowId, keysChanged);
00562 }
00563
if (!keysChanged->contains(key))
00564 keysChanged->append(key);
00565 }
00566 }
00567
00568
void
00569 KPasswdServer::removeAuthForWindowId(
long windowId)
00570 {
00571
QStringList *keysChanged = mWindowIdList.find(windowId);
00572
if (!keysChanged)
return;
00573
00574
for(QStringList::ConstIterator it = keysChanged->begin();
00575 it != keysChanged->end(); ++it)
00576 {
00577
QString key = *it;
00578 AuthInfoList *authList = m_authDict.find(key);
00579
if (!authList)
00580
continue;
00581
00582
AuthInfo *current = authList->first();
00583
for(; current; )
00584 {
00585
if (current->expire == AuthInfo::expWindowClose)
00586 {
00587
if (current->windowList.remove(windowId) && current->windowList.isEmpty())
00588 {
00589 authList->remove();
00590 current = authList->current();
00591
continue;
00592 }
00593 }
00594 current = authList->next();
00595 }
00596 }
00597 }
00598
00599
#include "kpasswdserver.moc"