File indexing completed on 2024-05-05 05:48:31

0001 /*
0002     --------------------------------------------------------------------
0003     CT Host Implementation
0004     --------------------------------------------------------------------
0005     SPDX-FileCopyrightText: 1999 Gary Meyer <gary@meyer.net>
0006     --------------------------------------------------------------------
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "cthost.h"
0011 
0012 #include <pwd.h>
0013 #include <sys/types.h>
0014 #include <unistd.h> // getuid()
0015 
0016 #include <QFile>
0017 #include <QTextStream>
0018 
0019 #include <KLocalizedString>
0020 
0021 #include "crontabWidget.h"
0022 
0023 #include "ctInitializationError.h"
0024 #include "ctSystemCron.h"
0025 #include "ctcron.h"
0026 
0027 #include "kcm_cron_debug.h"
0028 
0029 CTHost::CTHost(const QString &cronBinary, CTInitializationError &ctInitializationError)
0030 {
0031     struct passwd *userInfos = nullptr;
0032 
0033     mCrontabBinary = cronBinary;
0034 
0035     // If it is the root user
0036     if (getuid() == 0) {
0037         // Read /etc/passwd
0038         setpwent(); // restart
0039         while ((userInfos = getpwent())) {
0040             if (allowDeny(userInfos->pw_name)) {
0041                 const QString errorMessage = createCTCron(userInfos);
0042                 if (!errorMessage.isEmpty()) {
0043                     ctInitializationError.setErrorMessage(errorMessage);
0044                     return;
0045                 }
0046             }
0047             // delete userInfos;
0048         }
0049         setpwent(); // restart again for others
0050     }
0051     // Non-root user, so just create user's cron table.
0052     else {
0053         // Get name from UID, check it against AllowDeny()
0054         unsigned int uid = getuid();
0055         setpwent(); // restart
0056         while ((userInfos = getpwent())) {
0057             if ((userInfos->pw_uid == uid) && (!allowDeny(userInfos->pw_name))) {
0058                 ctInitializationError.setErrorMessage(
0059                     i18n("You have been blocked from using KCron\
0060                           by either the /etc/cron.allow file or the /etc/cron.deny file.\
0061                           \n\nCheck the crontab man page for further details."));
0062 
0063                 return;
0064             }
0065             // delete userInfos;
0066         }
0067 
0068         setpwent(); // restart again for others
0069 
0070         passwd *currentUserPassword = getpwuid(uid);
0071 
0072         const QString errorMessage = createCTCron(currentUserPassword);
0073         if (!errorMessage.isEmpty()) {
0074             ctInitializationError.setErrorMessage(errorMessage);
0075             return;
0076         }
0077 
0078         // delete currentUserPassword;
0079     }
0080     // Create the system cron table.
0081     createSystemCron();
0082 }
0083 
0084 CTHost::~CTHost()
0085 {
0086     qDeleteAll(mCrons);
0087 }
0088 
0089 bool CTHost::allowDeny(char *name)
0090 {
0091     QFile allow(QStringLiteral("/etc/cron.allow"));
0092 
0093     // if cron.allow exists make sure user is listed
0094     if (allow.open(QFile::ReadOnly)) {
0095         QTextStream stream(&allow);
0096         while (!stream.atEnd()) {
0097             if (stream.readLine() == QLatin1String(name)) {
0098                 allow.close();
0099                 return true;
0100             }
0101         }
0102         allow.close();
0103         return false;
0104     } else {
0105         allow.close();
0106         QFile deny(QStringLiteral("/etc/cron.deny"));
0107 
0108         // else if cron.deny exists make sure user is not listed
0109         if (deny.open(QFile::ReadOnly)) {
0110             QTextStream stream(&deny);
0111             while (!stream.atEnd()) {
0112                 if (stream.readLine() == QLatin1String(name)) {
0113                     deny.close();
0114                     return false;
0115                 }
0116             }
0117             deny.close();
0118             return true;
0119         } else {
0120             deny.close();
0121             return true;
0122         }
0123     }
0124 }
0125 
0126 CTSaveStatus CTHost::save(CrontabWidget *mCrontabWidget)
0127 {
0128     qCDebug(KCM_CRON_LOG) << "Save current cron.";
0129     // Retrieve the current cron to use. This could either be a user cron or a system cron.
0130     // Implements system cron entry point.
0131     CTCron *ctCron = mCrontabWidget->currentCron();
0132 
0133     return ctCron->save();
0134 }
0135 
0136 void CTHost::cancel()
0137 {
0138     for (CTCron *ctCron : std::as_const(mCrons)) {
0139         ctCron->cancel();
0140     }
0141 }
0142 
0143 bool CTHost::isDirty()
0144 {
0145     bool isDirty = false;
0146 
0147     for (CTCron *ctCron : std::as_const(mCrons)) {
0148         if (ctCron->isDirty()) {
0149             isDirty = true;
0150         }
0151     }
0152 
0153     return isDirty;
0154 }
0155 
0156 CTCron *CTHost::createSystemCron()
0157 {
0158     CTCron *p = new CTSystemCron(mCrontabBinary);
0159 
0160     mCrons.append(p);
0161 
0162     return p;
0163 }
0164 
0165 QString CTHost::createCTCron(const struct passwd *userInfos)
0166 {
0167     bool currentUserCron = false;
0168     if (userInfos->pw_uid == getuid()) {
0169         currentUserCron = true;
0170     }
0171 
0172     CTInitializationError ctInitializationError;
0173     auto p = new CTCron(mCrontabBinary, userInfos, currentUserCron, ctInitializationError);
0174     if (ctInitializationError.hasErrorMessage()) {
0175         delete p;
0176         return ctInitializationError.errorMessage();
0177     }
0178 
0179     mCrons.append(p);
0180 
0181     return QString();
0182 }
0183 
0184 CTCron *CTHost::findCurrentUserCron() const
0185 {
0186     // Because multiple users may exist, return only the currently logged in user's cron in user cron mode.
0187     for (CTCron *ctCron : std::as_const(mCrons)) {
0188         if (ctCron->isCurrentUserCron()) {
0189             return ctCron;
0190         }
0191     }
0192 
0193     qCDebug(KCM_CRON_LOG) << "Unable to find the current user Cron. Please report this bug and your crontab config to the developers.";
0194     return nullptr;
0195 }
0196 
0197 CTCron *CTHost::findSystemCron() const
0198 {
0199     // Return the cron belonging to root.
0200     for (CTCron *ctCron : std::as_const(mCrons)) {
0201         if (ctCron->isMultiUserCron()) {
0202             return ctCron;
0203         }
0204     }
0205 
0206     qCDebug(KCM_CRON_LOG) << "Unable to find the system Cron. Please report this bug and your crontab config to the developers.";
0207     return nullptr;
0208 }
0209 
0210 CTCron *CTHost::findUserCron(const QString &userLogin) const
0211 {
0212     for (CTCron *ctCron : std::as_const(mCrons)) {
0213         if (ctCron->userLogin() == userLogin) {
0214             return ctCron;
0215         }
0216     }
0217 
0218     qCDebug(KCM_CRON_LOG) << "Unable to find the user Cron " << userLogin << ". Please report this bug and your crontab config to the developers.";
0219     return nullptr;
0220 }
0221 
0222 CTCron *CTHost::findCronContaining(CTTask *ctTask) const
0223 {
0224     for (CTCron *ctCron : std::as_const(mCrons)) {
0225         if (ctCron->tasks().contains(ctTask)) {
0226             return ctCron;
0227         }
0228     }
0229 
0230     qCDebug(KCM_CRON_LOG) << "Unable to find the cron of this task. Please report this bug and your crontab config to the developers.";
0231     return nullptr;
0232 }
0233 
0234 CTCron *CTHost::findCronContaining(CTVariable *ctVariable) const
0235 {
0236     for (CTCron *ctCron : std::as_const(mCrons)) {
0237         if (ctCron->variables().contains(ctVariable)) {
0238             return ctCron;
0239         }
0240     }
0241 
0242     qCDebug(KCM_CRON_LOG) << "Unable to find the cron of this variable. Please report this bug and your crontab config to the developers.";
0243     return nullptr;
0244 }