diff --git a/src/ioslaves/file/file.h b/src/ioslaves/file/file.h --- a/src/ioslaves/file/file.h +++ b/src/ioslaves/file/file.h @@ -102,7 +102,8 @@ enum PriviledgeWarning { WARN_PRIVILEDGE_DEL = 1, - WARN_PRIVILEDGE_RMDIR + WARN_PRIVILEDGE_RMDIR, + NO_WARNING }; bool execWithRoot(const QString &action, const QString &subAction, const QVariant &args, PriviledgeWarning warning); void endPriviledgeOp(); diff --git a/src/ioslaves/file/file.cpp b/src/ioslaves/file/file.cpp --- a/src/ioslaves/file/file.cpp +++ b/src/ioslaves/file/file.cpp @@ -1394,7 +1394,9 @@ } bool proceed = true; - if (kauthStatus == KAuth::Action::AuthorizedStatus && !mPriviledgeOpStarted) { + if (kauthStatus == KAuth::Action::AuthorizedStatus + && !mPriviledgeOpStarted + && metaData(QStringLiteral("ShowInternalWarning")) == QStringLiteral("true")) { mPriviledgeOpStarted = true; proceed = showWarning(warning); } diff --git a/src/ioslaves/file/file_unix.cpp b/src/ioslaves/file/file_unix.cpp --- a/src/ioslaves/file/file_unix.cpp +++ b/src/ioslaves/file/file_unix.cpp @@ -489,8 +489,10 @@ if ((flags & KIO::Overwrite)) { // Try to delete the destination if (unlink(QFile::encodeName(dest).constData()) != 0) { - error(KIO::ERR_CANNOT_DELETE, dest); - return; + if (!execWithRoot(QStringLiteral("del"), QString(), dest, NO_WARNING)) { + error(KIO::ERR_CANNOT_DELETE, dest); + return; + } } // Try again - this won't loop forever since unlink succeeded symlink(target, destUrl, flags); @@ -505,6 +507,15 @@ return; } } else { + if (errno == EACCES || errno == EPERM) { + QVariantMap symlinkData; + symlinkData["target"] = target; + symlinkData["dest"] = dest; + if (execWithRoot(QStringLiteral("symlink"), QString(), symlinkData, NO_WARNING)) { + finished(); + return; + } + } // Some error occurred while we tried to symlink error(KIO::ERR_CANNOT_SYMLINK, dest); return; diff --git a/src/ioslaves/file/kauth/file.actions b/src/ioslaves/file/kauth/file.actions --- a/src/ioslaves/file/kauth/file.actions +++ b/src/ioslaves/file/kauth/file.actions @@ -0,0 +1,11 @@ +[org.kde.kio.file.symlink] +Name=Create symlink with root privilege +Description=Create symlink with root privilege +Policy=auth_admin +Persistence=session + +[org.kde.kio.file.del] +Name=Delete files with root privilege +Description=Delete files with root privilege +Policy=auth_admin +Persistence=session diff --git a/src/ioslaves/file/kauth/helper.h b/src/ioslaves/file/kauth/helper.h --- a/src/ioslaves/file/kauth/helper.h +++ b/src/ioslaves/file/kauth/helper.h @@ -29,6 +29,10 @@ class Helper : public QObject { Q_OBJECT + +public Q_SLOTS: + ActionReply symlink(const QVariantMap &args); + ActionReply del(const QVariantMap &args); }; #endif diff --git a/src/ioslaves/file/kauth/helper.cpp b/src/ioslaves/file/kauth/helper.cpp --- a/src/ioslaves/file/kauth/helper.cpp +++ b/src/ioslaves/file/kauth/helper.cpp @@ -19,5 +19,43 @@ ***/ #include "helper.h" +#include +#include +#include +#include + +ActionReply Helper::symlink(const QVariantMap &args) +{ + ActionReply reply = ActionReply::SuccessReply(); + const QVariantMap data = args["arguments"].toMap(); + const QString target = data["target"].toString(); + const QString dest = data["dest"].toString(); + + if (::symlink(QFile::encodeName(target).constData(), QFile::encodeName(dest).constData())) { + if (errno == EACCES || errno == EPERM) { + reply.setError(KIO::ERR_ACCESS_DENIED); + } + } + + return reply; +} + +// from the branch 'delete' +ActionReply Helper::del(const QVariantMap &args) +{ + ActionReply reply = ActionReply::SuccessReply(); + const QString path = args["arguments"].toString(); + const QString subAction = args["subaction"].toString(); + + if (subAction == QLatin1String("delete_file")) { + if (::unlink(QFile::encodeName(path).constData()) != 0) { + if (errno == EACCES || errno == EPERM) { + reply.setError(KIO::ERR_ACCESS_DENIED); + } + } + } + + return reply; +} KAUTH_HELPER_MAIN("org.kde.kio.file", Helper)