File indexing completed on 2024-04-14 15:05:31

0001 /***************************************************************************
0002     This is the wallet manager of Smb4K.
0003                              -------------------
0004     begin                : Sa Dez 27 2008
0005     copyright            : (C) 2008-2019 by Alexander Reinholdt
0006     email                : alexander.reinholdt@kdemail.net
0007  ***************************************************************************/
0008 
0009 /***************************************************************************
0010  *   This program is free software; you can redistribute it and/or modify  *
0011  *   it under the terms of the GNU General Public License as published by  *
0012  *   the Free Software Foundation; either version 2 of the License, or     *
0013  *   (at your option) any later version.                                   *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful, but   *
0016  *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
0018  *   General Public License for more details.                              *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program; if not, write to the                         *
0022  *   Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston,*
0023  *   MA 02110-1335, USA                                                    *
0024  ***************************************************************************/
0025 
0026 #ifdef HAVE_CONFIG_H
0027 #include <config.h>
0028 #endif
0029 
0030 // application specific includes
0031 #include "smb4kwalletmanager.h"
0032 #include "smb4kwalletmanager_p.h"
0033 #include "smb4ksettings.h"
0034 #include "smb4kauthinfo.h"
0035 #include "smb4khomesshareshandler.h"
0036 #include "smb4kglobal.h"
0037 #include "smb4knotification.h"
0038 #include "smb4khost.h"
0039 #include "smb4kshare.h"
0040 
0041 // Qt includes
0042 #include <QPointer>
0043 #include <QTest>
0044 #include <QApplication>
0045 
0046 // KDE includes
0047 
0048 using namespace Smb4KGlobal;
0049 
0050 Q_GLOBAL_STATIC(Smb4KWalletManagerStatic, p);
0051 
0052 
0053 
0054 Smb4KWalletManager::Smb4KWalletManager(QObject *parent)
0055 : QObject(parent), d(new Smb4KWalletManagerPrivate)
0056 {
0057   d->wallet = 0;
0058 }
0059 
0060 
0061 Smb4KWalletManager::~Smb4KWalletManager()
0062 {
0063 }
0064 
0065 
0066 Smb4KWalletManager *Smb4KWalletManager::self()
0067 {
0068   return &p->instance;
0069 }
0070 
0071 
0072 void Smb4KWalletManager::init()
0073 {
0074   if (useWalletSystem())
0075   {
0076     //
0077     // Get a pointer to the wallet, if we do not have one yet
0078     // 
0079     if (!d->wallet)
0080     {
0081       //
0082       // Open the wallet synchronously.
0083       // 
0084       d->wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), QApplication::activeWindow() ? QApplication::activeWindow()->winId() : 0);
0085       
0086       //
0087       // Check if the walled was opened successfully and set the
0088       // right folder, if it was
0089       // 
0090       if (d->wallet)
0091       {
0092         if (d->wallet->isOpen())
0093         {
0094           if (!d->wallet->hasFolder("Smb4K"))
0095           {
0096             d->wallet->createFolder("Smb4K");
0097             d->wallet->setFolder("Smb4K");
0098           }
0099           else
0100           {
0101             d->wallet->setFolder("Smb4K");
0102           }
0103         }
0104         else
0105         {
0106           Smb4KNotification::credentialsNotAccessible();
0107         }
0108       }
0109       else
0110       {
0111         delete d->wallet;
0112         d->wallet = 0;
0113         
0114         Smb4KNotification::openingWalletFailed(KWallet::Wallet::NetworkWallet());
0115       }
0116     }
0117   }
0118   else
0119   {
0120     if (d->wallet)
0121     {
0122       //
0123       // Close the wallet, if Smb4K is the only application that 
0124       // is using it. Thus, use force=false, otherwise it will definitely
0125       // be closed.
0126       //
0127       d->wallet->closeWallet(KWallet::Wallet::NetworkWallet(), false);
0128       
0129       //
0130       // Delete the wallet and set it to 0.
0131       // 
0132       delete d->wallet;
0133       d->wallet = 0;
0134     }
0135   }
0136   
0137   emit initialized();
0138 }
0139 
0140 
0141 void Smb4KWalletManager::readAuthInfo(const NetworkItemPtr &networkItem)
0142 {
0143   //
0144   // Only do something, if the networkItem is not null
0145   // 
0146   if (networkItem)
0147   {
0148     //
0149     // Initialize the wallet manager. 
0150     // 
0151     init();
0152     
0153     //
0154     // Proceed if the wallet is open
0155     // 
0156     if (walletIsOpen())
0157     {
0158       //
0159       // Get the list of entries
0160       // 
0161       QStringList entryList = d->wallet->entryList();
0162       
0163       //
0164       // Create the map to store the authentication information
0165       // 
0166       QMap<QString, QString> authInfoMap;
0167       
0168       //
0169       // Now loop through the stored credentials and make a case insensitive comparison 
0170       // with the URL of the network item.
0171       // 
0172       for (const QString &entry : entryList)
0173       {
0174         if (networkItem->type() == Host)
0175         {
0176           if (QString::compare(entry, networkItem->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0 ||
0177               QString::compare(entry, networkItem->url().toString(QUrl::RemoveScheme|QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0)
0178           {
0179             d->wallet->readMap(entry, authInfoMap);
0180             break;
0181           }
0182         }
0183         else if (networkItem->type() == Share)
0184         {
0185           //
0186           // Cast the network item. We need some share specific info
0187           // 
0188           SharePtr share = networkItem.staticCast<Smb4KShare>();
0189           
0190           if (share)
0191           {
0192             //
0193             // Process normal and 'homes' shares differently
0194             // 
0195             if (!share->isHomesShare())
0196             {
0197               //
0198               // Prefer the credentials for the share. Use the ones for the 
0199               // host as fallback.
0200               //
0201               if (QString::compare(entry, share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0 ||
0202                   QString::compare(entry, share->url().toString(QUrl::RemoveScheme|QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0)
0203               {
0204                 d->wallet->readMap(entry, authInfoMap);
0205                 break;
0206               }
0207               else if (QString::compare(entry, share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::RemovePath), Qt::CaseInsensitive) == 0 ||
0208                        QString::compare(entry, share->url().toString(QUrl::RemoveScheme|QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::RemovePath), Qt::CaseInsensitive) == 0)
0209               {
0210                 d->wallet->readMap(entry, authInfoMap);
0211               }
0212             }
0213             else
0214             {
0215               //
0216               // Prefer the credentials for the share. Use the ones for the 
0217               // host as fallback.
0218               //
0219               if (QString::compare(entry, share->homeUrl().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0 ||
0220                   QString::compare(entry, share->homeUrl().toString(QUrl::RemoveScheme|QUrl::RemoveUserInfo|QUrl::RemovePort), Qt::CaseInsensitive) == 0)
0221               {
0222                 d->wallet->readMap(entry, authInfoMap);
0223                 break;
0224               }
0225               else if (QString::compare(entry, share->homeUrl().toString(QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::RemovePath), Qt::CaseInsensitive) == 0 ||
0226                        QString::compare(entry, share->homeUrl().toString(QUrl::RemoveScheme|QUrl::RemoveUserInfo|QUrl::RemovePort|QUrl::RemovePath), Qt::CaseInsensitive) == 0)
0227               {
0228                 d->wallet->readMap(entry, authInfoMap);
0229               }
0230             }
0231           }
0232         }
0233       }
0234       
0235       //
0236       // Set the authentication information
0237       // 
0238       if (!authInfoMap.isEmpty())
0239       {
0240         switch (networkItem->type())
0241         {
0242           case Host:
0243           {
0244             HostPtr host = networkItem.staticCast<Smb4KHost>();
0245             
0246             if (QString::compare(host->workgroupName(), authInfoMap.value("Workgroup"), Qt::CaseInsensitive) == 0)
0247             {
0248               host->setLogin(authInfoMap.value("Login"));
0249               host->setPassword(authInfoMap.value("Password"));
0250             }
0251             
0252             break;
0253           }
0254           case Share:
0255           {
0256             SharePtr share = networkItem.staticCast<Smb4KShare>();
0257             
0258             if (QString::compare(share->workgroupName(), authInfoMap.value("Workgroup"), Qt::CaseInsensitive) == 0)
0259             {
0260               share->setLogin(authInfoMap.value("Login"));
0261               share->setPassword(authInfoMap.value("Password"));
0262             }
0263             
0264             break;
0265           }
0266           default:
0267           {
0268             break;
0269           }
0270         }
0271       }
0272       else
0273       {
0274         //
0275         // In case the map is empty, set the default login, if it is to be used
0276         // 
0277         if (Smb4KSettings::useDefaultLogin())
0278         {
0279           d->wallet->readMap("DEFAULT_LOGIN", authInfoMap);
0280           
0281           switch (networkItem->type())
0282           {
0283             case Host:
0284             {
0285               HostPtr host = networkItem.staticCast<Smb4KHost>();
0286               host->setLogin(authInfoMap.value("Login"));
0287               host->setPassword(authInfoMap.value("Password"));
0288               
0289               break;
0290             }
0291             case Share:
0292             {
0293               SharePtr share = networkItem.staticCast<Smb4KShare>();
0294               share->setLogin(authInfoMap.value("Login"));
0295               share->setPassword(authInfoMap.value("Password"));
0296               
0297               break;
0298             }
0299             default:
0300             {
0301               break;
0302             }
0303           }
0304         }
0305       }
0306     }
0307   }
0308 }
0309 
0310 
0311 void Smb4KWalletManager::readDefaultAuthInfo(Smb4KAuthInfo *authInfo)
0312 {
0313   if (authInfo)
0314   {
0315     //
0316     // Initialize the wallet manager.
0317     // 
0318     init();
0319     
0320     if (walletIsOpen())
0321     {
0322       //
0323       // Read the default authentication information from the
0324       // wallet.
0325       // 
0326       QMap<QString, QString> authInfoMap;
0327       d->wallet->readMap("DEFAULT_LOGIN", authInfoMap);
0328       
0329       if (!authInfoMap.isEmpty())
0330       {
0331         authInfo->setUserName(authInfoMap.value("Login"));
0332         authInfo->setPassword(authInfoMap.value("Password"));
0333       }
0334     }
0335   }
0336 }
0337 
0338 
0339 void Smb4KWalletManager::writeAuthInfo(const NetworkItemPtr &networkItem)
0340 {
0341   if (networkItem)
0342   {
0343     //
0344     // Initialize the wallet manager.
0345     // 
0346     init();
0347     
0348     if (walletIsOpen())
0349     {
0350       //
0351       // Handle the network item according to its type
0352       // 
0353       switch (networkItem->type())
0354       {
0355         case Host:
0356         {
0357           //
0358           // Cast the network item
0359           // 
0360           HostPtr host = networkItem.staticCast<Smb4KHost>();
0361           
0362           if (host)
0363           {
0364             //
0365             // Write the authentication information to the wallet, if it
0366             // is not empty.
0367             // 
0368             if (!host->login().isEmpty() /* allow empty passwords */ && !host->hostName().isEmpty())
0369             {
0370               //
0371               // Create the map that carries the authentication information
0372               // 
0373               QMap<QString, QString> authInfoMap;
0374               
0375               //
0376               // Insert login and password
0377               // 
0378               authInfoMap.insert("Login", host->login());
0379               authInfoMap.insert("Password", host->password());
0380               
0381               //
0382               // Enter the workgroup, if it exists
0383               // 
0384               if (!host->workgroupName().isEmpty())
0385               {
0386                 authInfoMap.insert("Workgroup", host->workgroupName());
0387               }
0388               
0389               //
0390               // Enter the IP address, if is exists
0391               // 
0392               if (host->hasIpAddress())
0393               {
0394                 authInfoMap.insert("IP Address", host->ipAddress());
0395               }
0396               
0397               //
0398               // Write the entry to the wallet
0399               // 
0400               d->wallet->writeMap(host->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), authInfoMap);
0401               d->wallet->sync();
0402             }
0403           }
0404 
0405           break;
0406         }
0407         case Share:
0408         {
0409           //
0410           // Cast the network item
0411           // 
0412           SharePtr share = networkItem.staticCast<Smb4KShare>();
0413           
0414           if (share)
0415           {
0416             //
0417             // Write the authentication information to the wallet, if it
0418             // is not empty.
0419             // 
0420             if (!share->login().isEmpty() /* allow empty passwords */ && !share->hostName().isEmpty())
0421             {
0422               //
0423               // Create the map that carries the authentication information
0424               // 
0425               QMap<QString, QString> authInfoMap;
0426               
0427               //
0428               // Insert login and password
0429               // 
0430               authInfoMap.insert("Login", share->login());
0431               authInfoMap.insert("Password", share->password());
0432               
0433               //
0434               // Enter the workgroup, if it exists
0435               // 
0436               if (!share->workgroupName().isEmpty())
0437               {
0438                 authInfoMap.insert("Workgroup", share->workgroupName());
0439               }
0440               
0441               //
0442               // Enter the IP address, if is exists
0443               // 
0444               if (share->hasHostIpAddress())
0445               {
0446                 authInfoMap.insert("IP Address", share->hostIpAddress());
0447               }
0448               
0449               //
0450               // Write the entry to the wallet
0451               // 
0452               if (!share->isHomesShare())
0453               {
0454                 d->wallet->writeMap(share->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), authInfoMap);
0455               }
0456               else
0457               {
0458                 d->wallet->writeMap(share->homeUrl().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), authInfoMap);
0459               }
0460             }
0461           }
0462           
0463           break;
0464         }
0465         default:
0466         {
0467           break;
0468         }
0469       }
0470     }
0471   }
0472 }
0473 
0474 
0475 void Smb4KWalletManager::writeDefaultAuthInfo(Smb4KAuthInfo *authInfo)
0476 {
0477   if (authInfo)
0478   {
0479     //
0480     // Initialize the wallet manager.
0481     // 
0482     init();
0483     
0484     if (walletIsOpen())
0485     {
0486       //
0487       // Write the default authentication information to the
0488       // wallet.
0489       // 
0490       if (!authInfo->userName().isEmpty() /* allow empty passwords */)
0491       {
0492         QMap<QString, QString> authInfoMap;
0493         authInfoMap.insert("Login", authInfo->userName());
0494         authInfoMap.insert("Password", authInfo->password());
0495         
0496         d->wallet->writeMap("DEFAULT_LOGIN", authInfoMap);
0497         d->wallet->sync();
0498       }
0499     }
0500   }
0501 }
0502 
0503 
0504 bool Smb4KWalletManager::showPasswordDialog(const NetworkItemPtr &networkItem)
0505 {
0506   //
0507   // Define the return value here
0508   // 
0509   bool success = false;
0510   
0511   //
0512   // Check that the network item is not null
0513   // 
0514   if (networkItem)
0515   {
0516     //
0517     // Initialize the wallet manager. 
0518     // 
0519     init();
0520     
0521     //
0522     // Get the known logins (for homes shares) and read the authentication 
0523     // information.
0524     // 
0525     QMap<QString, QString> knownLogins;
0526     
0527     switch(networkItem->type())
0528     {
0529       case Share:
0530       {
0531         //
0532         // Cast the network item
0533         // 
0534         SharePtr share = networkItem.staticCast<Smb4KShare>();
0535         
0536         //
0537         // If the share is a 'homes' share, read the known logins
0538         // for that share.
0539         // 
0540         if (share->isHomesShare())
0541         {
0542           //
0543           // Get the known logins
0544           // 
0545           QStringList users = Smb4KHomesSharesHandler::self()->homesUsers(share);
0546           
0547           //
0548           // Read the authentication information for all known logins
0549           // 
0550           for (const QString &user : users)
0551           {
0552             //
0553             // Create a temp share
0554             // 
0555             SharePtr tempShare = share;
0556             
0557             // 
0558             // Set the login
0559             // 
0560             tempShare->setLogin(user);
0561             
0562             //
0563             // Read the authentication information
0564             // 
0565             readAuthInfo(tempShare);
0566             
0567             //
0568             // Save the authentication data in the map
0569             // 
0570             knownLogins.insert(tempShare->login(), tempShare->password());
0571             
0572             //
0573             // Clear the temp share
0574             // 
0575             tempShare.clear();
0576           }
0577         }
0578         else
0579         {
0580           readAuthInfo(networkItem);
0581         }
0582 
0583         break;
0584       }
0585       default:
0586       {
0587         readAuthInfo(networkItem);
0588         break;
0589       }
0590     }
0591     
0592     // 
0593     // Set up the password dialog and show it
0594     // 
0595     QPointer<Smb4KPasswordDialog> dlg = new Smb4KPasswordDialog(networkItem, knownLogins, QApplication::activeWindow());
0596     
0597     if (dlg->exec() == Smb4KPasswordDialog::Accepted)
0598     {
0599       // Write the authentication information.
0600       writeAuthInfo(networkItem);
0601       success = true;
0602     }
0603 
0604     delete dlg;
0605   }
0606 
0607   return success;
0608 }
0609 
0610 
0611 bool Smb4KWalletManager::useWalletSystem() const
0612 {
0613   return (KWallet::Wallet::isEnabled() && Smb4KSettings::useWallet());
0614 }
0615 
0616 
0617 QList<Smb4KAuthInfo *> Smb4KWalletManager::walletEntries()
0618 {
0619   //
0620   // Initialize the wallet manager.
0621   // 
0622   init();
0623   
0624   //
0625   // Define the return value
0626   // 
0627   QList<Smb4KAuthInfo *> entries;
0628   
0629   //
0630   // Only read from the wallet if it is open
0631   // 
0632   if (walletIsOpen())
0633   {
0634     //
0635     // Get all entries from the wallet
0636     // 
0637     QStringList entryList = d->wallet->entryList();
0638     
0639     //
0640     // Process the entries
0641     // 
0642     for (const QString &entry : entryList)
0643     {
0644       //
0645       // Create a auth info object
0646       // 
0647       Smb4KAuthInfo *authInfo = new Smb4KAuthInfo();
0648       
0649       //
0650       // Read the authentication information from the wallet
0651       // 
0652       QMap<QString, QString> authInfoMap;
0653       d->wallet->readMap(entry, authInfoMap);
0654       
0655       //
0656       // Process the entry
0657       // 
0658       if (entry == "DEFAULT_LOGIN")
0659       {
0660         //
0661         // Default login
0662         // 
0663         authInfo->setUserName(authInfoMap.value("Login"));
0664         authInfo->setPassword(authInfoMap.value("Password"));
0665       }
0666       else
0667       {
0668         //
0669         // Entry for a specific URL
0670         // 
0671         authInfo->setUrl(entry);
0672         authInfo->setIpAddress(authInfoMap.value("IP Address"));
0673         authInfo->setWorkgroupName(authInfoMap.value("Workgroup"));
0674         authInfo->setUserName(authInfoMap.value("Login"));
0675         authInfo->setPassword(authInfoMap.value("Password"));
0676       }
0677       
0678       entries << authInfo;
0679     }
0680   }
0681   
0682   return entries;
0683 }
0684 
0685 
0686 void Smb4KWalletManager::writeWalletEntries(const QList<Smb4KAuthInfo *> &entries)
0687 {
0688   //
0689   // Initialize the wallet manager.
0690   // 
0691   init();
0692   
0693   //
0694   // Write the list if the wallet is open
0695   // 
0696   if (walletIsOpen())
0697   {
0698     //
0699     // First clear the wallet
0700     // 
0701     QStringList entryList = d->wallet->entryList();
0702     
0703     for (const QString &entry : entryList)
0704     {
0705       d->wallet->removeEntry(entry);
0706     }
0707     
0708     //
0709     // Now write the new entries to the wallet
0710     // 
0711     for (Smb4KAuthInfo *authInfo : entries)
0712     {
0713       QMap<QString, QString> authInfoMap;
0714       
0715       if (authInfo->type() == UnknownNetworkItem)
0716       {
0717         //
0718         // Default login
0719         // 
0720         authInfoMap.insert("Login", authInfo->userName());
0721         authInfoMap.insert("Password", authInfo->password());
0722         
0723         //
0724         // Write the default authentication information to the wallet
0725         // 
0726         d->wallet->writeMap("DEFAULT_LOGIN", authInfoMap);
0727       }
0728       else
0729       {
0730         //
0731         // Authentication information for a specific URL
0732         // 
0733         authInfoMap.insert("IP Address", authInfo->ipAddress());
0734         authInfoMap.insert("Workgroup", authInfo->workgroupName());
0735         authInfoMap.insert("Login", authInfo->userName());
0736         authInfoMap.insert("Password", authInfo->password());
0737         
0738         //
0739         // Write the authentication information to the wallet
0740         // 
0741         d->wallet->writeMap(authInfo->url().toString(QUrl::RemoveUserInfo|QUrl::RemovePort), authInfoMap);
0742       }
0743       
0744       //
0745       // Sync the entries to disk
0746       // 
0747       d->wallet->sync();
0748     }
0749   }
0750 }
0751 
0752 
0753 bool Smb4KWalletManager::walletIsOpen() const
0754 {
0755   return (d->wallet ? (useWalletSystem() && d->wallet->isOpen()) : false);
0756 }
0757