kio Library API Documentation

kpasswdserver.cpp

00001 /* 00002 This file is part of the KDE Cookie Jar 00003 00004 Copyright (C) 2002 Waldo Bastian (bastian@kde.org) 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 This software is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this library; see the file COPYING. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 00019 */ 00020 //---------------------------------------------------------------------------- 00021 // 00022 // KDE Password Server 00023 // $Id: kpasswdserver.cpp,v 1.19 2003/10/21 11:27:55 faure Exp $ 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 // no login+pass provided, check if kwallet has one 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 // When the user checks "keep password", that means both in the cache (kpasswdserver process) 00278 // and in the wallet, if enabled. 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 // Check all requests in the wait queue. 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 // Generate the basic key sequence. 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; // TODO: Update directory info, 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 // Insert into list, keep the list sorted "longest path" first. 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 // Update mWindowIdList 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"
KDE Logo
This file is part of the documentation for kio Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 20 09:49:14 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003