Commit e4c2c36a authored by Corbin Schwimmbeck's avatar Corbin Schwimmbeck Committed by Laurent Montel
Browse files

Remove running as root and implement temporary authorization.

Previously the application would offer system cron (through ctGlobalCron) while running as root, however, this has been replaced with system cron gaining temporary root permissions through KAuth.
parent 50effd71
......@@ -26,10 +26,13 @@ find_package (Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS
find_package(KF5 REQUIRED COMPONENTS
ConfigWidgets
CoreAddons
DocTools
Auth
I18n
KIO
)
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050f00)
add_definitions(-DKF_DISABLE_DEPRECATED_BEFORE_AND_AT=0x055600)
......
......@@ -21,7 +21,6 @@ target_sources(kcm_cron PRIVATE
crontablib/cttask.cpp
crontablib/ctunit.cpp
crontablib/ctvariable.cpp
crontablib/ctGlobalCron.cpp
crontablib/ctSystemCron.cpp
crontablib/ctInitializationError.cpp
crontablib/ctSaveStatus.cpp
......@@ -54,8 +53,12 @@ target_link_libraries(kcm_cron
KF5::ConfigWidgets
KF5::I18n
KF5::KIOWidgets
KF5::CoreAddons
KF5::Auth
)
install(TARGETS kcm_cron DESTINATION ${KDE_INSTALL_PLUGINDIR} )
# For root permissions.
add_subdirectory(helper)
install(FILES kcm_cron.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} )
......@@ -26,7 +26,6 @@
#include <QAction>
#include <QIcon>
#include "ctGlobalCron.h"
#include "ctcron.h"
#include "cthost.h"
#include "cttask.h"
......@@ -41,19 +40,11 @@
#include "kcm_cron_debug.h"
class CTGlobalCron;
CrontabWidget::CrontabWidget(QWidget *parent, CTHost *ctHost)
: QWidget(parent)
{
mCtHost = ctHost;
if (mCtHost->isRootUser()) {
mCtGlobalCron = new CTGlobalCron(mCtHost);
} else {
mCtGlobalCron = nullptr;
}
setupActions();
initialize();
......@@ -76,8 +67,6 @@ CrontabWidget::~CrontabWidget()
{
delete mTasksWidget;
delete mVariablesWidget;
delete mCtGlobalCron;
}
bool CrontabWidget::hasClipboardContent()
......@@ -110,40 +99,7 @@ QHBoxLayout *CrontabWidget::createCronSelector()
group->addButton(mSystemCronRadio);
layout->addWidget(mSystemCronRadio);
mOtherUserCronRadio = new QRadioButton(i18n("Cron of User:"), this);
group->addButton(mOtherUserCronRadio);
mOtherUsers = new QComboBox(this);
layout->addWidget(mOtherUserCronRadio);
layout->addWidget(mOtherUsers);
if (ctHost()->isRootUser()) {
QStringList users;
const auto crons = ctHost()->mCrons;
for (CTCron *ctCron : crons) {
if (ctCron->isCurrentUserCron()) {
continue;
}
if (ctCron->isSystemCron()) {
continue;
}
users.append(ctCron->userLogin());
}
users.sort();
mOtherUsers->addItems(users);
mOtherUsers->addItem(QIcon::fromTheme(QStringLiteral("users")), i18n("Show All Personal Crons"));
} else {
mOtherUserCronRadio->hide();
mOtherUsers->hide();
}
connect(group, static_cast<void (QButtonGroup::*)(QAbstractButton *)>(&QButtonGroup::buttonClicked), this, &CrontabWidget::refreshCron);
connect(mOtherUsers, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &CrontabWidget::checkOtherUsers);
layout->addStretch(1);
......@@ -183,25 +139,12 @@ void CrontabWidget::refreshCron()
mTasksWidget->refreshTasks(ctCron);
mVariablesWidget->refreshVariables(ctCron);
if (ctCron->isMultiUserCron() && !ctHost()->isRootUser()) {
qCDebug(KCM_CRON_LOG) << "Disabling view...";
mTasksWidget->treeWidget()->setEnabled(false);
mVariablesWidget->treeWidget()->setEnabled(false);
toggleNewEntryActions(false);
toggleModificationActions(false);
togglePasteAction(false);
mTasksWidget->toggleRunNowAction(false);
} else {
qCDebug(KCM_CRON_LOG) << "Enabling view...";
mTasksWidget->treeWidget()->setEnabled(true);
mVariablesWidget->treeWidget()->setEnabled(true);
mTasksWidget->treeWidget()->setEnabled(true);
mVariablesWidget->treeWidget()->setEnabled(true);
toggleNewEntryActions(true);
togglePasteAction(hasClipboardContent());
}
toggleNewEntryActions(true);
togglePasteAction(hasClipboardContent());
}
void CrontabWidget::copy()
......@@ -281,19 +224,13 @@ void CrontabWidget::paste()
CTCron *CrontabWidget::currentCron() const
{
// Checks which mode the gui is in, either user cron or system cron,
// returning the appropriate cron.
if (mCurrentUserCronRadio->isChecked()) {
return mCtHost->findCurrentUserCron();
} else if (mSystemCronRadio->isChecked()) {
} else {
return mCtHost->findSystemCron();
}
if (mOtherUsers->currentIndex() == mOtherUsers->count() - 1) {
qCDebug(KCM_CRON_LOG) << "Using Global Cron";
return mCtGlobalCron;
}
QString currentUserLogin = mOtherUsers->currentText();
return mCtHost->findUserCron(currentUserLogin);
}
TasksWidget *CrontabWidget::tasksWidget() const
......
......@@ -19,7 +19,6 @@ class CTHost;
class CTCron;
class QRadioButton;
class QComboBox;
class CTGlobalCron;
/**
* Main GUI view of the crontab entries.
......@@ -139,9 +138,5 @@ private:
QComboBox *mOtherUsers = nullptr;
/**
* Pointer to the pseudo Global Cron object
*/
CTGlobalCron *mCtGlobalCron = nullptr;
};
......@@ -42,7 +42,7 @@ CTSystemCron::CTSystemCron(const QString &crontabBinary)
d->writeCommandLine.parameters << d->tmpFileName;
d->writeCommandLine.standardOutputFile = QStringLiteral("/etc/crontab");
d->userLogin = i18n("System Crontab");
d->userLogin = i18n("root");
d->userRealName = d->userLogin;
d->initialTaskCount = 0;
......
......@@ -22,6 +22,10 @@
#include "cttask.h"
#include "ctvariable.h"
// For root permissions
#include <KAuthAction>
#include <KAuthExecuteJob>
#include <pwd.h> // pwd, getpwnam(), getpwuid()
#include <unistd.h> // getuid(), unlink()
......@@ -306,14 +310,30 @@ CTSaveStatus CTCron::save()
return CTSaveStatus(i18n("Unable to open crontab file for writing"), i18n("The file %1 could not be opened.", d->tmpFileName));
}
CommandLineStatus commandLineStatus = d->writeCommandLine.execute();
// install temp file into crontab
if (commandLineStatus.exitCode != 0) {
// For root permissions.
if (d->systemCron) {
qCDebug(KCM_CRON_LOG) << "Attempting to save system cron";
QVariantMap args;
args.insert(QLatin1String("source"), d->tmpFileName);
args.insert(QLatin1String("target"), d->writeCommandLine.standardOutputFile);
KAuth::Action saveAction(QLatin1String("local.kcron.crontab.save"));
saveAction.setHelperId(QLatin1String("local.kcron.crontab"));
saveAction.setArguments(args);
KAuth::ExecuteJob *job = saveAction.execute();
if (!job->exec())
qCDebug(KCM_CRON_LOG) << "KAuth returned an error: " << job->error() << job->errorText();
QFile::remove(d->tmpFileName);
return prepareSaveStatusError(commandLineStatus);
} else {
// Remove the temp file
if (job->error() > 0)
return CTSaveStatus(i18n("KAuth::ExecuteJob Error"), job->errorText());
}
// End root permissions.
else {
qCDebug(KCM_CRON_LOG) << "Attempting to save user cron";
// Save without root permissions.
CommandLineStatus commandLineStatus = d->writeCommandLine.execute();
QFile::remove(d->tmpFileName);
if (commandLineStatus.exitCode != 0)
return prepareSaveStatusError(commandLineStatus);
}
// Mark as applied
......
......@@ -18,6 +18,8 @@
#include <KLocalizedString>
#include "crontabWidget.h"
#include "ctInitializationError.h"
#include "ctSystemCron.h"
#include "ctcron.h"
......@@ -122,25 +124,14 @@ bool CTHost::allowDeny(char *name)
}
}
CTSaveStatus CTHost::save()
CTSaveStatus CTHost::save(CrontabWidget *mCrontabWidget)
{
if (!isRootUser()) {
qCDebug(KCM_CRON_LOG) << "Save current user cron";
CTCron *ctCron = findCurrentUserCron();
return ctCron->save();
}
qCDebug(KCM_CRON_LOG) << "Save current cron.";
// Retrieve the current cron to use. This could either be a user cron or a system cron.
// Implements system cron entry point.
CTCron *ctCron = mCrontabWidget->currentCron();
for (CTCron *ctCron : std::as_const(mCrons)) {
const CTSaveStatus ctSaveStatus = ctCron->save();
if (ctSaveStatus.isError()) {
return CTSaveStatus(i18nc("User login: errorMessage", "User %1: %2", ctCron->userLogin(), ctSaveStatus.errorMessage()),
ctSaveStatus.detailErrorMessage());
}
}
return CTSaveStatus();
return ctCron->save();
}
void CTHost::cancel()
......@@ -250,8 +241,3 @@ CTCron *CTHost::findCronContaining(CTVariable *ctVariable) const
qCDebug(KCM_CRON_LOG) << "Unable to find the cron of this variable. Please report this bug and your crontab config to the developers.";
return nullptr;
}
bool CTHost::isRootUser() const
{
return getuid() == 0;
}
......@@ -17,6 +17,7 @@ class CTTask;
class CTVariable;
class CTCron;
class CTInitializationError;
class CrontabWidget;
struct passwd;
......@@ -50,7 +51,7 @@ public:
* Apply changes.
* return an empty string if no problem ocurred.
*/
CTSaveStatus save();
CTSaveStatus save(CrontabWidget *mCrontabWidget);
/**
* Cancel changes.
......
......@@ -91,7 +91,7 @@ void KCMCron::save()
{
qCDebug(KCM_CRON_LOG) << "Saving crontab...";
CTSaveStatus saveStatus = mCtHost->save();
CTSaveStatus saveStatus = mCtHost->save(mCrontabWidget);
if (saveStatus.isError()) {
KMessageBox::detailedError(this, saveStatus.errorMessage(), saveStatus.detailErrorMessage());
}
......@@ -107,22 +107,20 @@ void KCMCron::defaults()
bool KCMCron::init()
{
// Display greeting screen.
// if there currently are no scheduled tasks...
if (!mCtHost->isRootUser()) {
int taskCount = 0;
for (CTCron *ctCron : std::as_const(mCtHost->mCrons)) {
taskCount += ctCron->tasks().count();
}
if (taskCount == 0) {
show();
// TODO Add this as a passive popup/message/something else
KMessageBox::information(this,
i18n("You can use this application to schedule programs to run in the background.\nTo schedule a new task now, click on "
"the Tasks folder and select Edit/New from the menu."),
i18n("Welcome to the Task Scheduler"),
QStringLiteral("welcome"));
}
// If there currently are no scheduled tasks...
int taskCount = 0;
for (CTCron *ctCron : std::as_const(mCtHost->mCrons)) {
taskCount += ctCron->tasks().count();
}
if (taskCount == 0) {
show();
// TODO Add this as a passive popup/message/something else
KMessageBox::information(this,
i18n("You can use this application to schedule programs to run in the background.\nTo schedule a new task now, click on "
"the Tasks folder and select Edit/New from the menu."),
i18n("Welcome to the Task Scheduler"),
QStringLiteral("welcome"));
}
return true;
......
......@@ -10,6 +10,7 @@
#include <QComboBox>
#include <QFontMetrics>
#include <QString>
#include <QTextEdit>
#include "ctcron.h"
......@@ -20,16 +21,15 @@
void KCronHelper::initUserCombo(QComboBox *userCombo, CrontabWidget *crontabWidget, const QString &selectedUserLogin)
{
// This only applies to the System Crontab.
// Populate the "Run as:" combobox with the login names of all current crons,
// selecting the current user (root) as the default selection.
int userComboIndex = 0;
QStringList users;
int selectedIndex = 0;
const auto crons = crontabWidget->ctHost()->mCrons;
for (CTCron *ctCron : crons) {
if (ctCron->isSystemCron()) {
continue;
}
users.append(ctCron->userLogin());
// Select the actual user
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment