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
00035 #ifdef Q_WS_X11
00036 #include <X11/X.h>
00037 #include <X11/Xlib.h>
00038 #endif
00039
00040 #include "kpasswdserver.h"
00041
00042 extern "C" {
00043 KDEDModule *create_kpasswdserver(const QCString &name)
00044 {
00045 return new KPasswdServer(name);
00046 }
00047 }
00048
00049 int
00050 KPasswdServer::AuthInfoList::compareItems(QPtrCollection::Item n1, QPtrCollection::Item n2)
00051 {
00052 if (!n1 || !n2)
00053 return 0;
00054
00055 AuthInfo *i1 = (AuthInfo *) n1;
00056 AuthInfo *i2 = (AuthInfo *) n2;
00057
00058 int l1 = i1->directory.length();
00059 int l2 = i2->directory.length();
00060
00061 if (l1 > l2)
00062 return -1;
00063 if (l1 < l2)
00064 return 1;
00065 return 0;
00066 }
00067
00068
00069 KPasswdServer::KPasswdServer(const QCString &name)
00070 : KDEDModule(name)
00071 {
00072 m_authDict.setAutoDelete(true);
00073 m_authPending.setAutoDelete(true);
00074 m_seqNr = 0;
00075 connect(this, SIGNAL(windowUnregistered(long)),
00076 this, SLOT(removeAuthForWindowId(long)));
00077 }
00078
00079 KPasswdServer::~KPasswdServer()
00080 {
00081 }
00082
00083 KIO::AuthInfo
00084 KPasswdServer::checkAuthInfo(KIO::AuthInfo info, long windowId)
00085 {
00086 kdDebug(130) << "KPasswdServer::checkAuthInfo: User= " << info.username
00087 << ", WindowId = " << windowId << endl;
00088
00089 QString key = createCacheKey(info);
00090
00091 Request *request = m_authPending.first();
00092 QString path2 = info.url.directory(false, false);
00093 for(; request; request = m_authPending.next())
00094 {
00095 if (request->key != key)
00096 continue;
00097
00098 if (info.verifyPath)
00099 {
00100 QString path1 = request->info.url.directory(false, false);
00101 if (!path2.startsWith(path1))
00102 continue;
00103 }
00104
00105 request = new Request;
00106 request->client = callingDcopClient();
00107 request->transaction = request->client->beginTransaction();
00108 request->key = key;
00109 request->info = info;
00110 m_authWait.append(request);
00111 return info;
00112 }
00113
00114 const AuthInfo *result = findAuthInfoItem(key, info);
00115 if (!result || result->isCanceled)
00116 {
00117 info.setModified(false);
00118 return info;
00119 }
00120
00121 updateAuthExpire(key, result, windowId, false);
00122
00123 return copyAuthInfo(result);
00124 }
00125
00126 KIO::AuthInfo
00127 KPasswdServer::queryAuthInfo(KIO::AuthInfo info, QString errorMsg, long windowId, long seqNr)
00128 {
00129 kdDebug(130) << "KPasswdServer::queryAuthInfo: User= " << info.username
00130 << ", Message= " << info.prompt << ", WindowId = " << windowId << endl;
00131 QString key = createCacheKey(info);
00132 Request *request = new Request;
00133 request->client = callingDcopClient();
00134 request->transaction = request->client->beginTransaction();
00135 request->key = key;
00136 request->info = info;
00137 request->windowId = windowId;
00138 request->seqNr = seqNr;
00139 if (errorMsg == "<NoAuthPrompt>")
00140 {
00141 request->errorMsg = QString::null;
00142 request->prompt = false;
00143 }
00144 else
00145 {
00146 request->errorMsg = errorMsg;
00147 request->prompt = true;
00148 }
00149 m_authPending.append(request);
00150
00151 if (m_authPending.count() == 1)
00152 QTimer::singleShot(0, this, SLOT(processRequest()));
00153
00154 return info;
00155 }
00156
00157 void
00158 KPasswdServer::addAuthInfo(KIO::AuthInfo info, long windowId)
00159 {
00160 kdDebug(130) << "KPasswdServer::addAuthInfo: User= " << info.username
00161 << ", RealmValue= " << info.realmValue << ", WindowId = " << windowId << endl;
00162 QString key = createCacheKey(info);
00163
00164 m_seqNr++;
00165
00166 addAuthInfoItem(key, info, windowId, m_seqNr, false);
00167 }
00168
00169 void
00170 KPasswdServer::processRequest()
00171 {
00172 Request *request = m_authPending.first();
00173 if (!request)
00174 return;
00175
00176 KIO::AuthInfo &info = request->info;
00177
00178 kdDebug(130) << "KPasswdServer::processRequest: User= " << info.username
00179 << ", Message= " << info.prompt << endl;
00180
00181 const AuthInfo *result = findAuthInfoItem(request->key, request->info);
00182
00183 if (result && (request->seqNr < result->seqNr))
00184 {
00185 kdDebug(130) << "KPasswdServer::processRequest: auto retry!" << endl;
00186 if (result->isCanceled)
00187 {
00188 info.setModified(false);
00189 }
00190 else
00191 {
00192 updateAuthExpire(request->key, result, request->windowId, false);
00193 info = copyAuthInfo(result);
00194 }
00195 }
00196 else
00197 {
00198 m_seqNr++;
00199 bool askPw = request->prompt;
00200 if (result && !info.username.isEmpty() &&
00201 !request->errorMsg.isEmpty())
00202 {
00203 QString prompt = request->errorMsg;
00204 prompt += i18n(" Do you want to retry?");
00205 int dlgResult = KMessageBox::warningContinueCancel(0, prompt,
00206 i18n("Authentication"), i18n("Retry"));
00207 if (dlgResult != KMessageBox::Continue)
00208 askPw = false;
00209 }
00210
00211 int dlgResult = QDialog::Rejected;
00212 if (askPw)
00213 {
00214 KIO::PasswordDialog dlg( info.prompt, info.username, info.keepPassword );
00215 if (info.caption.isEmpty())
00216 dlg.setPlainCaption( i18n("Authorization Dialog") );
00217 else
00218 dlg.setPlainCaption( info.caption );
00219
00220 if ( !info.comment.isEmpty() )
00221 dlg.addCommentLine( info.commentLabel, info.comment );
00222
00223 if ( !info.password.isEmpty() )
00224 dlg.setPassword( info.password );
00225
00226 if (info.readOnly)
00227 dlg.setUserReadOnly( true );
00228
00229 XSetTransientForHint( qt_xdisplay(), dlg.winId(), request->windowId);
00230
00231 dlgResult = dlg.exec();
00232
00233 if (dlgResult == QDialog::Accepted)
00234 {
00235 info.username = dlg.username();
00236 info.password = dlg.password();
00237 info.keepPassword = dlg.keepPassword();
00238 }
00239 }
00240 if ( dlgResult != QDialog::Accepted )
00241 {
00242 addAuthInfoItem(request->key, info, 0, m_seqNr, true);
00243 info.setModified( false );
00244 }
00245 else
00246 {
00247 addAuthInfoItem(request->key, info, request->windowId, m_seqNr, false);
00248 info.setModified( true );
00249 }
00250 }
00251
00252 QCString replyType;
00253 QByteArray replyData;
00254
00255 QDataStream stream2(replyData, IO_WriteOnly);
00256 stream2 << info << m_seqNr;
00257 replyType = "KIO::AuthInfo";
00258 request->client->endTransaction( request->transaction,
00259 replyType, replyData);
00260
00261 m_authPending.remove((unsigned int) 0);
00262
00263
00264 for(Request *waitRequest = m_authWait.first();
00265 waitRequest; )
00266 {
00267 bool keepQueued = false;
00268 QString key = waitRequest->key;
00269
00270 request = m_authPending.first();
00271 QString path2 = waitRequest->info.url.directory(false, false);
00272 for(; request; request = m_authPending.next())
00273 {
00274 if (request->key != key)
00275 continue;
00276
00277 if (info.verifyPath)
00278 {
00279 QString path1 = request->info.url.directory(false, false);
00280 if (!path2.startsWith(path1))
00281 continue;
00282 }
00283
00284 keepQueued = true;
00285 break;
00286 }
00287 if (keepQueued)
00288 {
00289 waitRequest = m_authWait.next();
00290 }
00291 else
00292 {
00293 const AuthInfo *result = findAuthInfoItem(waitRequest->key, waitRequest->info);
00294
00295 QCString replyType;
00296 QByteArray replyData;
00297
00298 QDataStream stream2(replyData, IO_WriteOnly);
00299
00300 if (!result || result->isCanceled)
00301 {
00302 waitRequest->info.setModified(false);
00303 stream2 << waitRequest->info;
00304 }
00305 else
00306 {
00307 updateAuthExpire(waitRequest->key, result, waitRequest->windowId, false);
00308 KIO::AuthInfo info = copyAuthInfo(result);
00309 stream2 << info;
00310 }
00311
00312 replyType = "KIO::AuthInfo";
00313 waitRequest->client->endTransaction( waitRequest->transaction,
00314 replyType, replyData);
00315
00316 m_authWait.remove();
00317 waitRequest = m_authWait.current();
00318 }
00319 }
00320
00321 if (m_authPending.count())
00322 QTimer::singleShot(0, this, SLOT(processRequest()));
00323
00324 }
00325
00326 QString KPasswdServer::createCacheKey( const KIO::AuthInfo &info )
00327 {
00328 if( info.url.isMalformed() )
00329 return QString::null;
00330
00331
00332 QString key = info.url.protocol();
00333 key += '-';
00334 if (!info.url.user().isEmpty())
00335 {
00336 key += info.url.user();
00337 key += "@";
00338 }
00339 key += info.url.host();
00340 int port = info.url.port();
00341 if( port )
00342 {
00343 key += ':';
00344 key += QString::number(port);
00345 }
00346
00347 return key;
00348 }
00349
00350 KIO::AuthInfo
00351 KPasswdServer::copyAuthInfo(const AuthInfo *i)
00352 {
00353 KIO::AuthInfo result;
00354 result.url = i->url;
00355 result.username = i->username;
00356 result.password = i->password;
00357 result.realmValue = i->realmValue;
00358 result.digestInfo = i->digestInfo;
00359 result.setModified(true);
00360
00361 return result;
00362 }
00363
00364 const KPasswdServer::AuthInfo *
00365 KPasswdServer::findAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
00366 {
00367 AuthInfoList *authList = m_authDict.find(key);
00368 if (!authList)
00369 return 0;
00370
00371 QString path2 = info.url.directory(false, false);
00372 for(AuthInfo *current = authList->first();
00373 current; )
00374 {
00375 if ((current->expire == AuthInfo::expTime) &&
00376 (difftime(time(0), current->expireTime) > 0))
00377 {
00378 authList->remove();
00379 current = authList->current();
00380 continue;
00381 }
00382
00383 if (info.verifyPath)
00384 {
00385 QString path1 = current->directory;
00386 if (path2.startsWith(path1))
00387 return current;
00388 }
00389 else
00390 {
00391 if (current->realmValue == info.realmValue)
00392 return current;
00393 }
00394
00395 current = authList->next();
00396 }
00397 return 0;
00398 }
00399
00400 void
00401 KPasswdServer::removeAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
00402 {
00403 AuthInfoList *authList = m_authDict.find(key);
00404 if (!authList)
00405 return;
00406
00407 for(AuthInfo *current = authList->first();
00408 current; )
00409 {
00410 if (current->realmValue == info.realmValue)
00411 {
00412 authList->remove();
00413 current = authList->current();
00414 }
00415 else
00416 {
00417 current = authList->next();
00418 }
00419 }
00420 if (authList->isEmpty())
00421 {
00422 m_authDict.remove(key);
00423 }
00424 }
00425
00426
00427 void
00428 KPasswdServer::addAuthInfoItem(const QString &key, const KIO::AuthInfo &info, long windowId, long seqNr, bool canceled)
00429 {
00430 AuthInfoList *authList = m_authDict.find(key);
00431 if (!authList)
00432 {
00433 authList = new AuthInfoList;
00434 m_authDict.insert(key, authList);
00435 }
00436 AuthInfo *current = authList->first();
00437 for(; current; current = authList->next())
00438 {
00439 if (current->realmValue == info.realmValue)
00440 {
00441 authList->take();
00442 break;
00443 }
00444 }
00445
00446 if (!current)
00447 {
00448 current = new AuthInfo;
00449 current->expire = AuthInfo::expTime;
00450 kdDebug(130) << "Creating AuthInfo" << endl;
00451 }
00452 else
00453 {
00454 kdDebug(130) << "Updating AuthInfo" << endl;
00455 }
00456
00457 current->url = info.url;
00458 current->directory = info.url.directory(false, false);
00459 current->username = info.username;
00460 current->password = info.password;
00461 current->realmValue = info.realmValue;
00462 current->digestInfo = info.digestInfo;
00463 current->seqNr = seqNr;
00464 current->isCanceled = canceled;
00465
00466 updateAuthExpire(key, current, windowId, info.keepPassword && !canceled);
00467
00468
00469 authList->inSort(current);
00470 }
00471
00472 void
00473 KPasswdServer::updateAuthExpire(const QString &key, const AuthInfo *auth, long windowId, bool keep)
00474 {
00475 AuthInfo *current = const_cast<AuthInfo *>(auth);
00476 if (keep)
00477 {
00478 current->expire = AuthInfo::expNever;
00479 }
00480 else if (windowId && (current->expire != AuthInfo::expNever))
00481 {
00482 current->expire = AuthInfo::expWindowClose;
00483 if (!current->windowList.contains(windowId))
00484 current->windowList.append(windowId);
00485 }
00486 else if (current->expire == AuthInfo::expTime)
00487 {
00488 current->expireTime = time(0)+10;
00489 }
00490
00491
00492 if (windowId)
00493 {
00494 QStringList *keysChanged = mWindowIdList.find(windowId);
00495 if (!keysChanged)
00496 {
00497 keysChanged = new QStringList;
00498 mWindowIdList.insert(windowId, keysChanged);
00499 }
00500 if (!keysChanged->contains(key))
00501 keysChanged->append(key);
00502 }
00503 }
00504
00505 void
00506 KPasswdServer::removeAuthForWindowId(long windowId)
00507 {
00508 QStringList *keysChanged = mWindowIdList.find(windowId);
00509 if (!keysChanged) return;
00510
00511 for(QStringList::ConstIterator it = keysChanged->begin();
00512 it != keysChanged->end(); ++it)
00513 {
00514 QString key = *it;
00515 AuthInfoList *authList = m_authDict.find(key);
00516 if (!authList)
00517 continue;
00518
00519 AuthInfo *current = authList->first();
00520 for(; current; )
00521 {
00522 if (current->expire == AuthInfo::expWindowClose)
00523 {
00524 if (current->windowList.remove(windowId) && current->windowList.isEmpty())
00525 {
00526 authList->remove();
00527 current = authList->current();
00528 continue;
00529 }
00530 }
00531 current = authList->next();
00532 }
00533 }
00534 }
00535
00536 #include "kpasswdserver.moc"