• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KIO

ksambashare.cpp
Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (c) 2004 Jan Schaefer <j_schaef@informatik.uni-kl.de>
00003    Copyright 2010 Rodrigo Belem <rclbelem@gmail.com>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License version 2 as published by the Free Software Foundation.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017    Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "ksambashare.h"
00021 #include "ksambashare_p.h"
00022 #include "ksambasharedata.h"
00023 #include "ksambasharedata_p.h"
00024 
00025 #include <QtCore/QMap>
00026 #include <QtCore/QMutableMapIterator>
00027 #include <QtCore/QFile>
00028 #include <QtCore/QRegExp>
00029 #include <QtCore/QFileInfo>
00030 #include <QtCore/QTextStream>
00031 #include <QtCore/QStringList>
00032 
00033 #include <kdirwatch.h>
00034 #include <kdebug.h>
00035 #include <kglobal.h>
00036 #include <kprocess.h>
00037 #include <kuser.h>
00038 
00039 // Default smb.conf locations
00040 // sorted by priority, most priority first
00041 static const char * const DefaultSambaConfigFilePathList[] =
00042 {
00043   "/etc/samba/smb.conf",
00044   "/etc/smb.conf",
00045   "/usr/local/etc/smb.conf",
00046   "/usr/local/samba/lib/smb.conf",
00047   "/usr/samba/lib/smb.conf",
00048   "/usr/lib/smb.conf",
00049   "/usr/local/lib/smb.conf"
00050 };
00051 static const int DefaultSambaConfigFilePathListSize = sizeof(DefaultSambaConfigFilePathList)
00052         / sizeof(char*);
00053 
00054 KSambaSharePrivate::KSambaSharePrivate(KSambaShare *parent)
00055     : q_ptr(parent)
00056     , data()
00057     , smbConf()
00058     , userSharePath()
00059     , skipUserShare(false)
00060 {
00061     setUserSharePath();
00062     findSmbConf();
00063     sync();
00064 }
00065 
00066 KSambaSharePrivate::~KSambaSharePrivate()
00067 {
00068 }
00069 
00070 bool KSambaSharePrivate::isSambaInstalled()
00071 {
00072     if (QFile::exists("/usr/sbin/smbd")
00073         || QFile::exists("/usr/local/sbin/smbd")) {
00074         return true;
00075     }
00076 
00077     kDebug() << "Samba is not installed!";
00078 
00079     return false;
00080 }
00081 
00082 // Try to find the samba config file path
00083 // in several well-known paths
00084 bool KSambaSharePrivate::findSmbConf()
00085 {
00086     for (int i = 0; i < DefaultSambaConfigFilePathListSize; ++i) {
00087         const QString filePath(DefaultSambaConfigFilePathList[i]);
00088         if (QFile::exists(filePath)) {
00089             smbConf = filePath;
00090             return true;
00091         }
00092     }
00093 
00094     kWarning() << "KSambaShare: Could not find smb.conf!";
00095 
00096     return false;
00097 }
00098 
00099 void KSambaSharePrivate::setUserSharePath()
00100 {
00101     const QString rawString = testparmParamValue(QLatin1String("usershare path"));
00102     const QFileInfo fileInfo(rawString);
00103     if (fileInfo.isDir()) {
00104         userSharePath = rawString;
00105     }
00106 }
00107 
00108 int KSambaSharePrivate::runProcess(const QString &progName, const QStringList &args,
00109                                    QByteArray &stdOut, QByteArray &stdErr)
00110 {
00111     KProcess process;
00112 
00113     process.setProgram(progName, args);
00114     process.setOutputChannelMode(KProcess::SeparateChannels);
00115     process.start();
00116     //TODO: make it async in future
00117     process.waitForFinished();
00118 
00119     stdOut = process.readAllStandardOutput();
00120     stdErr = process.readAllStandardError();
00121     return process.exitCode();
00122 }
00123 
00124 QString KSambaSharePrivate::testparmParamValue(const QString &parameterName)
00125 {
00126     if (!isSambaInstalled()) {
00127         return QString();
00128     }
00129 
00130     QStringList args;
00131     QByteArray stdErr;
00132     QByteArray stdOut;
00133 
00134     args << QLatin1String("-d0") << QLatin1String("-s") << QLatin1String("--parameter-name")
00135          << parameterName;
00136 
00137     runProcess(QLatin1String("testparm"), args, stdOut, stdErr);
00138 
00139     //TODO: parse and process error messages.
00140     // create a parser for the error output and
00141     // send error message somewhere
00142     if (!stdErr.isEmpty()) {
00143         QList<QByteArray> err;
00144         err << stdErr.trimmed().split('\n');
00145         if ((err.count() == 2)
00146                 && err.at(0).startsWith("Load smb config files from")
00147                 && err.at(1).startsWith("Loaded services file OK.")) {
00148             kDebug() << "Running testparm" << args;
00149         } else {
00150             kWarning() << "We got some errors while running testparm" << stdErr;
00151         }
00152     }
00153 
00154     if (!stdOut.isEmpty()) {
00155         return QString::fromLocal8Bit(stdOut.trimmed());
00156     }
00157 
00158     return QString();
00159 }
00160 
00161 QByteArray KSambaSharePrivate::getNetUserShareInfo()
00162 {
00163     if (skipUserShare || !isSambaInstalled()) {
00164         return QByteArray();
00165     }
00166 
00167     QStringList args;
00168     QByteArray stdOut;
00169     QByteArray stdErr;
00170 
00171     args << QLatin1String("usershare") << QLatin1String("info");
00172 
00173     runProcess(QLatin1String("net"), args, stdOut, stdErr);
00174 
00175     if (!stdErr.isEmpty()) {
00176         if (stdErr.contains("You do not have permission to create a usershare")) {
00177             skipUserShare = true;
00178         } else if (stdErr.contains("usershares are currently disabled")) {
00179             skipUserShare = true;
00180         } else {
00181             //TODO: parse and process other error messages.
00182             // create a parser for the error output and
00183             // send error message somewhere
00184             kWarning() << "We got some errors while running 'net usershare info'";
00185             kWarning() << stdErr;
00186         }
00187     }
00188 
00189     return stdOut;
00190 }
00191 
00192 QStringList KSambaSharePrivate::shareNames() const
00193 {
00194     return data.keys();
00195 }
00196 
00197 QStringList KSambaSharePrivate::sharedDirs() const
00198 {
00199     QStringList dirs;
00200 
00201     QMap<QString, KSambaShareData>::ConstIterator i;
00202     for (i = data.constBegin(); i != data.constEnd(); ++i) {
00203         if (!dirs.contains(i.value().path())) {
00204             dirs << i.value().path();
00205         }
00206     }
00207 
00208     return dirs;
00209 }
00210 
00211 KSambaShareData KSambaSharePrivate::getShareByName(const QString &shareName) const
00212 {
00213     return data.value(shareName);
00214 }
00215 
00216 QList<KSambaShareData> KSambaSharePrivate::getSharesByPath(const QString &path) const
00217 {
00218     QList<KSambaShareData> shares;
00219 
00220     QMap<QString, KSambaShareData>::ConstIterator i;
00221     for (i = data.constBegin(); i != data.constEnd(); ++i) {
00222         if (i.value().path() == path) {
00223             shares << i.value();
00224         }
00225     }
00226 
00227     return shares;
00228 }
00229 
00230 bool KSambaSharePrivate::isShareNameValid(const QString &name) const
00231 {
00232     // Samba forbidden chars
00233     const QRegExp notToMatchRx(QLatin1String("[%<>*\?|/\\+=;:\",]"));
00234     return (notToMatchRx.indexIn(name) == -1);
00235 }
00236 
00237 bool KSambaSharePrivate::isDirectoryShared(const QString &path) const
00238 {
00239     QMap<QString, KSambaShareData>::ConstIterator i;
00240     for (i = data.constBegin(); i != data.constEnd(); ++i) {
00241         if (i.value().path() == path) {
00242             return true;
00243         }
00244     }
00245 
00246     return false;
00247 }
00248 
00249 bool KSambaSharePrivate::isShareNameAvailable(const QString &name) const
00250 {
00251     // Samba does not allow to name a share with a user name registered in the system
00252     return (!KUser::allUserNames().contains(name) || !data.keys().contains(name));
00253 }
00254 
00255 KSambaShareData::UserShareError KSambaSharePrivate::isPathValid(const QString &path) const
00256 {
00257     QFileInfo pathInfo = path;
00258 
00259     if (!pathInfo.exists()) {
00260         return KSambaShareData::UserSharePathNotExists;
00261     }
00262 
00263     if (!pathInfo.isDir()) {
00264         return KSambaShareData::UserSharePathNotDirectory;
00265     }
00266 
00267     if (pathInfo.isRelative()) {
00268         if (pathInfo.makeAbsolute()) {
00269             return KSambaShareData::UserSharePathNotAbsolute;
00270         }
00271     }
00272 
00273     // TODO: check if the user is root
00274     if (KSambaSharePrivate::testparmParamValue(QLatin1String("usershare owner only"))
00275             == QLatin1String("Yes")) {
00276         if (!pathInfo.permission(QFile::ReadUser | QFile::WriteUser)) {
00277             return KSambaShareData::UserSharePathNotAllowed;
00278         }
00279     }
00280 
00281     return KSambaShareData::UserSharePathOk;
00282 }
00283 
00284 KSambaShareData::UserShareError KSambaSharePrivate::isAclValid(const QString &acl) const
00285 {
00286     const QRegExp aclRx("(?:(?:(\\w+\\s*)\\\\|)(\\w+\\s*):([fFrRd]{1})(?:,|))*");
00287     // TODO: check if user is a valid smb user
00288     return aclRx.exactMatch(acl) ? KSambaShareData::UserShareAclOk
00289            : KSambaShareData::UserShareAclInvalid;
00290 }
00291 
00292 KSambaShareData::UserShareError KSambaSharePrivate::guestsAllowed(const
00293         KSambaShareData::GuestPermission &guestok) const
00294 {
00295     if (guestok == KSambaShareData::GuestsAllowed) {
00296         if (KSambaSharePrivate::testparmParamValue("usershare allow guests")
00297                 == QLatin1String("No")) {
00298             return KSambaShareData::UserShareGuestsNotAllowed;
00299         }
00300     }
00301 
00302     return KSambaShareData::UserShareGuestsOk;
00303 }
00304 
00305 KSambaShareData::UserShareError KSambaSharePrivate::add(const KSambaShareData &shareData)
00306 {
00307     // TODO:
00308     // * check for usershare max shares
00309 
00310     if (!isSambaInstalled()) {
00311         return KSambaShareData::UserShareSystemError;
00312     }
00313 
00314     QStringList args;
00315     QByteArray stdOut;
00316     QByteArray stdErr;
00317 
00318     if (data.contains(shareData.name())) {
00319         if (data.value(shareData.name()).path() != shareData.path()) {
00320             return KSambaShareData::UserShareNameInUse;
00321         }
00322     } else {
00323         // It needs to be added here, otherwise another instance of KSambaShareDataPrivate
00324         // will be created and added to data.
00325         data.insert(shareData.name(), shareData);
00326     }
00327 
00328     QString guestok = QString("guest_ok=%1").arg(
00329                           (shareData.guestPermission() == KSambaShareData::GuestsNotAllowed)
00330                           ? QLatin1String("n") : QLatin1String("y"));
00331 
00332     args << QLatin1String("usershare") << QLatin1String("add") << shareData.name()
00333          << shareData.path() << shareData.comment() << shareData.acl() << guestok;
00334 
00335     int ret = runProcess(QLatin1String("net"), args, stdOut, stdErr);
00336 
00337     //TODO: parse and process error messages.
00338     if (!stdErr.isEmpty()) {
00339         // create a parser for the error output and
00340         // send error message somewhere
00341         kWarning() << "We got some errors while running 'net usershare add'" << args;
00342         kWarning() << stdErr;
00343     }
00344 
00345     return (ret == 0) ? KSambaShareData::UserShareOk : KSambaShareData::UserShareSystemError;
00346 }
00347 
00348 KSambaShareData::UserShareError KSambaSharePrivate::remove(const KSambaShareData &shareData) const
00349 {
00350     if (!isSambaInstalled()) {
00351         return KSambaShareData::UserShareSystemError;
00352     }
00353 
00354     QStringList args;
00355 
00356     if (!data.contains(shareData.name())) {
00357         return KSambaShareData::UserShareNameInvalid;
00358     }
00359 
00360     args << QLatin1String("usershare") << QLatin1String("delete") << shareData.name();
00361 
00362     int result = KProcess::execute(QLatin1String("net"), args);
00363     return (result == 0) ? KSambaShareData::UserShareOk : KSambaShareData::UserShareSystemError;
00364 }
00365 
00366 bool KSambaSharePrivate::sync()
00367 {
00368     const QRegExp headerRx(QLatin1String("^\\s*\\["
00369                                          "([^%<>*\?|/\\+=;:\",]+)"
00370                                          "\\]"));
00371 
00372     const QRegExp OptValRx(QLatin1String("^\\s*([\\w\\d\\s]+)"
00373                                          "="
00374                                          "(.*)$"));
00375 
00376     QTextStream stream(getNetUserShareInfo());
00377     QString currentShare;
00378     QStringList shareList;
00379 
00380     while (!stream.atEnd()) {
00381         const QString line = stream.readLine().trimmed();
00382 
00383         if (headerRx.exactMatch(line)) {
00384             currentShare = headerRx.cap(1).trimmed();
00385             shareList << currentShare;
00386 
00387             if (!data.contains(currentShare)) {
00388                 KSambaShareData shareData;
00389                 shareData.dd->name = currentShare;
00390                 data.insert(currentShare, shareData);
00391             }
00392         } else if (OptValRx.exactMatch(line)) {
00393             const QString key = OptValRx.cap(1).trimmed();
00394             const QString value = OptValRx.cap(2).trimmed();
00395             KSambaShareData shareData = getShareByName(currentShare);
00396 
00397             if (key == QLatin1String("path")) {
00398                 shareData.dd->path = value;
00399             } else if (key == QLatin1String("comment")) {
00400                 shareData.dd->comment = value;
00401             } else if (key == QLatin1String("usershare_acl")) {
00402                 shareData.dd->acl = value;
00403             } else if (key == QLatin1String("guest_ok")) {
00404                 shareData.dd->guestPermission = value;
00405             } else {
00406                 kWarning() << "Something nasty happen while parsing 'net usershare info'"
00407                            << "share:" << currentShare << "key:" << key;
00408             }
00409         } else if (line.trimmed().isEmpty()) {
00410             continue;
00411         } else {
00412             return false;
00413         }
00414     }
00415 
00416     QMutableMapIterator<QString, KSambaShareData> i(data);
00417     while (i.hasNext()) {
00418         i.next();
00419         if (!shareList.contains(i.key())) {
00420             i.remove();
00421         }
00422     }
00423 
00424     return true;
00425 }
00426 
00427 void KSambaSharePrivate::_k_slotFileChange(const QString &path)
00428 {
00429     sync();
00430     kDebug() << "path changed:" << path;
00431     Q_Q(KSambaShare);
00432     emit q->changed();
00433 }
00434 
00435 KSambaShare::KSambaShare()
00436     : QObject(0)
00437     , d_ptr(new KSambaSharePrivate(this))
00438 {
00439     Q_D(const KSambaShare);
00440     if (QFile::exists(d->userSharePath)) {
00441         KDirWatch::self()->addDir(d->userSharePath, KDirWatch::WatchFiles);
00442         connect(KDirWatch::self(), SIGNAL(dirty(const QString &)), this,
00443                 SLOT(_k_slotFileChange(const QString &)));
00444     }
00445 }
00446 
00447 KSambaShare::~KSambaShare()
00448 {
00449     Q_D(const KSambaShare);
00450     if (KDirWatch::exists() && KDirWatch::self()->contains(d->userSharePath)) {
00451         KDirWatch::self()->removeDir(d->userSharePath);
00452     }
00453     delete d_ptr;
00454 }
00455 
00456 QString KSambaShare::smbConfPath() const
00457 {
00458     Q_D(const KSambaShare);
00459     return d->smbConf;
00460 }
00461 
00462 bool KSambaShare::isDirectoryShared(const QString &path) const
00463 {
00464     Q_D(const KSambaShare);
00465     return d->isDirectoryShared(path);
00466 }
00467 
00468 bool KSambaShare::isShareNameAvailable(const QString &name) const
00469 {
00470     Q_D(const KSambaShare);
00471     return d->isShareNameValid(name) && d->isShareNameAvailable(name);
00472 }
00473 
00474 QStringList KSambaShare::shareNames() const
00475 {
00476     Q_D(const KSambaShare);
00477     return d->shareNames();
00478 }
00479 
00480 QStringList KSambaShare::sharedDirectories() const
00481 {
00482     Q_D(const KSambaShare);
00483     return d->sharedDirs();
00484 }
00485 
00486 KSambaShareData KSambaShare::getShareByName(const QString &name) const
00487 {
00488     Q_D(const KSambaShare);
00489     return d->getShareByName(name);
00490 }
00491 
00492 QList<KSambaShareData> KSambaShare::getSharesByPath(const QString &path) const
00493 {
00494     Q_D(const KSambaShare);
00495     return d->getSharesByPath(path);
00496 }
00497 
00498 KSambaShare *KSambaShare::instance()
00499 {
00500     K_GLOBAL_STATIC(KSambaShare, _instance)
00501     return _instance;
00502 }
00503 
00504 #include "moc_ksambashare.cpp"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal