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 Wed Aug 4 05:25:34 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003