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.5.2.3 2003/05/17 11:19:24 mueller 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 
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     // Check all requests in the wait queue.
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     // Generate the basic key sequence.
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; // TODO: Update directory info, 
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    // Insert into list, keep the list sorted "longest path" first.
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    // Update mWindowIdList
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"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:31 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001