Commit 453f3699 authored by Janet Blackquill's avatar Janet Blackquill 🌈
Browse files

Revert "Finish PolKit integration"

This reverts commit deb4cd41.
parent 063557b0
Pipeline #129390 failed with stage
in 2 minutes and 30 seconds
......@@ -1241,10 +1241,16 @@ bool KFileItem::isWritable() const
// for the groups... then we need to handle the deletion properly...
*/
if (d->m_permissions != KFileItem::Unknown) {
// No write permission at all
if (!(S_IWUSR & d->m_permissions) && !(S_IWGRP & d->m_permissions) && !(S_IWOTH & d->m_permissions)) {
return false;
}
}
// Or if we can't write it - not network transparent
if (d->m_bIsLocalUrl) {
// file protocol has supportsPrivilegeExecution so any local file is potentially writable
return true;
return QFileInfo(d->m_url.toLocalFile()).isWritable();
} else {
return KProtocolManager::supportsWriting(d->m_url);
}
......
......@@ -14,24 +14,19 @@
#include <QFileInfo>
#ifndef Q_OS_WIN
#include <KUser>
#include <unistd.h>
#endif
class KFileItemListPropertiesPrivate : public QSharedData
{
public:
KFileItemListPropertiesPrivate()
: m_isDirectory(false),
m_isFile(false),
m_supportsReading(false),
m_supportsDeleting(false),
m_supportsWriting(false),
m_supportsMoving(false),
m_supportsPrivilegeExecution(false),
m_isLocal(true)
{ }
: m_isDirectory(false)
, m_isFile(false)
, m_supportsReading(false)
, m_supportsDeleting(false)
, m_supportsWriting(false)
, m_supportsMoving(false)
, m_isLocal(true)
{
}
void setItems(const KFileItemList &items);
void determineMimeTypeAndGroup() const;
......@@ -45,9 +40,7 @@ public:
bool m_supportsDeleting : 1;
bool m_supportsWriting : 1;
bool m_supportsMoving : 1;
bool m_supportsPrivilegeExecution : 1;
bool m_isLocal : 1;
bool m_isOwner : 1;
};
KFileItemListProperties::KFileItemListProperties()
......@@ -76,7 +69,6 @@ void KFileItemListPropertiesPrivate::setItems(const KFileItemList &items)
m_supportsMoving = initialValue;
m_isDirectory = initialValue;
m_isFile = initialValue;
m_isOwner = true;
m_isLocal = true;
m_mimeType.clear();
m_mimeGroup.clear();
......@@ -86,14 +78,10 @@ void KFileItemListPropertiesPrivate::setItems(const KFileItemList &items)
bool isLocal = false;
const QUrl url = item.mostLocalUrl(&isLocal);
m_isLocal = m_isLocal && isLocal;
m_supportsPrivilegeExecution = KProtocolManager::supportsPrivilegeExecution(url);
#ifndef Q_OS_WIN
m_isOwner = m_isOwner && (item.user() == KUser(getuid()).loginName());
#endif
m_supportsReading = m_supportsReading && KProtocolManager::supportsReading(url);
m_supportsReading = m_supportsReading && KProtocolManager::supportsReading(url);
m_supportsDeleting = m_supportsDeleting && KProtocolManager::supportsDeleting(url);
m_supportsWriting = m_supportsWriting && KProtocolManager::supportsWriting(url) && (m_supportsPrivilegeExecution || item.isWritable());
m_supportsMoving = m_supportsMoving && KProtocolManager::supportsMoving(url);
m_supportsWriting = m_supportsWriting && KProtocolManager::supportsWriting(url) && item.isWritable();
m_supportsMoving = m_supportsMoving && KProtocolManager::supportsMoving(url);
// For local files we can do better: check if we have write permission in parent directory
// TODO: if we knew about the parent KFileItem, we could even do that for remote protocols too
......@@ -103,7 +91,7 @@ void KFileItemListPropertiesPrivate::setItems(const KFileItemList &items)
if (parentDirInfo.filePath() != directory) {
parentDirInfo.setFile(directory);
}
if (!parentDirInfo.isWritable() && !m_supportsPrivilegeExecution) {
if (!parentDirInfo.isWritable()) {
m_supportsDeleting = false;
m_supportsMoving = false;
}
......@@ -144,11 +132,6 @@ bool KFileItemListProperties::supportsReading() const
return d->m_supportsReading;
}
bool KFileItemListProperties::isOwner() const
{
return d->m_isOwner;
}
bool KFileItemListProperties::supportsDeleting() const
{
return d->m_supportsDeleting;
......
......@@ -121,12 +121,6 @@ public:
*/
QString mimeType() const;
/**
* @return Whether all items are owned by the current user
* @since dunno
*/
bool isOwner() const;
/**
* @return the MIME type group (e.g. "text") of all items, if they all have the same, otherwise an empty string
*/
......
......@@ -47,7 +47,6 @@ KProtocolInfoPrivate::KProtocolInfoPrivate(const QString &path)
m_canRenameFromFile = config.readEntry("renameFromFile", false);
m_canRenameToFile = config.readEntry("renameToFile", false);
m_canDeleteRecursive = config.readEntry("deleteRecursive", false);
m_supportsPrivilegeExecution = config.readEntry("privilegeExecution", false);
const QString fnu = config.readEntry("fileNameUsedForCopying", "FromURL");
m_fileNameUsedForCopying = KProtocolInfo::FromUrl;
if (fnu == QLatin1String("Name")) {
......@@ -139,7 +138,6 @@ KProtocolInfoPrivate::KProtocolInfoPrivate(const QString &name, const QString &e
m_canRenameFromFile = json.value(QStringLiteral("renameFromFile")).toBool();
m_canRenameToFile = json.value(QStringLiteral("renameToFile")).toBool();
m_canDeleteRecursive = json.value(QStringLiteral("deleteRecursive")).toBool();
m_supportsPrivilegeExecution = json.value(QStringLiteral("privilegeExecution")).toBool();
// default is "FromURL"
const QString fnu = json.value(QStringLiteral("fileNameUsedForCopying")).toString();
......
......@@ -48,7 +48,6 @@ public:
bool m_canRenameFromFile : 1;
bool m_canRenameToFile : 1;
bool m_canDeleteRecursive : 1;
bool m_supportsPrivilegeExecution : 1;
QString m_defaultMimetype;
QString m_icon;
QString m_config;
......
......@@ -1107,16 +1107,6 @@ bool KProtocolManager::supportsTruncating(const QUrl &url)
return prot->m_supportsTruncating;
}
bool KProtocolManager::supportsPrivilegeExecution(const QUrl &url)
{
KProtocolInfoPrivate *prot = findProtocol(url);
if (!prot) {
return false;
}
return prot->m_supportsPrivilegeExecution;
}
bool KProtocolManager::canCopyFromFile(const QUrl &url)
{
KProtocolInfoPrivate *prot = findProtocol(url);
......
......@@ -627,18 +627,6 @@ public:
* @since 4.1
*/
static QString protocolForArchiveMimetype(const QString &mimeType);
/**
* Returns whether the protocol can modify file system with elevated privileges.
*
* This corresponds to the "privilegeExecution=" field in the protocol description
* file. Valid values for this field are "true" or "false" (default).
*
* @param url the url to check
* @return true if protocol supports privilege execution
* @since 5.80
*/
static bool supportsPrivilegeExecution(const QUrl &url);
/*=============================== OTHERS ====================================*/
......
......@@ -219,7 +219,7 @@ void FileProtocol::mkdir(const QUrl &url, int permissions)
if (QT_LSTAT(QFile::encodeName(path).constData(), &buff) == -1) {
bool dirCreated = QDir().mkdir(path);
if (!dirCreated) {
if (auto err = execWithElevatedPrivilege(MKDIR, {path, permissions}, errno)) {
if (auto err = execWithElevatedPrivilege(MKDIR, {path}, errno)) {
if (!err.wasCanceled()) {
// TODO: add access denied & disk full (or another reasons) handling (into Qt, possibly)
error(KIO::ERR_CANNOT_MKDIR, path);
......
......@@ -28,8 +28,7 @@
"output": "filesystem",
"protocol": "file",
"reading": true,
"writing": true,
"privilegeExecution": true
"writing": true
}
}
}
......@@ -21,7 +21,6 @@ enum ActionType {
RMDIR,
SYMLINK,
UTIME,
COPY,
};
/**
......
......@@ -504,8 +504,14 @@ static bool createUDSEntry(const QString &filename, const QByteArray &path, UDSE
return true;
}
QIODevice::OpenMode openModeFromFlags(int flags)
PrivilegeOperationReturnValue FileProtocol::tryOpen(QFile &f, const QByteArray &path, int flags, int mode, int errcode)
{
const QString sockPath = socketPath();
FdReceiver fdRecv(QFile::encodeName(sockPath).toStdString());
if (!fdRecv.isListening()) {
return PrivilegeOperationReturnValue::failure(errcode);
}
QIODevice::OpenMode openMode;
if (flags & O_RDONLY) {
openMode |= QIODevice::ReadOnly;
......@@ -523,19 +529,6 @@ QIODevice::OpenMode openModeFromFlags(int flags)
openMode |= QIODevice::Append;
}
return openMode;
}
PrivilegeOperationReturnValue FileProtocol::tryOpen(QFile &f, const QByteArray &path, int flags, int mode, int errcode)
{
const QString sockPath = socketPath();
FdReceiver fdRecv(QFile::encodeName(sockPath).toStdString());
if (!fdRecv.isListening()) {
return PrivilegeOperationReturnValue::failure(errcode);
}
auto openMode = openModeFromFlags(flags);
if (auto err = execWithElevatedPrivilege(OPEN, {path, flags, mode, sockPath}, errcode)) {
return err;
} else {
......@@ -551,7 +544,7 @@ PrivilegeOperationReturnValue FileProtocol::tryChangeFileAttr(ActionType action,
{
KAuth::Action execAction(QStringLiteral("org.kde.kio.file.exec"));
execAction.setHelperId(QStringLiteral("org.kde.kio.file"));
if (execAction.status() == KAuth::Action::AuthorizedStatus || execAction.status() == KAuth::Action::AuthRequiredStatus) {
if (execAction.status() == KAuth::Action::AuthorizedStatus) {
return execWithElevatedPrivilege(action, args, errcode);
}
return PrivilegeOperationReturnValue::failure(errcode);
......@@ -681,21 +674,6 @@ void FileProtocol::copy(const QUrl &srcUrl, const QUrl &destUrl, int _mode, JobF
return;
}
goto notAuth;
auth: {
auto err = execWithElevatedPrivilege(COPY, {srcUrl, destUrl}, errno);
if (err) {
if (!err.wasCanceled()) {
error(KIO::ERR_UNKNOWN, QString());
}
} else {
finished();
}
return;
}
notAuth:
qCDebug(KIO_FILE) << "copy()" << srcUrl << "to" << destUrl << "mode=" << _mode;
const QString src = srcUrl.toLocalFile();
......@@ -763,7 +741,12 @@ notAuth:
QFile srcFile(src);
if (!srcFile.open(QIODevice::ReadOnly)) {
goto auth;
if (auto err = tryOpen(srcFile, _src, O_RDONLY, S_IRUSR, errno)) {
if (!err.wasCanceled()) {
error(KIO::ERR_CANNOT_OPEN_FOR_READING, src);
}
return;
}
}
#if HAVE_FADVISE
......@@ -772,7 +755,17 @@ notAuth:
QFile destFile(dest);
if (!destFile.open(QIODevice::Truncate | QIODevice::WriteOnly)) {
goto auth;
if (auto err = tryOpen(destFile, _dest, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR, errno)) {
if (!err.wasCanceled()) {
// qDebug() << "###### COULD NOT WRITE " << dest;
if (err == EACCES) {
error(KIO::ERR_WRITE_ACCESS_DENIED, dest);
} else {
error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest);
}
}
return;
}
}
// _mode == -1 means don't touch dest permissions, leave it with the system default ones
......@@ -1465,60 +1458,39 @@ void FileProtocol::stat(const QUrl &url)
finished();
}
static int lock()
{
auto fid = open("/tmp/kio-kauth-filehelper-long-randomish-name", O_RDWR | O_CREAT, 0644);
if (fid < 0) {
return -1;
}
if (lockf(fid, F_LOCK, 0) == -1) {
close(fid);
return -1;
}
return fid;
}
static bool unlock(int fid)
{
if (lockf(fid, F_ULOCK, 0) == -1) {
return false;
}
if (close(fid) < 0) {
return false;
}
return true;
}
PrivilegeOperationReturnValue FileProtocol::execWithElevatedPrivilege(ActionType action, const QVariantList &args, int errcode)
{
if (privilegeOperationUnitTestMode()) {
return PrivilegeOperationReturnValue::success();
}
// temporarily disable privilege execution
if (true) {
return PrivilegeOperationReturnValue::failure(errcode);
}
if (!(errcode == EACCES || errcode == EPERM)) {
return PrivilegeOperationReturnValue::failure(errcode);
}
const QString operationDetails = actionDetails(action, args);
KIO::PrivilegeOperationStatus opStatus = requestPrivilegeOperation(operationDetails);
if (opStatus != KIO::OperationAllowed) {
if (opStatus == KIO::OperationCanceled) {
error(KIO::ERR_USER_CANCELED, QString());
return PrivilegeOperationReturnValue::canceled();
}
return PrivilegeOperationReturnValue::failure(errcode);
}
const QUrl targetUrl = QUrl::fromLocalFile(args.first().toString()); // target is always the first item.
const bool useParent = action != CHOWN && action != CHMOD && action != UTIME;
const QString targetPath = useParent ? targetUrl.adjusted(QUrl::RemoveFilename).toLocalFile() : targetUrl.toLocalFile();
bool userIsOwner = QFileInfo(targetPath).ownerId() == getuid();
if (args.length() > 1) {
const QUrl otherURL = QUrl::fromLocalFile(args[1].toString()); // target is always the first item.
const bool useParent = action != CHOWN && action != CHMOD && action != UTIME;
const QString otherPath = useParent ? otherURL.adjusted(QUrl::RemoveFilename).toLocalFile() : otherURL.toLocalFile();
userIsOwner = userIsOwner && QFileInfo(otherPath).ownerId() == getuid();
if (action == RENAME) { // for rename check src and dest owner
QString dest = QUrl(args[1].toString()).toLocalFile();
userIsOwner = userIsOwner && QFileInfo(dest).ownerId() == getuid();
}
if (userIsOwner) {
error(KIO::ERR_PRIVILEGE_NOT_REQUIRED, targetPath);
return PrivilegeOperationReturnValue::canceled();
......@@ -1539,39 +1511,12 @@ PrivilegeOperationReturnValue FileProtocol::execWithElevatedPrivilege(ActionType
argv.insert(QStringLiteral("arguments"), helperArgs);
execAction.setArguments(argv);
const auto actionHelper = [](ActionType action) -> QString {
switch (action) {
case ActionType::CHMOD: return i18n("Authentication is required to change this file's permissions.");
case ActionType::CHOWN: return i18n("Authentication is required to change who owns this file.");
case ActionType::DEL: return i18n("Authentication is required to delete this file.");
case ActionType::MKDIR: return i18n("Authentication is required to create a folder.");
case ActionType::OPEN: return i18n("Authentication is required to open this file.");
case ActionType::OPENDIR: return i18n("Authentication is required to open this folder.");
case ActionType::RENAME: return i18n("Authentication is required to rename this file.");
case ActionType::RMDIR: return i18n("Authentication is required to delete this folder.");
case ActionType::SYMLINK: return i18n("Authentication is required to create a symlink.");
case ActionType::UTIME: return i18n("Authentication is required to modify this file's last updated time.");
case ActionType::COPY: return i18n("Authentication is required to copy this item.");
case ActionType::UNKNOWN: return i18n("Authentication is required to perform this action.");
}
Q_UNREACHABLE();
return QString();
};
KAuth::Action::DetailsMap details;
details.insert(KAuth::Action::AuthDetail::DetailMessage, actionHelper(action));
execAction.setDetailsV2(details);
auto lid = lock();
auto reply = execAction.execute();
if (reply->exec()) {
addTemporaryAuthorization(actionId);
unlock(lid);
return PrivilegeOperationReturnValue::success();
}
unlock(lid);
return PrivilegeOperationReturnValue::failure(KIO::ERR_ACCESS_DENIED);
}
......
add_executable(file_helper filehelper.cpp fdsender.cpp)
target_link_libraries(file_helper Qt${QT_MAJOR_VERSION}::Network KF5::AuthCore KF5::I18n KF5::KIOCore)
install(TARGETS file_helper DESTINATION ${KAUTH_HELPER_INSTALL_DIR})
kauth_install_helper_files(file_helper org.kde.kio.file root)
kauth_install_actions(org.kde.kio.file file.actions)
#install(TARGETS file_helper DESTINATION ${KAUTH_HELPER_INSTALL_DIR})
#kauth_install_helper_files(file_helper org.kde.kio.file root)
#kauth_install_actions(org.kde.kio.file file.actions)
......@@ -87,4 +87,3 @@ Description[x-test]=xxRoot privileges are required to complete the action.xx
Description[zh_CN]=完成操作需要 Root 权限。
Description[zh_TW]=完成動作需要 root 權限。
Policy=auth_admin
Persistence=session
......@@ -12,7 +12,6 @@
#include <libgen.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/types.h>
#include <unistd.h>
#include <utime.h>
......@@ -39,18 +38,28 @@ struct Privilege {
static ActionType intToActionType(int action)
{
switch (action) {
case 1: return CHMOD;
case 2: return CHOWN;
case 3: return DEL;
case 4: return MKDIR;
case 5: return OPEN;
case 6: return OPENDIR;
case 7: return RENAME;
case 8: return RMDIR;
case 9: return SYMLINK;
case 10: return UTIME;
case 11: return COPY;
default: return UNKNOWN;
case 1:
return CHMOD;
case 2:
return CHOWN;
case 3:
return DEL;
case 4:
return MKDIR;
case 5:
return OPEN;
case 6:
return OPENDIR;
case 7:
return RENAME;
case 8:
return RMDIR;
case 9:
return SYMLINK;
case 10:
return UTIME;
default:
return UNKNOWN;
}
}
......@@ -238,7 +247,6 @@ ActionReply FileHelper::exec(const QVariantMap &args)
}
case UTIME: {
qWarning() << "utime";
timespec times[2];
time_t actime = arg2.toULongLong();
time_t modtime = arg3.toULongLong();
......@@ -252,59 +260,6 @@ ActionReply FileHelper::exec(const QVariantMap &args)
break;
}
// a lil macro to make the process of handling failure less repetitive
#define bailOnFail(cond) if (!cond) { reply.setError(EIO); return reply; }
case COPY: {
const auto src = arg1.toUrl();
const auto dest = arg2.toUrl();
QFileInfo srcFI(src.toLocalFile());
QFileInfo destFI(dest.toLocalFile());
if (!srcFI.exists()) {
reply.setError(ENOENT);
return reply;
}
if (!destFI.exists()) {
if (dest.toLocalFile().endsWith(QStringLiteral("/"))) {
reply.setError(ENOENT);
return reply;
}
bailOnFail(QFile::copy(srcFI.absoluteFilePath(), dest.toLocalFile()));
QFile dst(dest.toLocalFile());
bailOnFail(dst.open(QFile::ReadWrite));
bailOnFail(dst.setFileTime(srcFI.fileTime(QFileDevice::FileAccessTime), QFileDevice::FileAccessTime));
bailOnFail(dst.setFileTime(srcFI.fileTime(QFileDevice::FileModificationTime), QFileDevice::FileModificationTime));
} else {
if (srcFI.isFile() && destFI.isDir()) {
bailOnFail(QFile::copy(srcFI.absoluteFilePath(), destFI.absoluteFilePath()));
const auto path = QDir::cleanPath(destFI.absoluteFilePath() + QStringLiteral("/") + srcFI.baseName());
QFile dst(path);
bailOnFail(dst.open(QFile::ReadWrite));
bailOnFail(dst.setFileTime(srcFI.fileTime(QFileDevice::FileAccessTime), QFileDevice::FileAccessTime));
bailOnFail(dst.setFileTime(srcFI.fileTime(QFileDevice::FileModificationTime), QFileDevice::FileModificationTime));
} else if (srcFI.isFile() && destFI.isFile()) {
bailOnFail(QFile::remove(destFI.absoluteFilePath()));
bailOnFail(QFile::copy(srcFI.absoluteFilePath(), destFI.absoluteFilePath()));
QFile dst(dest.toLocalFile());
bailOnFail(dst.open(QFile::ReadWrite));
bailOnFail(dst.setFileTime(srcFI.fileTime(QFileDevice::FileAccessTime), QFileDevice::FileAccessTime));
bailOnFail(dst.setFileTime(srcFI.fileTime(QFileDevice::FileModificationTime), QFileDevice::FileModificationTime));
} else if (srcFI.isDir() && destFI.isFile()) {
reply.setError(EINVAL);
return reply;
} else if (srcFI.isDir() && destFI.isDir()) {
bailOnFail(QFile::copy(srcFI.absoluteFilePath(), destFI.absoluteFilePath()));
} else {
Q_UNREACHABLE();
}
}
}
default:
reply.setError(ENOTSUP);
break;
......
......@@ -1808,10 +1808,7 @@ KFilePermissionsPropsPlugin::KFilePermissionsPropsPlugin(KPropertiesDialog *_pro
isMyFile = true;
}
// if it's local, we could potentially raise privileges with an
// auth dialog. but we can't possibly know if we can until we
// actually attempt to do an action.
d->canChangePermissions = isLocal || ((isMyFile || IamRoot) && (!isLink));
d->canChangePermissions = (isMyFile || IamRoot) && (!isLink);
// create GUI
......
......@@ -52,13 +52,4 @@ KIOWIDGETS_EXECUTABLE_TESTS(
previewtest
${runapplication_EXE}
)
add_executable(kauth_tester kauth_tester.cpp)
target_link_libraries(kauth_tester
KF5::KIOCore
KF5::KIOGui
KF5::KIOWidgets
KF5::KIOFileWidgets
KF5::WidgetsAddons
KF5::IconThemes
)
endif()
#include <QApplication>
#include <QDebug>
#include <QDir>
#include <KIO/FileUndoManager>
#include <KIO/CopyJob>
#include <KIO/DeleteJob>
#include <KIO/SimpleJob>
#include <KIO/MkdirJob>