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

0001 /***************************************************************************
0002     These are the private helper classes of the Smb4KGlobal namespace.
0003                              -------------------
0004     begin                : Di Jul 24 2007
0005     copyright            : (C) 2007-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 "smb4kglobal_p.h"
0032 #include "smb4knotification.h"
0033 #include "smb4ksettings.h"
0034 
0035 // Qt includes
0036 #include <QDir>
0037 #include <QTextStream>
0038 #include <QTextCodec>
0039 #include <QFile>
0040 #include <QCoreApplication>
0041 #include <QHostAddress>
0042 #include <QAbstractSocket>
0043 #include <QHostInfo>
0044 #include <QDirIterator>
0045 
0046 
0047 Smb4KGlobalPrivate::Smb4KGlobalPrivate()
0048 {
0049   onlyForeignShares = false;
0050   coreInitialized = false;
0051   m_sambaConfigMissing = false;
0052   
0053 #ifdef Q_OS_LINUX
0054   whitelistedMountArguments << "dynperm";
0055   whitelistedMountArguments << "rwpidforward";
0056   whitelistedMountArguments << "hard";
0057   whitelistedMountArguments << "soft";
0058   whitelistedMountArguments << "noacl";
0059   whitelistedMountArguments << "cifsacl";
0060   whitelistedMountArguments << "backupuid";
0061   whitelistedMountArguments << "backupgid";
0062   whitelistedMountArguments << "ignorecase";
0063   whitelistedMountArguments << "nocase";
0064   whitelistedMountArguments << "nobrl";
0065   whitelistedMountArguments << "sfu";
0066   whitelistedMountArguments << "nounix";
0067   whitelistedMountArguments << "nouser_xattr";
0068   whitelistedMountArguments << "fsc";
0069   whitelistedMountArguments << "multiuser";
0070   whitelistedMountArguments << "actimeo";
0071   whitelistedMountArguments << "noposixpaths";
0072   whitelistedMountArguments << "posixpaths";
0073 #endif
0074   
0075   //
0076   // File system watcher for smb.conf file
0077   // 
0078   m_watcher = new QFileSystemWatcher(this);
0079   
0080   //
0081   // Connections
0082   // 
0083   connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), SLOT(slotAboutToQuit()));
0084   connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(slotSmbConfModified(QString)));
0085 }
0086 
0087 
0088 Smb4KGlobalPrivate::~Smb4KGlobalPrivate()
0089 {
0090   // Clear the workgroup list.
0091   while (!workgroupsList.isEmpty())
0092   {
0093     workgroupsList.takeFirst().clear();
0094   }
0095 
0096   // Clear the host list.
0097   while (!hostsList.isEmpty())
0098   {
0099     hostsList.takeFirst().clear();
0100   }
0101 
0102   // Clear the list of mounted shares.
0103   while (!mountedSharesList.isEmpty())
0104   {
0105     mountedSharesList.takeFirst().clear();
0106   }
0107 
0108   // Clear the list of shares.
0109   while (!sharesList.isEmpty())
0110   {
0111     sharesList.takeFirst().clear();
0112   }
0113 }
0114 
0115 
0116 const QMap<QString,QString> &Smb4KGlobalPrivate::globalSambaOptions(bool read)
0117 {
0118   if ((!m_sambaConfigMissing && m_sambaOptions.isEmpty()) || read)
0119   {
0120     // 
0121     // Clear the options.
0122     // 
0123     m_sambaOptions.clear();
0124     
0125     // 
0126     // Now search the smb.conf file.
0127     // 
0128     // With the introduction of Samba 4, the smb.conf file might also
0129     // be named smb4.conf. Thus we need to search for two filenames.
0130     // 
0131     QStringList paths;
0132     paths << "/etc";
0133     paths << "/usr/local/etc";
0134     paths << "/usr/pkg/etc";
0135     
0136     QStringList files;
0137     files << "smb.conf";
0138     files << "smb4.conf";
0139     
0140     QString result;
0141     
0142     for (const QString &path : paths)
0143     {
0144       QDirIterator it(path, files, QDir::Files, QDirIterator::Subdirectories);
0145       
0146       while (it.hasNext())
0147       {
0148         result = it.next();
0149       }
0150       
0151       if (!result.isEmpty())
0152       {
0153         break;
0154       }
0155     }
0156     
0157     //
0158     // Check if we found the file and read it. Otherwise show an error
0159     // message to the user.
0160     // 
0161     QStringList contents;
0162     
0163     if (!result.isEmpty())
0164     {
0165       QFile smbConf(result);
0166       
0167       if (smbConf.open(QIODevice::ReadOnly | QIODevice::Text))
0168       {
0169         QTextStream ts(&smbConf);
0170         
0171         while (!ts.atEnd())
0172         {
0173           contents << ts.readLine(0);
0174         }
0175         
0176         smbConf.close();
0177       }
0178       else
0179       {
0180         Smb4KNotification::openingFileFailed(smbConf);
0181         return m_sambaOptions;
0182       }
0183       
0184       //
0185       // Add the file to the file system watcher
0186       // 
0187       m_watcher->addPath(result);
0188       
0189       //
0190       // Tell the program that the config file was found
0191       // 
0192       m_sambaConfigMissing = false;
0193     }
0194     else
0195     {
0196       if (!m_sambaConfigMissing)
0197       {
0198         Smb4KNotification::sambaConfigFileMissing();
0199         m_sambaConfigMissing = true;
0200         return m_sambaOptions;
0201       }
0202     }
0203     
0204     //
0205     // Process the contents of the smb.conf file
0206     // 
0207     if (!contents.isEmpty())
0208     {
0209       //
0210       // Jump to the [global] section and get the listed parameters
0211       // 
0212       for (int i = contents.indexOf("[global]", 0); i < contents.size(); ++i)
0213       {
0214         if (i == -1)
0215         {
0216           // 
0217           // No [global] section found. Stop.
0218           // 
0219           break;
0220         }
0221         else if (contents.at(i).trimmed().startsWith('#') || contents.at(i).trimmed().startsWith(';') || contents.at(i).trimmed().isEmpty())
0222         {
0223           // 
0224           // This is either a comment or an empty line. We do not want it.
0225           // 
0226           continue;
0227         }
0228         else if (contents.at(i).trimmed().startsWith(QLatin1String("include")))
0229         {
0230           //
0231           // This is an include file. Get its contents and insert it into the 
0232           // global Samba options map
0233           // 
0234           QFile includeFile(contents.at(i).section('=', 1, 1).trimmed());
0235 
0236           if (includeFile.exists())
0237           {
0238             if (includeFile.open(QIODevice::ReadOnly | QIODevice::Text))
0239             {
0240               QTextStream ts(&includeFile);
0241 
0242               QString buffer;
0243 
0244               while(!ts.atEnd())
0245               {
0246                 buffer = ts.readLine(0).trimmed();
0247 
0248                 if (buffer.startsWith('#') || buffer.startsWith(';'))
0249                 {
0250                   // 
0251                   // This is either a comment or an empty line. We do not want it.
0252                   // 
0253                   continue;
0254                 }
0255                 else
0256                 {
0257                   //
0258                   // This is an option. Put it into the global Samba options map
0259                   // 
0260                   QString key = contents.at(i).section('=', 0, 0).trimmed().toLower();
0261                   QString value = contents.at(i).section('=', 1, 1).trimmed().toUpper();
0262           
0263                   m_sambaOptions.insert(key, value);
0264                 }
0265               }
0266             }
0267             else
0268             {
0269               Smb4KNotification::openingFileFailed(includeFile);
0270               continue;
0271             }
0272           }
0273         }
0274         else if (contents.at(i).trimmed().startsWith('[') && !contents.at(i).contains("[global]", Qt::CaseSensitive))
0275         {
0276           //
0277           // A new section begins. Stop.
0278           // 
0279           break;
0280         }
0281         else
0282         {
0283           //
0284           // This is an option. Put it into the global Samba options map
0285           // 
0286           QString key = contents.at(i).section('=', 0, 0).trimmed().toLower();
0287           QString value = contents.at(i).section('=', 1, 1).trimmed().toUpper();
0288           
0289           m_sambaOptions.insert(key, value);
0290         }
0291       }
0292     }
0293   }
0294     
0295   return m_sambaOptions;
0296 }
0297 
0298 
0299 void Smb4KGlobalPrivate::slotAboutToQuit()
0300 {
0301   Smb4KSettings::self()->save();
0302 }
0303 
0304 
0305 void Smb4KGlobalPrivate::slotSmbConfModified(const QString &/*file*/)
0306 {
0307   globalSambaOptions(true);
0308 }
0309