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 += "@";
}
key += info.url.host();
int port = info.url.port();
if( port )
{
key += ':';
key += QString::number(port);
}
return key;
}
KIO::AuthInfo
KPasswdServer::copyAuthInfo(const AuthInfo *i)
{
KIO::AuthInfo result;
result.url = i->url;
result.username = i->username;
result.password = i->password;
result.realmValue = i->realmValue;
result.digestInfo = i->digestInfo;
result.setModified(true);
return result;
}
const KPasswdServer::AuthInfo *
KPasswdServer::findAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
{
AuthInfoList *authList = m_authDict.find(key);
if (!authList)
return 0;
QString path2 = info.url.directory(false, false);
for(AuthInfo *current = authList->first();
current; )
{
if ((current->expire == AuthInfo::expTime) &&
(difftime(time(0), current->expireTime) > 0))
{
authList->remove();
current = authList->current();
continue;
}
if (info.verifyPath)
{
QString path1 = current->directory;
if (path2.startsWith(path1) &&
(info.username.isEmpty() || info.username == current->username))
return current;
}
else
{
if (current->realmValue == info.realmValue &&
(info.username.isEmpty() || info.username == current->username))
return current; // TODO: Update directory info,
}
current = authList->next();
}
return 0;
}
void
KPasswdServer::removeAuthInfoItem(const QString &key, const KIO::AuthInfo &info)
{
AuthInfoList *authList = m_authDict.find(key);
if (!authList)
return;
for(AuthInfo *current = authList->first();
current; )
{
if (current->realmValue == info.realmValue)
{
authList->remove();
current = authList->current();
}
else
{
current = authList->next();
}
}
if (authList->isEmpty())
{
m_authDict.remove(key);
}
}
void
KPasswdServer::addAuthInfoItem(const QString &key, const KIO::AuthInfo &info, long windowId, long seqNr, bool canceled)
{
AuthInfoList *authList = m_authDict.find(key);
if (!authList)
{
authList = new AuthInfoList;
m_authDict.insert(key, authList);
}
AuthInfo *current = authList->first();
for(; current; current = authList->next())
{
if (current->realmValue == info.realmValue)
{
authList->take();
break;
}
}
if (!current)
{
current = new AuthInfo;
current->expire = AuthInfo::expTime;
kdDebug(130) << "Creating AuthInfo" << endl;
00399 }
00400 else
00401 {
00402 kdDebug(130) << "Updating AuthInfo" << endl;
00403 }
00404
00405 current->url = info.url;
00406 current->directory = info.url.directory(false, false);
00407 current->username = info.username;
00408 current->password = info.password;
00409 current->realmValue = info.realmValue;
00410 current->digestInfo = info.digestInfo;
00411 current->seqNr = seqNr;
00412 current->isCanceled = canceled;
00413
00414 updateAuthExpire(key, current, windowId, info.keepPassword && !canceled);
00415
00416
00417 authList->inSort(current);
00418 }
00419
00420 void
00421 KPasswdServer::updateAuthExpire(const QString &key, const AuthInfo *auth, long windowId, bool keep)
00422 {
00423 AuthInfo *current = const_cast<AuthInfo *>(auth);
00424 if (keep)
00425 {
00426 current->expire = AuthInfo::expNever;
00427 }
00428 else if (windowId && (current->expire != AuthInfo::expNever))
00429 {
00430 current->expire = AuthInfo::expWindowClose;
00431 if (!current->windowList.contains(windowId))
00432 current->windowList.append(windowId);
00433 }
00434 else if (current->expire == AuthInfo::expTime)
00435 {
00436 current->expireTime = time(0)+10;
00437 }
00438
00439
00440 if (windowId)
00441 {
00442 QStringList *keysChanged = mWindowIdList.find(windowId);
00443 if (!keysChanged)
00444 {
00445 keysChanged = new QStringList;
00446 mWindowIdList.insert(windowId, keysChanged);
00447 }
00448 if (!keysChanged->contains(key))
00449 keysChanged->append(key);
00450 }
00451 }
00452
00453 void
00454 KPasswdServer::removeAuthForWindowId(long windowId)
00455 {
00456 QStringList *keysChanged = mWindowIdList.find(windowId);
00457 if (!keysChanged) return;
00458
00459 for(QStringList::ConstIterator it = keysChanged->begin();
00460 it != keysChanged->end(); ++it)
00461 {
00462 QString key = *it;
00463 AuthInfoList *authList = m_authDict.find(key);
00464 if (!authList)
00465 continue;
00466
00467 AuthInfo *current = authList->first();
00468 for(; current; )
00469 {
00470 if (current->expire == AuthInfo::expWindowClose)
00471 {
00472 if (current->windowList.remove(windowId) && current->windowList.isEmpty())
00473 {
00474 authList->remove();
00475 current = authList->current();
00476 continue;
00477 }
00478 }
00479 current = authList->next();
00480 }
00481 }
00482 }
00483
00484 #include "kpasswdserver.moc"
00485