1 /* 2 -------------------------------------------------------------------- 3 CT Host Implementation 4 -------------------------------------------------------------------- 5 SPDX-FileCopyrightText: 1999 Gary Meyer <gary@meyer.net> 6 -------------------------------------------------------------------- 7 SPDX-License-Identifier: GPL-2.0-or-later 8 */ 9 10 #include "cthost.h" 11 12 #include <pwd.h> 13 #include <sys/types.h> 14 #include <unistd.h> // getuid() 15 16 #include <QFile> 17 #include <QTextStream> 18 19 #include <KLocalizedString> 20 21 #include "crontabWidget.h" 22 23 #include "ctInitializationError.h" 24 #include "ctSystemCron.h" 25 #include "ctcron.h" 26 27 #include "kcm_cron_debug.h" 28 CTHost(const QString & cronBinary,CTInitializationError & ctInitializationError)29CTHost::CTHost(const QString &cronBinary, CTInitializationError &ctInitializationError) 30 { 31 struct passwd *userInfos = nullptr; 32 33 mCrontabBinary = cronBinary; 34 35 // If it is the root user 36 if (getuid() == 0) { 37 // Read /etc/passwd 38 setpwent(); // restart 39 while ((userInfos = getpwent())) { 40 if (allowDeny(userInfos->pw_name)) { 41 const QString errorMessage = createCTCron(userInfos); 42 if (!errorMessage.isEmpty()) { 43 ctInitializationError.setErrorMessage(errorMessage); 44 return; 45 } 46 } 47 // delete userInfos; 48 } 49 setpwent(); // restart again for others 50 } 51 // Non-root user, so just create user's cron table. 52 else { 53 // Get name from UID, check it against AllowDeny() 54 unsigned int uid = getuid(); 55 setpwent(); // restart 56 while ((userInfos = getpwent())) { 57 if ((userInfos->pw_uid == uid) && (!allowDeny(userInfos->pw_name))) { 58 ctInitializationError.setErrorMessage( 59 i18n("You have been blocked from using KCron\ 60 by either the /etc/cron.allow file or the /etc/cron.deny file.\ 61 \n\nCheck the crontab man page for further details.")); 62 63 return; 64 } 65 // delete userInfos; 66 } 67 68 setpwent(); // restart again for others 69 70 passwd *currentUserPassword = getpwuid(uid); 71 72 const QString errorMessage = createCTCron(currentUserPassword); 73 if (!errorMessage.isEmpty()) { 74 ctInitializationError.setErrorMessage(errorMessage); 75 return; 76 } 77 78 // delete currentUserPassword; 79 } 80 // Create the system cron table. 81 createSystemCron(); 82 } 83 ~CTHost()84CTHost::~CTHost() 85 { 86 qDeleteAll(mCrons); 87 } 88 allowDeny(char * name)89bool CTHost::allowDeny(char *name) 90 { 91 QFile allow(QStringLiteral("/etc/cron.allow")); 92 93 // if cron.allow exists make sure user is listed 94 if (allow.open(QFile::ReadOnly)) { 95 QTextStream stream(&allow); 96 while (!stream.atEnd()) { 97 if (stream.readLine() == QLatin1String(name)) { 98 allow.close(); 99 return true; 100 } 101 } 102 allow.close(); 103 return false; 104 } else { 105 allow.close(); 106 QFile deny(QStringLiteral("/etc/cron.deny")); 107 108 // else if cron.deny exists make sure user is not listed 109 if (deny.open(QFile::ReadOnly)) { 110 QTextStream stream(&deny); 111 while (!stream.atEnd()) { 112 if (stream.readLine() == QLatin1String(name)) { 113 deny.close(); 114 return false; 115 } 116 } 117 deny.close(); 118 return true; 119 } else { 120 deny.close(); 121 return true; 122 } 123 } 124 } 125 save(CrontabWidget * mCrontabWidget)126CTSaveStatus CTHost::save(CrontabWidget *mCrontabWidget) 127 { 128 qCDebug(KCM_CRON_LOG) << "Save current cron."; 129 // Retrieve the current cron to use. This could either be a user cron or a system cron. 130 // Implements system cron entry point. 131 CTCron *ctCron = mCrontabWidget->currentCron(); 132 133 return ctCron->save(); 134 } 135 cancel()136void CTHost::cancel() 137 { 138 for (CTCron *ctCron : std::as_const(mCrons)) { 139 ctCron->cancel(); 140 } 141 } 142 isDirty()143bool CTHost::isDirty() 144 { 145 bool isDirty = false; 146 147 for (CTCron *ctCron : std::as_const(mCrons)) { 148 if (ctCron->isDirty()) { 149 isDirty = true; 150 } 151 } 152 153 return isDirty; 154 } 155 createSystemCron()156CTCron *CTHost::createSystemCron() 157 { 158 CTCron *p = new CTSystemCron(mCrontabBinary); 159 160 mCrons.append(p); 161 162 return p; 163 } 164 createCTCron(const struct passwd * userInfos)165QString CTHost::createCTCron(const struct passwd *userInfos) 166 { 167 bool currentUserCron = false; 168 if (userInfos->pw_uid == getuid()) { 169 currentUserCron = true; 170 } 171 172 CTInitializationError ctInitializationError; 173 auto p = new CTCron(mCrontabBinary, userInfos, currentUserCron, ctInitializationError); 174 if (ctInitializationError.hasErrorMessage()) { 175 delete p; 176 return ctInitializationError.errorMessage(); 177 } 178 179 mCrons.append(p); 180 181 return QString(); 182 } 183 findCurrentUserCron() const184CTCron *CTHost::findCurrentUserCron() const 185 { 186 // Because multiple users may exist, return only the currently logged in user's cron in user cron mode. 187 for (CTCron *ctCron : std::as_const(mCrons)) { 188 if (ctCron->isCurrentUserCron()) { 189 return ctCron; 190 } 191 } 192 193 qCDebug(KCM_CRON_LOG) << "Unable to find the current user Cron. Please report this bug and your crontab config to the developers."; 194 return nullptr; 195 } 196 findSystemCron() const197CTCron *CTHost::findSystemCron() const 198 { 199 // Return the cron belonging to root. 200 for (CTCron *ctCron : std::as_const(mCrons)) { 201 if (ctCron->isMultiUserCron()) { 202 return ctCron; 203 } 204 } 205 206 qCDebug(KCM_CRON_LOG) << "Unable to find the system Cron. Please report this bug and your crontab config to the developers."; 207 return nullptr; 208 } 209 findUserCron(const QString & userLogin) const210CTCron *CTHost::findUserCron(const QString &userLogin) const 211 { 212 for (CTCron *ctCron : std::as_const(mCrons)) { 213 if (ctCron->userLogin() == userLogin) { 214 return ctCron; 215 } 216 } 217 218 qCDebug(KCM_CRON_LOG) << "Unable to find the user Cron " << userLogin << ". Please report this bug and your crontab config to the developers."; 219 return nullptr; 220 } 221 findCronContaining(CTTask * ctTask) const222CTCron *CTHost::findCronContaining(CTTask *ctTask) const 223 { 224 for (CTCron *ctCron : std::as_const(mCrons)) { 225 if (ctCron->tasks().contains(ctTask)) { 226 return ctCron; 227 } 228 } 229 230 qCDebug(KCM_CRON_LOG) << "Unable to find the cron of this task. Please report this bug and your crontab config to the developers."; 231 return nullptr; 232 } 233 findCronContaining(CTVariable * ctVariable) const234CTCron *CTHost::findCronContaining(CTVariable *ctVariable) const 235 { 236 for (CTCron *ctCron : std::as_const(mCrons)) { 237 if (ctCron->variables().contains(ctVariable)) { 238 return ctCron; 239 } 240 } 241 242 qCDebug(KCM_CRON_LOG) << "Unable to find the cron of this variable. Please report this bug and your crontab config to the developers."; 243 return nullptr; 244 } 245