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() << "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() << "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 request->errorMsg = errorMsg;
00140 m_authPending.append(request);
00141
00142 if (m_authPending.count() == 1)
00143 QTimer::singleShot(0, this, SLOT(processRequest()));
00144
00145 return info;
00146 }
00147
00148 void
00149 KPasswdServer::addAuthInfo(KIO::AuthInfo info, long windowId)
00150 {
00151 kdDebug() << "KPasswdServer::addAuthInfo: User= " << info.username
00152 << ", RealmValue= " << info.realmValue << ", WindowId = " << windowId << endl;
00153 QString key = createCacheKey(info);
00154
00155 m_seqNr++;
00156
00157 addAuthInfoItem(key, info, windowId, m_seqNr, false);
00158 }
00159
00160 void
00161 KPasswdServer::processRequest()
00162 {
00163 Request *request = m_authPending.first();
00164 if (!request)
00165 return;
00166
00167 KIO::AuthInfo &info = request->info;
00168
00169 kdDebug() << "KPasswdServer::processRequest: User= " << info.username
00170 << ", Message= " << info.prompt << endl;
00171
00172 const AuthInfo *result = findAuthInfoItem(request->key, request->info);
00173
00174 if (result && (request->seqNr < result->seqNr))
00175 {
00176 kdDebug() << "KPasswdServer::processRequest: auto retry!" << endl;
00177 if (result->isCanceled)
00178 {
00179 info.setModified(false);
00180 }
00181 else
00182 {
00183 updateAuthExpire(request->key, result, request->windowId, false);
00184 info = copyAuthInfo(result);
00185 }
00186 }
00187 else
00188 {
00189 m_seqNr++;
00190 bool askPw = true;
00191 if (result && !info.username.isEmpty() &&
00192 !request->errorMsg.isEmpty())
00193 {
00194 QString prompt = request->errorMsg;
00195 prompt += i18n(" Do you want to retry?");
00196 int dlgResult = KMessageBox::warningContinueCancel(0, prompt,
00197 i18n("Authentication"), i18n("Retry"));
00198 if (dlgResult != KMessageBox::Continue)
00199 askPw = false;
00200 }
00201
00202 int dlgResult = QDialog::Rejected;
00203 if (askPw)
00204 {
00205 KIO::PasswordDialog dlg( info.prompt, info.username, info.keepPassword );
00206 if (info.caption.isEmpty())
00207 dlg.setPlainCaption( i18n("Authorization Dialog") );
00208 else
00209 dlg.setPlainCaption( info.caption );
00210
00211 if ( !info.comment.isEmpty() )
00212 dlg.addCommentLine( info.commentLabel, info.comment );
00213
00214 if ( !info.password.isEmpty() )
00215 dlg.setPassword( info.password );
00216
00217 if (info.readOnly)
00218 dlg.setUserReadOnly( true );
00219
00220 XSetTransientForHint( qt_xdisplay(), dlg.winId(), request->windowId);
00221
00222 dlgResult = dlg.exec();
00223
00224 if (dlgResult == QDialog::Accepted)
00225 {
00226 info.username = dlg.username();
00227 info.password = dlg.password();
00228 info.keepPassword = dlg.keepPassword();
00229 }
00230 }
00231 if ( dlgResult != QDialog::Accepted )
00232 {
00233 addAuthInfoItem(request->key, info, 0, m_seqNr, true);
00234 info.setModified( false );
00235 }
00236 else
00237 {
00238 addAuthInfoItem(request->key, info, request->windowId, m_seqNr, false);
00239 info.setModified( true );
00240 }
00241 }
00242
00243 QCString replyType;
00244 QByteArray replyData;
00245
00246 QDataStream stream2(replyData, IO_WriteOnly);
00247 stream2 << info << m_seqNr;
00248 replyType = "KIO::AuthInfo";
00249 request->client->endTransaction( request->transaction,
00250 replyType, replyData);
00251
00252 m_authPending.remove((unsigned int) 0);
00253
00254
00255 for(Request *waitRequest = m_authWait.first();
00256 waitRequest; )
00257 {
00258 bool keepQueued = false;
00259 QString key = waitRequest->key;
00260
00261 request = m_authPending.first();
00262 QString path2 = waitRequest->info.url.directory(false, false);
00263 for(; request; request = m_authPending.next())
00264 {
00265 if (request->key != key)
00266 continue;
00267
00268 if (info.verifyPath)
00269 {
00270 QString path1 = request->info.url.directory(false, false);
00271 if (!path2.startsWith(path1))
00272 continue;
00273 }
00274
00275 keepQueued = true;
00276 break;
00277 }
00278 if (keepQueued)
00279 {
00280 waitRequest = m_authWait.next();
00281 }
00282 else
00283 {
00284 const AuthInfo *result = findAuthInfoItem(waitRequest->key, waitRequest->info);
00285
00286 QCString replyType;
00287 QByteArray replyData;
00288
00289 QDataStream stream2(replyData, IO_WriteOnly);
00290
00291 if (!result || result->isCanceled)
00292 {
00293 waitRequest->info.setModified(false);
00294 stream2 << waitRequest->info;
00295 }
00296 else
00297 {
00298 updateAuthExpire(waitRequest->key, result, waitRequest->windowId, false);
00299 KIO::AuthInfo info = copyAuthInfo(result);
00300 stream2 << info;
00301 }
00302
00303 replyType = "KIO::AuthInfo";
00304 waitRequest->client->endTransaction( waitRequest->transaction,
00305 replyType, replyData);
00306
00307 m_authWait.remove();
00308 waitRequest = m_authWait.current();
00309 }
00310 }
00311
00312 if (m_authPending.count())
00313 QTimer::singleShot(0, this, SLOT(processRequest()));
00314
00315 }
00316
00317 QString KPasswdServer::createCacheKey( const KIO::AuthInfo &info )
00318 {
00319 if( info.url.isMalformed() )
00320 return QString::null;
00321
00322
00323 QString key = info.url.protocol();
00324 key += '-';
00325 if (!info.url.user().isEmpty())
00326 {
00327 key += info.url.user();
00328 key += "@";
00329 }
00330 key += info.url.host();
00331 int port = info.url.port();
00332 if( port )
00333 {
00334 key += ':';
00335 key += QString::number(port);
00336 }
00337
00338 return key;
00339 }
00340
00341 KIO::AuthInfo
00342 KPasswdServer::copyAuthInfo(const AuthInfo *i)
00343 {
00344 KIO::AuthInfo result;
00345 result.url = i->url;
00346 result.username = i->username;
00347 result.password = i->password;
00348 result.realmValue = i->realmValue;
00349 result.digestInfo = i->digestInfo;
00350 result.setModified(true);
00351
00352 return result;
00353 }
00354
00355 const KPasswdServer::AuthInfo *
00356 KPasswdServer::findAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
00357 {
00358 AuthInfoList *authList = m_authDict.find(key);
00359 if (!authList)
00360 return 0;
00361
00362 QString path2 = info.url.directory(false, false);
00363 for(AuthInfo *current = authList->first();
00364 current; )
00365 {
00366 if ((current->expire == AuthInfo::expTime) &&
00367 (difftime(time(0), current->expireTime) > 0))
00368 {
00369 authList->remove();
00370 current = authList->current();
00371 continue;
00372 }
00373
00374 if (info.verifyPath)
00375 {
00376 QString path1 = current->directory;
00377 if (path2.startsWith(path1))
00378 return current;
00379 }
00380 else
00381 {
00382 if (current->realmValue == info.realmValue)
00383 return current;
00384 }
00385
00386 current = authList->next();
00387 }
00388 return 0;
00389 }
00390
00391 void
00392 KPasswdServer::removeAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
00393 {
00394 AuthInfoList *authList = m_authDict.find(key);
00395 if (!authList)
00396 return;
00397
00398 for(AuthInfo *current = authList->first();
00399 current; )
00400 {
00401 if (current->realmValue == info.realmValue)
00402 {
00403 authList->remove();
00404 current = authList->current();
00405 }
00406 else
00407 {
00408 current = authList->next();
00409 }
00410 }
00411 if (authList->isEmpty())
00412 {
00413 m_authDict.remove(key);
00414 }
00415 }
00416
00417
00418 void
00419 KPasswdServer::addAuthInfoItem(const QString &key, const KIO::AuthInfo &info, long windowId, long seqNr, bool canceled)
00420 {
00421 AuthInfoList *authList = m_authDict.find(key);
00422 if (!authList)
00423 {
00424 authList = new AuthInfoList;
00425 m_authDict.insert(key, authList);
00426 }
00427 AuthInfo *current = authList->first();
00428 for(; current; current = authList->next())
00429 {
00430 if (current->realmValue == info.realmValue)
00431 {
00432 authList->take();
00433 break;
00434 }
00435 }
00436
00437 if (!current)
00438 {
00439 current = new AuthInfo;
00440 current->expire = AuthInfo::expTime;
00441 kdDebug() << "Creating AuthInfo" << endl;
00442 }
00443 else
00444 {
00445 kdDebug() << "Updating AuthInfo" << endl;
00446 }
00447
00448 current->url = info.url;
00449 current->directory = info.url.directory(false, false);
00450 current->username = info.username;
00451 current->password = info.password;
00452 current->realmValue = info.realmValue;
00453 current->digestInfo = info.digestInfo;
00454 current->seqNr = seqNr;
00455 current->isCanceled = canceled;
00456
00457 updateAuthExpire(key, current, windowId, info.keepPassword && !canceled);
00458
00459
00460 authList->inSort(current);
00461 }
00462
00463 void
00464 KPasswdServer::updateAuthExpire(const QString &key, const AuthInfo *auth, long windowId, bool keep)
00465 {
00466 AuthInfo *current = const_cast<AuthInfo *>(auth);
00467 if (keep)
00468 {
00469 current->expire = AuthInfo::expNever;
00470 }
00471 else if (windowId && (current->expire != AuthInfo::expNever))
00472 {
00473 current->expire = AuthInfo::expWindowClose;
00474 if (!current->windowList.contains(windowId))
00475 current->windowList.append(windowId);
00476 }
00477 else if (current->expire == AuthInfo::expTime)
00478 {
00479 current->expireTime = time(0)+10;
00480 }
00481
00482
00483 if (windowId)
00484 {
00485 QStringList *keysChanged = mWindowIdList.find(windowId);
00486 if (!keysChanged)
00487 {
00488 keysChanged = new QStringList;
00489 mWindowIdList.insert(windowId, keysChanged);
00490 }
00491 if (!keysChanged->contains(key))
00492 keysChanged->append(key);
00493 }
00494 }
00495
00496 void
00497 KPasswdServer::removeAuthForWindowId(long windowId)
00498 {
00499 QStringList *keysChanged = mWindowIdList.find(windowId);
00500 if (!keysChanged) return;
00501
00502 for(QStringList::ConstIterator it = keysChanged->begin();
00503 it != keysChanged->end(); ++it)
00504 {
00505 QString key = *it;
00506 AuthInfoList *authList = m_authDict.find(key);
00507 if (!authList)
00508 continue;
00509
00510 AuthInfo *current = authList->first();
00511 for(; current; )
00512 {
00513 if (current->expire == AuthInfo::expWindowClose)
00514 {
00515 if (current->windowList.remove(windowId) && current->windowList.isEmpty())
00516 {
00517 authList->remove();
00518 current = authList->current();
00519 continue;
00520 }
00521 }
00522 current = authList->next();
00523 }
00524 }
00525 }
00526
00527 #include "kpasswdserver.moc"