~ubuntu-branches/ubuntu/raring/cron/raring

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
}