1
by Steve Greenland
Import upstream version 3.0pl1 |
1 |
/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
2 |
* All rights reserved
|
|
3 |
*
|
|
4 |
* Distribute freely, except: don't remove my name from the source or
|
|
5 |
* documentation (don't take credit for my work), mark your changes (don't
|
|
6 |
* get me blamed for your possible bugs), don't alter or remove this
|
|
7 |
* notice. May be sold if buildable source is provided to buyer. No
|
|
8 |
* warrantee of any kind, express or implied, is included with this
|
|
9 |
* software; use at your own risk, responsibility for damages (if any) to
|
|
10 |
* anyone resulting from the use of this software rests entirely with the
|
|
11 |
* user.
|
|
12 |
*
|
|
13 |
* Send bug reports, bug fixes, enhancements, requests, flames, etc., and
|
|
14 |
* I'll try to keep a version up to date. I can be reached as follows:
|
|
15 |
* Paul Vixie <paul@vix.com> uunet!decwrl!vixie!paul
|
|
16 |
*/
|
|
17 |
||
18 |
#if !defined(lint) && !defined(LINT)
|
|
19 |
static char rcsid[] = "$Id: database.c,v 2.8 1994/01/15 20:43:43 vixie Exp $"; |
|
20 |
#endif
|
|
21 |
||
22 |
/* vix 26jan87 [RCS has the log]
|
|
23 |
*/
|
|
24 |
||
25 |
||
26 |
#include "cron.h" |
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
27 |
#define __USE_GNU /* For O_NOFOLLOW */ |
1
by Steve Greenland
Import upstream version 3.0pl1 |
28 |
#include <fcntl.h> |
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
29 |
#undef __USE_GNU
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
30 |
#include <sys/stat.h> |
31 |
#include <sys/file.h> |
|
2.1.14
by Christian Kastner
* Makefile: |
32 |
#include <time.h> |
1
by Steve Greenland
Import upstream version 3.0pl1 |
33 |
|
34 |
#define TMAX(a,b) ((a)>(b)?(a):(b))
|
|
35 |
||
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
36 |
/* Try to get maximum path name -- this isn't really correct, but we're
|
37 |
going to be lazy */
|
|
38 |
||
39 |
#ifndef PATH_MAX
|
|
40 |
||
41 |
#ifdef MAXPATHLEN
|
|
42 |
#define PATH_MAX MAXPATHLEN
|
|
43 |
#else
|
|
44 |
#define PATH_MAX 2048
|
|
45 |
#endif
|
|
46 |
||
47 |
#endif /* ifndef PATH_MAX */ |
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
48 |
|
49 |
static void process_crontab __P((char *, char *, char *, |
|
50 |
struct stat *, |
|
51 |
cron_db *, cron_db *)); |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
52 |
#ifdef DEBIAN
|
53 |
static int valid_name (char *filename); |
|
54 |
static user *get_next_system_crontab __P((user *)); |
|
55 |
#endif
|
|
2.1.14
by Christian Kastner
* Makefile: |
56 |
|
57 |
void force_rescan_user(cron_db *old_db, cron_db *new_db, const char *fname, time_t old_mtime); |
|
58 |
||
2.1.16
by Javier Fernandez-Sanguino Pen~a, Javier Fernandez-Sanguino, Christian Kastner
* The development team has migrated from Subversion to git, with the latter |
59 |
static void add_orphan(const char *uname, const char *fname, const char *tabname); |
60 |
static void free_orphan(orphan *o); |
|
61 |
||
1
by Steve Greenland
Import upstream version 3.0pl1 |
62 |
void
|
63 |
load_database(old_db) |
|
64 |
cron_db *old_db; |
|
65 |
{
|
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
66 |
DIR *dir; |
1
by Steve Greenland
Import upstream version 3.0pl1 |
67 |
struct stat statbuf; |
68 |
struct stat syscron_stat; |
|
69 |
DIR_T *dp; |
|
70 |
cron_db new_db; |
|
71 |
user *u, *nu; |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
72 |
#ifdef DEBIAN
|
73 |
struct stat syscrond_stat; |
|
74 |
struct stat syscrond_file_stat; |
|
75 |
||
76 |
char syscrond_fname[PATH_MAX+1]; |
|
77 |
int syscrond_change = 0; |
|
78 |
#endif
|
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
79 |
|
80 |
Debug(DLOAD, ("[%d] load_database()\n", getpid())) |
|
81 |
||
82 |
/* before we start loading any data, do a stat on SPOOL_DIR
|
|
83 |
* so that if anything changes as of this moment (i.e., before we've
|
|
84 |
* cached any of the database), we'll see the changes next time.
|
|
85 |
*/
|
|
86 |
if (stat(SPOOL_DIR, &statbuf) < OK) { |
|
87 |
log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR); |
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
88 |
statbuf.st_mtime = 0; |
1
by Steve Greenland
Import upstream version 3.0pl1 |
89 |
}
|
90 |
||
91 |
/* track system crontab file
|
|
92 |
*/
|
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
93 |
if (stat(SYSCRONTAB, &syscron_stat) < OK) { |
94 |
log_it("CRON", getpid(), "STAT FAILED", SYSCRONTAB); |
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
95 |
syscron_stat.st_mtime = 0; |
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
96 |
}
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
97 |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
98 |
#ifdef DEBIAN
|
99 |
/* Check mod time of SYSCRONDIR. This won't tell us if a file
|
|
100 |
* in it changed, but will capture deletions, which the individual
|
|
101 |
* file check won't
|
|
102 |
*/
|
|
103 |
if (stat(SYSCRONDIR, &syscrond_stat) < OK) { |
|
104 |
log_it("CRON", getpid(), "STAT FAILED", SYSCRONDIR); |
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
105 |
syscrond_stat.st_mtime = 0; |
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
106 |
}
|
107 |
||
108 |
/* If SYSCRONDIR was modified, we know that something is changed and
|
|
109 |
* there is no need for any further checks. If it wasn't, we should
|
|
110 |
* pass through the old list of files in SYSCRONDIR and check their
|
|
111 |
* mod time. Therefore a stopped hard drive won't be spun up, since
|
|
112 |
* we avoid reading of SYSCRONDIR and don't change its access time.
|
|
113 |
* This is especially important on laptops with APM.
|
|
114 |
*/
|
|
115 |
if (old_db->sysd_mtime != syscrond_stat.st_mtime) { |
|
116 |
syscrond_change = 1; |
|
117 |
} else { |
|
118 |
/* Look through the individual files */
|
|
119 |
user *systab; |
|
120 |
||
121 |
Debug(DLOAD, ("[%d] system dir mtime unch, check files now.\n", |
|
122 |
getpid())) |
|
123 |
||
124 |
for (systab = old_db->head; |
|
125 |
(systab = get_next_system_crontab (systab)) != NULL; |
|
126 |
systab = systab->next) { |
|
127 |
||
128 |
sprintf(syscrond_fname, "%s/%s", SYSCRONDIR, |
|
129 |
systab->name + 8); |
|
130 |
||
131 |
Debug(DLOAD, ("\t%s:", syscrond_fname)) |
|
132 |
||
133 |
if (stat(syscrond_fname, &syscrond_file_stat) < OK) |
|
134 |
syscrond_file_stat.st_mtime = 0; |
|
135 |
||
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
136 |
if (syscrond_file_stat.st_mtime != systab->mtime || |
137 |
systab->mtime == 0) { |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
138 |
syscrond_change = 1; |
139 |
}
|
|
140 |
||
141 |
Debug(DLOAD, (" [checked]\n")) |
|
142 |
}
|
|
143 |
}
|
|
144 |
#endif /* DEBIAN */ |
|
145 |
||
1
by Steve Greenland
Import upstream version 3.0pl1 |
146 |
/* if spooldir's mtime has not changed, we don't need to fiddle with
|
147 |
* the database.
|
|
148 |
*
|
|
149 |
* Note that old_db->mtime is initialized to 0 in main(), and
|
|
150 |
* so is guaranteed to be different than the stat() mtime the first
|
|
151 |
* time this function is called.
|
|
152 |
*/
|
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
153 |
#ifdef DEBIAN
|
154 |
if ((old_db->user_mtime == statbuf.st_mtime) && |
|
155 |
(old_db->sys_mtime == syscron_stat.st_mtime) && |
|
156 |
(!syscrond_change)) { |
|
157 |
#else
|
|
158 |
if ((old_db->user_mtime == statbuf.st_mtime) && |
|
159 |
(old_db->sys_mtime == syscron_stat.st_mtime)) { |
|
160 |
#endif
|
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
161 |
Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n", |
162 |
getpid())) |
|
163 |
return; |
|
164 |
}
|
|
165 |
||
166 |
/* something's different. make a new database, moving unchanged
|
|
167 |
* elements from the old database, reloading elements that have
|
|
168 |
* actually changed. Whatever is left in the old database when
|
|
169 |
* we're done is chaff -- crontabs that disappeared.
|
|
170 |
*/
|
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
171 |
new_db.user_mtime = statbuf.st_mtime; |
172 |
new_db.sys_mtime = syscron_stat.st_mtime; |
|
173 |
#ifdef DEBIAN
|
|
174 |
new_db.sysd_mtime = syscrond_stat.st_mtime; |
|
175 |
#endif
|
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
176 |
new_db.head = new_db.tail = NULL; |
177 |
||
178 |
if (syscron_stat.st_mtime) { |
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
179 |
process_crontab(SYSUSERNAME, "*system*", |
1
by Steve Greenland
Import upstream version 3.0pl1 |
180 |
SYSCRONTAB, &syscron_stat, |
181 |
&new_db, old_db); |
|
182 |
}
|
|
183 |
||
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
184 |
#ifdef DEBIAN
|
185 |
/* Read all the package crontabs. */
|
|
186 |
if (!(dir = opendir(SYSCRONDIR))) { |
|
187 |
log_it("CRON", getpid(), "OPENDIR FAILED", SYSCRONDIR); |
|
188 |
}
|
|
189 |
||
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
190 |
while (dir != NULL && NULL != (dp = readdir(dir))) { |
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
191 |
char fname[MAXNAMLEN+1], |
192 |
tabname[PATH_MAX+1]; |
|
193 |
||
194 |
||
195 |
/* avoid file names beginning with ".". this is good
|
|
196 |
* because we would otherwise waste two guaranteed calls
|
|
197 |
* to stat() for . and .., and also because package names
|
|
198 |
* starting with a period are just too nasty to consider.
|
|
199 |
*/
|
|
200 |
if (dp->d_name[0] == '.') |
|
201 |
continue; |
|
202 |
||
203 |
/* skipfile names with letters outside the set
|
|
204 |
* [A-Za-z0-9_-], like run-parts.
|
|
205 |
*/
|
|
206 |
if (!valid_name(dp->d_name)) |
|
207 |
continue; |
|
208 |
||
209 |
/* Generate the "fname" */
|
|
210 |
(void) strcpy(fname,"*system*"); |
|
211 |
(void) strcat(fname, dp->d_name); |
|
212 |
sprintf(tabname,"%s/%s", SYSCRONDIR, dp->d_name); |
|
213 |
||
214 |
/* statbuf is used as working storage by process_crontab() --
|
|
215 |
current contents are irrelevant */
|
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
216 |
process_crontab(SYSUSERNAME, fname, tabname, |
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
217 |
&statbuf, &new_db, old_db); |
218 |
||
219 |
}
|
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
220 |
if (dir) |
221 |
closedir(dir); |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
222 |
#endif
|
223 |
||
1
by Steve Greenland
Import upstream version 3.0pl1 |
224 |
/* we used to keep this dir open all the time, for the sake of
|
225 |
* efficiency. however, we need to close it in every fork, and
|
|
226 |
* we fork a lot more often than the mtime of the dir changes.
|
|
227 |
*/
|
|
228 |
if (!(dir = opendir(SPOOL_DIR))) { |
|
229 |
log_it("CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR); |
|
230 |
}
|
|
231 |
||
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
232 |
while (dir != NULL && NULL != (dp = readdir(dir))) { |
1
by Steve Greenland
Import upstream version 3.0pl1 |
233 |
char fname[MAXNAMLEN+1], |
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
234 |
tabname[PATH_MAX+1]; |
1
by Steve Greenland
Import upstream version 3.0pl1 |
235 |
|
236 |
/* avoid file names beginning with ".". this is good
|
|
237 |
* because we would otherwise waste two guaranteed calls
|
|
238 |
* to getpwnam() for . and .., and also because user names
|
|
239 |
* starting with a period are just too nasty to consider.
|
|
240 |
*/
|
|
241 |
if (dp->d_name[0] == '.') |
|
242 |
continue; |
|
243 |
||
244 |
(void) strcpy(fname, dp->d_name); |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
245 |
snprintf(tabname, PATH_MAX+1, CRON_TAB(fname)); |
1
by Steve Greenland
Import upstream version 3.0pl1 |
246 |
|
247 |
process_crontab(fname, fname, tabname, |
|
248 |
&statbuf, &new_db, old_db); |
|
249 |
}
|
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
250 |
if (dir) |
251 |
closedir(dir); |
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
252 |
|
253 |
/* if we don't do this, then when our children eventually call
|
|
254 |
* getpwnam() in do_command.c's child_process to verify MAILTO=,
|
|
255 |
* they will screw us up (and v-v).
|
|
256 |
*/
|
|
257 |
endpwent(); |
|
258 |
||
259 |
/* whatever's left in the old database is now junk.
|
|
260 |
*/
|
|
261 |
Debug(DLOAD, ("unlinking old database:\n")) |
|
262 |
for (u = old_db->head; u != NULL; u = nu) { |
|
263 |
Debug(DLOAD, ("\t%s\n", u->name)) |
|
264 |
nu = u->next; |
|
265 |
unlink_user(old_db, u); |
|
266 |
free_user(u); |
|
267 |
}
|
|
268 |
||
269 |
/* overwrite the database control block with the new one.
|
|
270 |
*/
|
|
271 |
*old_db = new_db; |
|
272 |
Debug(DLOAD, ("load_database is done\n")) |
|
273 |
}
|
|
274 |
||
275 |
||
276 |
void
|
|
277 |
link_user(db, u) |
|
278 |
cron_db *db; |
|
279 |
user *u; |
|
280 |
{
|
|
281 |
if (db->head == NULL) |
|
282 |
db->head = u; |
|
283 |
if (db->tail) |
|
284 |
db->tail->next = u; |
|
285 |
u->prev = db->tail; |
|
286 |
u->next = NULL; |
|
287 |
db->tail = u; |
|
288 |
}
|
|
289 |
||
290 |
||
291 |
void
|
|
292 |
unlink_user(db, u) |
|
293 |
cron_db *db; |
|
294 |
user *u; |
|
295 |
{
|
|
296 |
if (u->prev == NULL) |
|
297 |
db->head = u->next; |
|
298 |
else
|
|
299 |
u->prev->next = u->next; |
|
300 |
||
301 |
if (u->next == NULL) |
|
302 |
db->tail = u->prev; |
|
303 |
else
|
|
304 |
u->next->prev = u->prev; |
|
305 |
}
|
|
306 |
||
307 |
||
308 |
user * |
|
309 |
find_user(db, name) |
|
310 |
cron_db *db; |
|
311 |
char *name; |
|
312 |
{
|
|
313 |
char *env_get(); |
|
314 |
user *u; |
|
315 |
||
316 |
for (u = db->head; u != NULL; u = u->next) |
|
317 |
if (!strcmp(u->name, name)) |
|
318 |
break; |
|
319 |
return u; |
|
320 |
}
|
|
321 |
||
322 |
||
323 |
static void |
|
324 |
process_crontab(uname, fname, tabname, statbuf, new_db, old_db) |
|
325 |
char *uname; |
|
326 |
char *fname; |
|
327 |
char *tabname; |
|
328 |
struct stat *statbuf; |
|
329 |
cron_db *new_db; |
|
330 |
cron_db *old_db; |
|
331 |
{
|
|
332 |
struct passwd *pw = NULL; |
|
333 |
int crontab_fd = OK - 1; |
|
2.1.16
by Javier Fernandez-Sanguino Pen~a, Javier Fernandez-Sanguino, Christian Kastner
* The development team has migrated from Subversion to git, with the latter |
334 |
user *u = NULL; |
1
by Steve Greenland
Import upstream version 3.0pl1 |
335 |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
336 |
#ifdef DEBIAN
|
337 |
/* If the name begins with *system*, don't worry about password -
|
|
338 |
it's part of the system crontab */
|
|
339 |
if (strncmp(fname, "*system*", 8) && !(pw = getpwnam(uname))) { |
|
340 |
#else
|
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
341 |
if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) { |
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
342 |
#endif
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
343 |
/* file doesn't have a user in passwd file.
|
344 |
*/
|
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
345 |
if (strncmp(fname, "tmp.", 4)) { |
346 |
/* don't log these temporary files */
|
|
347 |
log_it(fname, getpid(), "ORPHAN", "no passwd entry"); |
|
2.1.16
by Javier Fernandez-Sanguino Pen~a, Javier Fernandez-Sanguino, Christian Kastner
* The development team has migrated from Subversion to git, with the latter |
348 |
add_orphan(uname, fname, tabname); |
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
349 |
}
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
350 |
goto next_crontab; |
351 |
}
|
|
352 |
||
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
353 |
if (pw) { |
354 |
/* Path for user crontabs (including root's!) */
|
|
355 |
if ((crontab_fd = open(tabname, O_RDONLY|O_NOFOLLOW, 0)) < OK) { |
|
356 |
/* crontab not accessible?
|
|
357 |
*/
|
|
358 |
log_it(fname, getpid(), "CAN'T OPEN", tabname); |
|
359 |
goto next_crontab; |
|
360 |
}
|
|
361 |
||
362 |
if (fstat(crontab_fd, statbuf) < OK) { |
|
363 |
log_it(fname, getpid(), "FSTAT FAILED", tabname); |
|
364 |
goto next_crontab; |
|
365 |
}
|
|
366 |
/* Check to make sure that the crontab is owned by the correct user
|
|
367 |
(or root) */
|
|
2.1.14
by Christian Kastner
* Makefile: |
368 |
if (statbuf->st_uid != pw->pw_uid && statbuf->st_uid != ROOT_UID) { |
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
369 |
log_it(fname, getpid(), "WRONG FILE OWNER", tabname); |
2.1.14
by Christian Kastner
* Makefile: |
370 |
force_rescan_user(old_db, new_db, fname, 0); |
371 |
goto next_crontab; |
|
372 |
}
|
|
373 |
||
374 |
/* Check to make sure that the crontab is a regular file */
|
|
375 |
if (!S_ISREG(statbuf->st_mode)) { |
|
376 |
log_it(fname, getpid(), "NOT A REGULAR FILE", tabname); |
|
377 |
goto next_crontab; |
|
378 |
}
|
|
379 |
||
380 |
/* Check to make sure that the crontab's permissions are secure */
|
|
381 |
if ((statbuf->st_mode & 07777) != 0600) { |
|
382 |
log_it(fname, getpid(), "INSECURE MODE (mode 0600 expected)", tabname); |
|
383 |
force_rescan_user(old_db, new_db, fname, 0); |
|
384 |
goto next_crontab; |
|
385 |
}
|
|
386 |
||
387 |
/* Check to make sure that there are no hardlinks to the crontab */
|
|
388 |
if (statbuf->st_nlink != 1) { |
|
389 |
log_it(fname, getpid(), "NUMBER OF HARD LINKS > 1", tabname); |
|
390 |
force_rescan_user(old_db, new_db, fname, 0); |
|
391 |
goto next_crontab; |
|
392 |
}
|
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
393 |
} else { |
394 |
/* System crontab path. These can be symlinks, but the
|
|
395 |
symlink and the target must be owned by root. */
|
|
396 |
if (lstat(tabname, statbuf) < OK) { |
|
397 |
log_it(fname, getpid(), "LSTAT FAILED", tabname); |
|
398 |
goto next_crontab; |
|
399 |
}
|
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
400 |
if (S_ISLNK(statbuf->st_mode) && statbuf->st_uid != ROOT_UID) { |
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
401 |
log_it(fname, getpid(), "WRONG SYMLINK OWNER", tabname); |
2.1.14
by Christian Kastner
* Makefile: |
402 |
force_rescan_user(old_db, new_db, fname, 0); |
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
403 |
goto next_crontab; |
404 |
}
|
|
405 |
if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) { |
|
406 |
/* crontab not accessible?
|
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
407 |
|
2.1.14
by Christian Kastner
* Makefile: |
408 |
If tabname is a symlink, it's most probably just broken, so
|
409 |
we force a rescan. Once the link is fixed, it will get picked
|
|
410 |
up and processed again. If tabname is a regular file, this
|
|
411 |
error is bad so we skip it instead.
|
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
412 |
*/
|
2.1.14
by Christian Kastner
* Makefile: |
413 |
if (S_ISLNK(statbuf->st_mode)) { |
414 |
log_it(fname, getpid(), "CAN'T OPEN SYMLINK", tabname); |
|
415 |
force_rescan_user(old_db, new_db, fname, 0); |
|
416 |
goto next_crontab; |
|
417 |
} else { |
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
418 |
log_it(fname, getpid(), "CAN'T OPEN", tabname); |
419 |
goto next_crontab; |
|
2.1.14
by Christian Kastner
* Makefile: |
420 |
}
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
421 |
}
|
422 |
||
423 |
if (fstat(crontab_fd, statbuf) < OK) { |
|
424 |
log_it(fname, getpid(), "FSTAT FAILED", tabname); |
|
425 |
goto next_crontab; |
|
426 |
}
|
|
2.1.14
by Christian Kastner
* Makefile: |
427 |
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
428 |
/* Check to make sure that the crontab is owned by root */
|
429 |
if (statbuf->st_uid != ROOT_UID) { |
|
430 |
log_it(fname, getpid(), "WRONG FILE OWNER", tabname); |
|
2.1.14
by Christian Kastner
* Makefile: |
431 |
force_rescan_user(old_db, new_db, fname, 0); |
432 |
goto next_crontab; |
|
433 |
}
|
|
434 |
||
435 |
/* Check to make sure that the crontab is a regular file */
|
|
436 |
if (!S_ISREG(statbuf->st_mode)) { |
|
437 |
log_it(fname, getpid(), "NOT A REGULAR FILE", tabname); |
|
438 |
goto next_crontab; |
|
439 |
}
|
|
440 |
||
441 |
/* Check to make sure that the crontab is writable only by root
|
|
442 |
* This should really be in sync with the check for users above
|
|
443 |
* (mode 0600). An upgrade path could be implemented for 4.1
|
|
444 |
*/
|
|
445 |
if ((statbuf->st_mode & S_IWGRP) || (statbuf->st_mode & S_IWOTH)) { |
|
446 |
log_it(fname, getpid(), "INSECURE MODE (group/other writable)", tabname); |
|
447 |
force_rescan_user(old_db, new_db, fname, 0); |
|
448 |
goto next_crontab; |
|
449 |
}
|
|
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
450 |
/* Technically, we should also check whether the parent dir is
|
451 |
* writable, and so on. This would only make proper sense for
|
|
452 |
* regular files; we can't realistically check all possible
|
|
453 |
* security issues resulting from symlinks. We'll just assume that
|
|
454 |
* root will handle responsible when creating them.
|
|
455 |
*/
|
|
2.1.14
by Christian Kastner
* Makefile: |
456 |
|
457 |
/* Check to make sure that there are no hardlinks to the crontab */
|
|
458 |
if (statbuf->st_nlink != 1) { |
|
459 |
log_it(fname, getpid(), "NUMBER OF HARD LINKS > 1", tabname); |
|
460 |
force_rescan_user(old_db, new_db, fname, 0); |
|
461 |
goto next_crontab; |
|
462 |
}
|
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
463 |
}
|
464 |
/*
|
|
465 |
* The link count check is not sufficient (the owner may
|
|
466 |
* delete their original link, reducing the link count back to
|
|
467 |
* 1), but this is all we've got.
|
|
468 |
*/
|
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
469 |
Debug(DLOAD, ("\t%s:", fname)) |
2.1.16
by Javier Fernandez-Sanguino Pen~a, Javier Fernandez-Sanguino, Christian Kastner
* The development team has migrated from Subversion to git, with the latter |
470 |
|
471 |
if (old_db != NULL) |
|
472 |
u = find_user(old_db, fname); |
|
473 |
||
1
by Steve Greenland
Import upstream version 3.0pl1 |
474 |
if (u != NULL) { |
475 |
/* if crontab has not changed since we last read it
|
|
476 |
* in, then we can just use our existing entry.
|
|
477 |
*/
|
|
478 |
if (u->mtime == statbuf->st_mtime) { |
|
479 |
Debug(DLOAD, (" [no change, using old data]")) |
|
480 |
unlink_user(old_db, u); |
|
481 |
link_user(new_db, u); |
|
482 |
goto next_crontab; |
|
483 |
}
|
|
484 |
||
485 |
/* before we fall through to the code that will reload
|
|
486 |
* the user, let's deallocate and unlink the user in
|
|
487 |
* the old database. This is more a point of memory
|
|
488 |
* efficiency than anything else, since all leftover
|
|
489 |
* users will be deleted from the old database when
|
|
490 |
* we finish with the crontab...
|
|
491 |
*/
|
|
492 |
Debug(DLOAD, (" [delete old data]")) |
|
493 |
unlink_user(old_db, u); |
|
494 |
free_user(u); |
|
495 |
log_it(fname, getpid(), "RELOAD", tabname); |
|
496 |
}
|
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
497 |
|
498 |
u = load_user(crontab_fd, pw, uname, fname, tabname); |
|
1
by Steve Greenland
Import upstream version 3.0pl1 |
499 |
if (u != NULL) { |
500 |
u->mtime = statbuf->st_mtime; |
|
501 |
link_user(new_db, u); |
|
2.1.14
by Christian Kastner
* Makefile: |
502 |
} else { |
503 |
/* The crontab we attempted to load contains a syntax error. A
|
|
504 |
* fix won't get picked up by the regular change detection
|
|
505 |
* code, so we force a rescan. statbuf->st_mtime still contains
|
|
506 |
* the file's mtime, so we use it to rescan only when an update
|
|
507 |
* has actually taken place.
|
|
508 |
*/
|
|
509 |
force_rescan_user(old_db, new_db, fname, statbuf->st_mtime); |
|
510 |
}
|
|
511 |
||
1
by Steve Greenland
Import upstream version 3.0pl1 |
512 |
|
513 |
next_crontab: |
|
514 |
if (crontab_fd >= OK) { |
|
515 |
Debug(DLOAD, (" [done]\n")) |
|
516 |
close(crontab_fd); |
|
517 |
}
|
|
518 |
}
|
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
519 |
|
520 |
#ifdef DEBIAN
|
|
521 |
||
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
522 |
#include <regex.h> |
523 |
||
524 |
/* True or false? Is this a valid filename? */
|
|
525 |
||
526 |
/* Taken from Clint Adams 'run-parts' version to support lsb style
|
|
527 |
names, originally GPL, but relicensed to cron license per e-mail of
|
|
528 |
27 September 2003. I've changed it to do regcomp() only once. */
|
|
529 |
||
2.2.1
by Christian Kastner, Christian Kastner, Javier Fernandez-Sanguino Pen~a
[ Christian Kastner ] |
530 |
static int |
531 |
valid_name(char *filename) |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
532 |
{
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
533 |
static regex_t hierre, tradre, excsre, classicalre; |
534 |
static int donere = 0; |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
535 |
|
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
536 |
if (!donere) { |
537 |
donere = 1; |
|
538 |
if (regcomp(&hierre, "^_?([a-z0-9_.]+-)+[a-z0-9]+$", |
|
539 |
REG_EXTENDED | REG_NOSUB) |
|
540 |
|| regcomp(&excsre, "^[a-z0-9-].*dpkg-(old|dist)$", |
|
541 |
REG_EXTENDED | REG_NOSUB) |
|
542 |
|| regcomp(&tradre, "^[a-z0-9][a-z0-9-]*$", REG_NOSUB) |
|
543 |
|| regcomp(&classicalre, "^[a-zA-Z0-9_-]+$", |
|
544 |
REG_EXTENDED | REG_NOSUB)) { |
|
545 |
log_it("CRON", getpid(), "REGEX FAILED", "valid_name"); |
|
546 |
(void) exit(ERROR_EXIT); |
|
547 |
}
|
|
548 |
}
|
|
549 |
if (lsbsysinit_mode) { |
|
550 |
if (!regexec(&hierre, filename, 0, NULL, 0)) { |
|
551 |
return regexec(&excsre, filename, 0, NULL, 0); |
|
552 |
} else { |
|
553 |
return !regexec(&tradre, filename, 0, NULL, 0); |
|
554 |
}
|
|
555 |
}
|
|
556 |
/* Old standard style */
|
|
557 |
return !regexec(&classicalre, filename, 0, NULL, 0); |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
558 |
}
|
559 |
||
2.1.1
by Steve Greenland
And yes, still needs urgency=high. |
560 |
|
2
by Steve Greenland
* Add type usbdevfs to skipped "file systems" (this is /proc/bus/usb) |
561 |
static user * |
562 |
get_next_system_crontab (curtab) |
|
563 |
user *curtab; |
|
564 |
{
|
|
565 |
for ( ; curtab != NULL; curtab = curtab->next) |
|
566 |
if (!strncmp(curtab->name, "*system*", 8) && curtab->name [8]) |
|
567 |
break; |
|
568 |
return curtab; |
|
569 |
}
|
|
570 |
||
571 |
#endif
|
|
2.1.14
by Christian Kastner
* Makefile: |
572 |
|
573 |
/* Force rescan of a crontab the next time cron wakes up
|
|
574 |
*
|
|
575 |
* cron currently only detects changes caused by an mtime update; it does not
|
|
576 |
* detect other attribute changes such as UID or mode. To allow cron to recover
|
|
577 |
* from errors of that nature as well, this function removes the crontab from
|
|
578 |
* the old DB (if present there) and adds an empty crontab to the new DB with
|
|
579 |
* a given mtime. Specifying mtime as 0 will force a rescan the next time the
|
|
580 |
* daemon wakes up.
|
|
581 |
*/
|
|
582 |
void
|
|
583 |
force_rescan_user(cron_db *old_db, cron_db *new_db, const char *fname, time_t old_mtime) |
|
584 |
{
|
|
585 |
user *u; |
|
586 |
||
587 |
/* Remove from old DB and free resources */
|
|
588 |
u = find_user(old_db, fname); |
|
589 |
if (u != NULL) { |
|
590 |
Debug(DLOAD, (" [delete old data]")) |
|
591 |
unlink_user(old_db, u); |
|
592 |
free_user(u); |
|
593 |
}
|
|
594 |
||
2.1.16
by Javier Fernandez-Sanguino Pen~a, Javier Fernandez-Sanguino, Christian Kastner
* The development team has migrated from Subversion to git, with the latter |
595 |
/* Allocate an empty crontab with the specified mtime, add it to new DB */
|
2.1.14
by Christian Kastner
* Makefile: |
596 |
if ((u = (user *) malloc(sizeof(user))) == NULL) { |
597 |
errno = ENOMEM; |
|
598 |
}
|
|
599 |
if ((u->name = strdup(fname)) == NULL) { |
|
600 |
free(u); |
|
601 |
errno = ENOMEM; |
|
602 |
}
|
|
603 |
u->mtime = old_mtime; |
|
604 |
u->crontab = NULL; |
|
605 |
#ifdef WITH_SELINUX
|
|
606 |
u->scontext = NULL; |
|
607 |
#endif
|
|
608 |
Debug(DLOAD, ("\t%s: [added empty placeholder to force rescan]\n", fname)) |
|
609 |
link_user(new_db, u); |
|
610 |
}
|
|
2.1.16
by Javier Fernandez-Sanguino Pen~a, Javier Fernandez-Sanguino, Christian Kastner
* The development team has migrated from Subversion to git, with the latter |
611 |
|
612 |
/* This fix was taken from Fedora cronie */
|
|
613 |
static orphan *orphans; |
|
614 |
||
615 |
static void |
|
616 |
free_orphan(orphan *o) { |
|
617 |
free(o->tabname); |
|
618 |
free(o->fname); |
|
619 |
free(o->uname); |
|
620 |
free(o); |
|
621 |
}
|
|
622 |
||
623 |
void
|
|
624 |
check_orphans(cron_db *db) { |
|
625 |
orphan *prev_orphan = NULL; |
|
626 |
orphan *o = orphans; |
|
627 |
struct stat statbuf; |
|
628 |
||
629 |
while (o != NULL) { |
|
630 |
if (getpwnam(o->uname) != NULL) { |
|
631 |
orphan *next = o->next; |
|
632 |
||
633 |
if (prev_orphan == NULL) { |
|
634 |
orphans = next; |
|
635 |
} else { |
|
636 |
prev_orphan->next = next; |
|
637 |
}
|
|
638 |
||
639 |
process_crontab(o->uname, o->fname, o->tabname, |
|
640 |
&statbuf, db, NULL); |
|
641 |
||
642 |
/* process_crontab could have added a new orphan */
|
|
643 |
if (prev_orphan == NULL && orphans != next) { |
|
644 |
prev_orphan = orphans; |
|
645 |
}
|
|
646 |
free_orphan(o); |
|
647 |
o = next; |
|
648 |
} else { |
|
649 |
prev_orphan = o; |
|
650 |
o = o->next; |
|
651 |
}
|
|
652 |
}
|
|
653 |
}
|
|
654 |
||
655 |
static void |
|
656 |
add_orphan(const char *uname, const char *fname, const char *tabname) { |
|
657 |
orphan *o; |
|
658 |
||
659 |
o = calloc(1, sizeof(*o)); |
|
660 |
if (o == NULL) |
|
661 |
return; |
|
662 |
||
663 |
if (uname) |
|
664 |
if ((o->uname=strdup(uname)) == NULL) |
|
665 |
goto cleanup; |
|
666 |
||
667 |
if (fname) |
|
668 |
if ((o->fname=strdup(fname)) == NULL) |
|
669 |
goto cleanup; |
|
670 |
||
671 |
if (tabname) |
|
672 |
if ((o->tabname=strdup(tabname)) == NULL) |
|
673 |
goto cleanup; |
|
674 |
||
675 |
o->next = orphans; |
|
676 |
orphans = o; |
|
677 |
return; |
|
678 |
||
679 |
cleanup: |
|
680 |
free_orphan(o); |
|
681 |
}
|