Index: src/ioslaves/file/file.h =================================================================== --- src/ioslaves/file/file.h +++ src/ioslaves/file/file.h @@ -105,6 +105,7 @@ PrivilegeOperationReturnValue execWithElevatedPrivilege(ActionType action, const QVariant &arg1, const QVariant &arg2 = QVariant(), const QVariant &arg3 = QVariant()); + PrivilegeOperationReturnValue tryOpen(QFile &f, const QByteArray &path, int flags, int mode); private: mutable QHash mUsercache; mutable QHash mGroupcache; Index: src/ioslaves/file/file_unix.cpp =================================================================== --- src/ioslaves/file/file_unix.cpp +++ src/ioslaves/file/file_unix.cpp @@ -41,6 +41,8 @@ #include +#include "sharefd.h" + //sendfile has different semantics in different platforms #if defined HAVE_SENDFILE && defined Q_OS_LINUX #define USE_SENDFILE 1 @@ -70,6 +72,45 @@ return QStringLiteral("org_kde_kio_file_helper_%1").arg(getpid()); } +PrivilegeOperationReturnValue FileProtocol::tryOpen(QFile &f, const QByteArray &path, int flags, int mode) +{ + FdReceiver fdRecv(socketPath()); + if (!fdRecv.isValid()) { + return PrivilegeOperationReturnValue::failure(); + } + + int fd = fdRecv.fileDescriptor(); + if (fd == -1) { + return PrivilegeOperationReturnValue::failure(); + } + + QIODevice::OpenMode openMode; + if (flags & O_RDONLY) { + openMode |= QIODevice::ReadOnly; + } + if (flags & O_WRONLY || flags & O_CREAT) { + openMode |= QIODevice::WriteOnly; + } + if (flags & O_RDWR) { + openMode |= QIODevice::ReadWrite; + } + if (flags & O_TRUNC) { + openMode |= QIODevice::Truncate; + } + if (flags & O_APPEND) { + openMode |= QIODevice::Append; + } + + if (auto err = execWithElevatedPrivilege(OPEN, path, flags, mode)) { + return err; + } else { + if (!f.open(fd, openMode, QFileDevice::AutoCloseHandle)) { + return PrivilegeOperationReturnValue::failure(); + } + } + return PrivilegeOperationReturnValue::success(); +} + void FileProtocol::copy(const QUrl &srcUrl, const QUrl &destUrl, int _mode, JobFlags _flags) { @@ -125,34 +166,60 @@ // the symlink actually points to current source! if ((_flags & KIO::Overwrite) && ((buff_dest.st_mode & QT_STAT_MASK) == QT_STAT_LNK)) { //qDebug() << "copy(): LINK DESTINATION"; - QFile::remove(dest); + if (!QFile::remove(dest)) { + if (auto err = execWithElevatedPrivilege(DEL, _dest)) { + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_DELETE_ORIGINAL, dest); + } + return; + } + } } } QFile src_file(src); if (!src_file.open(QIODevice::ReadOnly)) { - error(KIO::ERR_CANNOT_OPEN_FOR_READING, src); - return; + if (auto err = tryOpen(src_file, _src, O_RDONLY, S_IRUSR)) { + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_OPEN_FOR_READING, src); + } + return; + } } #if HAVE_FADVISE posix_fadvise(src_file.handle(), 0, 0, POSIX_FADV_SEQUENTIAL); #endif QFile dest_file(dest); if (!dest_file.open(QIODevice::Truncate | QIODevice::WriteOnly)) { - // qDebug() << "###### COULD NOT WRITE " << dest; - if (errno == EACCES) { - error(KIO::ERR_WRITE_ACCESS_DENIED, dest); - } else { - error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest); + if (auto err = tryOpen(dest_file, _dest, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR)) { + if (!err.wasCanceled()) { + // qDebug() << "###### COULD NOT WRITE " << dest; + if (errno == EACCES) { + error(KIO::ERR_WRITE_ACCESS_DENIED, dest); + } else { + error(KIO::ERR_CANNOT_OPEN_FOR_WRITING, dest); + } + } + src_file.close(); + return; } - src_file.close(); - return; } // nobody shall be allowed to peek into the file during creation - dest_file.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner); + if (!dest_file.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner)) { + if (auto err = execWithElevatedPrivilege(CHOWN, _dest, getuid(), getgid())) { + dest_file.close(); + execWithElevatedPrivilege(DEL, _dest); + if (!err.wasCanceled()) { + error(KIO::ERR_CANNOT_CHOWN, dest); + } + return; + } else { + dest_file.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner); + } + } #if HAVE_FADVISE posix_fadvise(dest_file.handle(), 0, 0, POSIX_FADV_SEQUENTIAL); @@ -213,7 +280,9 @@ acl_free(acl); } #endif - dest_file.remove(); // don't keep partly copied file + if (!QFile::remove(dest)) { // don't keep partly copied file + execWithElevatedPrivilege(DEL, _dest); + } return; } if (n == 0) { @@ -234,7 +303,9 @@ acl_free(acl); } #endif - dest_file.remove(); // don't keep partly copied file + if (!QFile::remove(dest)) { // don't keep partly copied file + execWithElevatedPrivilege(DEL, _dest); + } return; } processed_size += n; @@ -255,7 +326,9 @@ acl_free(acl); } #endif - dest_file.remove(); // don't keep partly copied file + if (!QFile::remove(dest)) { // don't keep partly copied file + execWithElevatedPrivilege(DEL, _dest); + } return; } @@ -270,10 +343,10 @@ || (acl && acl_set_file(_dest.data(), ACL_TYPE_ACCESS, acl) != 0) #endif ) { - KMountPoint::Ptr mp = KMountPoint::currentMountPoints().findByPath(dest); - // Eat the error if the filesystem apparently doesn't support chmod. - if (mp && mp->testFileSystemFlag(KMountPoint::SupportsChmod)) { - warning(i18n("Could not change permissions for '%1'", dest)); + if (auto err = execWithElevatedPrivilege(CHMOD, _dest, _mode)) { + if (!err.wasCanceled()) { + warning(i18n("Could not change permissions for '%1'", dest)); + } } } #if HAVE_POSIX_ACL @@ -288,15 +361,19 @@ // we might not be allowed to change the owner (void)::chown(_dest.data(), buff_src.st_uid, -1 /*keep group*/); } else { - qCWarning(KIO_FILE) << QStringLiteral("Couldn't preserve group for '%1'").arg(dest); + if (execWithElevatedPrivilege(CHOWN, _dest, buff_src.st_uid, buff_src.st_gid)) { + qCWarning(KIO_FILE) << QStringLiteral("Couldn't preserve group for '%1'").arg(dest); + } } // copy access and modification time struct utimbuf ut; ut.actime = buff_src.st_atime; ut.modtime = buff_src.st_mtime; if (::utime(_dest.data(), &ut) != 0) { - qCWarning(KIO_FILE) << QStringLiteral("Couldn't preserve access and modification time for '%1'").arg(dest); + if (execWithElevatedPrivilege(UTIME, _dest, qint64(ut.actime), qint64(ut.modtime))) { + qCWarning(KIO_FILE) << QStringLiteral("Couldn't preserve access and modification time for '%1'").arg(dest); + } } processedSize(buff_src.st_size);