File indexing completed on 2024-09-08 12:53:14
0001 /*************************************************************************** 0002 The helper that mounts and unmounts shares. 0003 ------------------- 0004 begin : Sa Okt 16 2010 0005 copyright : (C) 2010-2020 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 "smb4kmounthelper.h" 0032 #include "../core/smb4kglobal.h" 0033 0034 // Qt includes 0035 #include <QProcessEnvironment> 0036 #include <QDebug> 0037 #include <QLatin1String> 0038 #include <QUrl> 0039 #include <QNetworkConfigurationManager> 0040 0041 // KDE includes 0042 #include <KAuth/KAuthHelperSupport> 0043 #include <KCoreAddons/KProcess> 0044 #include <KI18n/KLocalizedString> 0045 #include <KIOCore/KMountPoint> 0046 0047 using namespace Smb4KGlobal; 0048 0049 KAUTH_HELPER_MAIN("org.kde.smb4k.mounthelper", Smb4KMountHelper); 0050 0051 KAuth::ActionReply Smb4KMountHelper::mount(const QVariantMap& args) 0052 { 0053 // 0054 // The action reply 0055 // 0056 ActionReply reply; 0057 0058 // 0059 // Check if the system is online and return an error if it is not 0060 // 0061 QNetworkConfigurationManager networkManager; 0062 0063 if (!networkManager.isOnline()) 0064 { 0065 reply.setType(ActionReply::HelperErrorType); 0066 return reply; 0067 } 0068 0069 // 0070 // Get the mount executable 0071 // 0072 const QString mount = findMountExecutable(); 0073 0074 // 0075 // Check the mount executable 0076 // 0077 if (mount != args["mh_command"].toString()) 0078 { 0079 // Something weird is going on, bail out. 0080 reply.setType(ActionReply::HelperErrorType); 0081 return reply; 0082 } 0083 0084 // 0085 // Mount command 0086 // 0087 QStringList command; 0088 #if defined(Q_OS_LINUX) 0089 command << mount; 0090 command << args["mh_url"].toUrl().toString(QUrl::RemoveScheme|QUrl::RemoveUserInfo|QUrl::RemovePort); 0091 command << args["mh_mountpoint"].toString(); 0092 command << args["mh_options"].toStringList(); 0093 #elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) 0094 command << mount; 0095 command << args["mh_options"].toStringList(); 0096 command << args["mh_url"].toUrl().toString(QUrl::RemoveScheme|QUrl::RemoveUserInfo|QUrl::RemovePort); 0097 command << args["mh_mountpoint"].toString(); 0098 #endif 0099 0100 // 0101 // The process 0102 // 0103 KProcess proc(this); 0104 proc.setOutputChannelMode(KProcess::SeparateChannels); 0105 proc.setProcessEnvironment(QProcessEnvironment::systemEnvironment()); 0106 #if defined(Q_OS_LINUX) 0107 proc.setEnv("PASSWD", args["mh_url"].toUrl().password().toUtf8().data(), true); 0108 #endif 0109 // We need this to avoid a translated password prompt. 0110 proc.setEnv("LANG", "C"); 0111 // If the location of a Kerberos ticket is passed, it needs to 0112 // be passed to the process environment here. 0113 if (args.contains("mh_krb5ticket")) 0114 { 0115 proc.setEnv("KRB5CCNAME", args["mh_krb5ticket"].toString()); 0116 } 0117 0118 proc.setProgram(command); 0119 proc.start(); 0120 0121 if (proc.waitForStarted(-1)) 0122 { 0123 bool userKill = false; 0124 0125 while (!proc.waitForFinished(10)) 0126 { 0127 // Check if there is a password prompt. If there is one, pass 0128 // the password to it. 0129 QByteArray out = proc.readAllStandardError(); 0130 0131 if (out.startsWith("Password")) 0132 { 0133 proc.write(args["mh_url"].toUrl().password().toUtf8().data()); 0134 proc.write("\r"); 0135 } 0136 0137 // We want to be able to terminate the process from outside. 0138 // Thus, we implement a loop that checks periodically, if we 0139 // need to kill the process. 0140 if (HelperSupport::isStopped()) 0141 { 0142 proc.kill(); 0143 userKill = true; 0144 } 0145 } 0146 0147 if (proc.exitStatus() == KProcess::CrashExit) 0148 { 0149 if (!userKill) 0150 { 0151 reply.setType(ActionReply::HelperErrorType); 0152 reply.setErrorDescription(i18n("The mount process crashed.")); 0153 } 0154 } 0155 else 0156 { 0157 // Check if there is output on stderr. 0158 QString stdErr = QString::fromUtf8(proc.readAllStandardError()); 0159 reply.addData("mh_error_message", stdErr.trimmed()); 0160 } 0161 } 0162 else 0163 { 0164 reply.setType(ActionReply::HelperErrorType); 0165 reply.setErrorDescription(i18n("The mount process could not be started.")); 0166 } 0167 0168 return reply; 0169 } 0170 0171 0172 KAuth::ActionReply Smb4KMountHelper::unmount(const QVariantMap& args) 0173 { 0174 ActionReply reply; 0175 0176 // 0177 // Get the umount executable 0178 // 0179 const QString umount = findUmountExecutable(); 0180 0181 // 0182 // Check the mount executable 0183 // 0184 if (umount != args["mh_command"].toString()) 0185 { 0186 // Something weird is going on, bail out. 0187 reply.setType(ActionReply::HelperErrorType); 0188 return reply; 0189 } 0190 0191 // 0192 // Check if the mountpoint is valid and the filesystem is correct. 0193 // 0194 bool mountPointOk = false; 0195 KMountPoint::List mountPoints = KMountPoint::currentMountPoints(KMountPoint::BasicInfoNeeded|KMountPoint::NeedMountOptions); 0196 0197 for (const QExplicitlySharedDataPointer<KMountPoint> &mountPoint : mountPoints) 0198 { 0199 #if defined(Q_OS_LINUX) 0200 if (QString::compare(args["mh_mountpoint"].toString(), mountPoint->mountPoint()) == 0 && 0201 QString::compare(mountPoint->mountType(), "cifs", Qt::CaseInsensitive) == 0) 0202 #else 0203 if (QString::compare(args["mh_mountpoint"].toString(), mountPoint->mountPoint()) == 0 && 0204 QString::compare(mountPoint->mountType(), "smbfs", Qt::CaseInsensitive) == 0) 0205 #endif 0206 { 0207 mountPointOk = true; 0208 break; 0209 } 0210 } 0211 0212 // 0213 // Stop here if the mountpoint is not valid 0214 // 0215 if (!mountPointOk) 0216 { 0217 reply.setType(ActionReply::HelperErrorType); 0218 reply.setErrorDescription(i18n("The mountpoint %1 is invalid.", args["mh_mountpoint"].toString())); 0219 } 0220 0221 // 0222 // The command 0223 // 0224 QStringList command; 0225 command << umount; 0226 command << args["mh_options"].toStringList(); 0227 command << args["mh_mountpoint"].toString(); 0228 0229 // 0230 // The process 0231 // 0232 KProcess proc(this); 0233 proc.setOutputChannelMode(KProcess::SeparateChannels); 0234 proc.setProcessEnvironment(QProcessEnvironment::systemEnvironment()); 0235 proc.setProgram(command); 0236 0237 // 0238 // Depending on the online state, use a different behavior for unmounting. 0239 // 0240 // Extensive tests have shown that - when offline - unmounting does not 0241 // work properly when the the process is not detached. Thus, detach it 0242 // when the system is offline. 0243 // 0244 QNetworkConfigurationManager networkManager; 0245 0246 if (networkManager.isOnline()) 0247 { 0248 proc.start(); 0249 0250 if (proc.waitForStarted(-1)) 0251 { 0252 // We want to be able to terminate the process from outside. 0253 // Thus, we implement a loop that checks periodically, if we 0254 // need to kill the process. 0255 bool userKill = false; 0256 0257 while (!proc.waitForFinished(10)) 0258 { 0259 if (HelperSupport::isStopped()) 0260 { 0261 proc.kill(); 0262 userKill = true; 0263 break; 0264 } 0265 } 0266 0267 if (proc.exitStatus() == KProcess::CrashExit) 0268 { 0269 if (!userKill) 0270 { 0271 reply.setType(ActionReply::HelperErrorType); 0272 reply.setErrorDescription(i18n("The unmount process crashed.")); 0273 } 0274 } 0275 else 0276 { 0277 // Check if there is output on stderr. 0278 QString stdErr = QString::fromUtf8(proc.readAllStandardError()); 0279 reply.addData("mh_error_message", stdErr.trimmed()); 0280 } 0281 } 0282 else 0283 { 0284 reply.setType(ActionReply::HelperErrorType); 0285 reply.setErrorDescription(i18n("The unmount process could not be started.")); 0286 } 0287 } 0288 else 0289 { 0290 proc.startDetached(); 0291 } 0292 0293 return reply; 0294 } 0295 0296