View | Details | Raw Unified | Return to bug 191304
Collapse All | Expand All

(-)cron/Makefile (-1 / +1 lines)
Lines 1-4 Link Here
1
# $FreeBSD: head/usr.sbin/cron/Makefile 80029 2001-07-20 06:20:32Z obrien $
1
# $FreeBSD: releng/10.0/usr.sbin/cron/Makefile 80029 2001-07-20 06:20:32Z obrien $
2
2
3
SUBDIR=	lib cron crontab
3
SUBDIR=	lib cron crontab
4
4
(-)cron/Makefile.inc (-1 / +1 lines)
Lines 1-4 Link Here
1
# $FreeBSD: head/usr.sbin/cron/Makefile.inc 147225 2005-06-10 06:12:53Z des $
1
# $FreeBSD: releng/10.0/usr.sbin/cron/Makefile.inc 147225 2005-06-10 06:12:53Z des $
2
2
3
LIBCRON= ${.OBJDIR}/../lib/libcron.a
3
LIBCRON= ${.OBJDIR}/../lib/libcron.a
4
4
(-)cron/cron/Makefile (-3 / +1 lines)
Lines 1-4 Link Here
1
# $FreeBSD: head/usr.sbin/cron/cron/Makefile 267233 2014-06-08 17:29:31Z bdrewery $
1
# $FreeBSD: releng/10.0/usr.sbin/cron/cron/Makefile 201390 2010-01-02 11:07:44Z ed $
2
2
3
PROG=	cron
3
PROG=	cron
4
MAN=	cron.8
4
MAN=	cron.8
Lines 11-16 Link Here
11
11
12
WARNS?=	2
12
WARNS?=	2
13
13
14
NO_PIE=	yes
15
16
.include <bsd.prog.mk>
14
.include <bsd.prog.mk>
(-)cron/cron/compat.h (-140 lines)
Lines 1-140 Link Here
1
/* Copyright 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
/*
19
 * $FreeBSD: head/usr.sbin/cron/cron/compat.h 50479 1999-08-28 01:35:59Z peter $
20
 */
21
22
#ifndef __P
23
# ifdef __STDC__
24
#  define __P(x) x
25
# else
26
#  define __P(x) ()
27
#  define const
28
# endif
29
#endif
30
31
#if defined(UNIXPC) || defined(unixpc)
32
# define UNIXPC 1
33
# define ATT 1
34
#endif
35
36
#if defined(hpux) || defined(_hpux) || defined(__hpux)
37
# define HPUX 1
38
# define seteuid(e) setresuid(-1,e,-1)
39
# define setreuid(r,e)	setresuid(r,e,-1)
40
#endif
41
42
#if defined(_IBMR2)
43
# define AIX 1
44
#endif
45
46
#if defined(__convex__)
47
# define CONVEX 1
48
#endif
49
50
#if defined(sgi) || defined(_sgi) || defined(__sgi)
51
# define IRIX 1
52
/* IRIX 4 hdrs are broken: one cannot #include both <stdio.h>
53
 * and <stdlib.h> because they disagree on system(), perror().
54
 * Therefore we must zap the "const" keyword BEFORE including
55
 * either of them.
56
 */
57
# define const
58
#endif
59
60
#if defined(_UNICOS)
61
# define UNICOS 1
62
#endif
63
64
#ifndef POSIX
65
# if (BSD >= 199103) || defined(__linux) || defined(ultrix) || defined(AIX) ||\
66
	defined(HPUX) || defined(CONVEX) || defined(IRIX)
67
#  define POSIX
68
# endif
69
#endif
70
71
#ifndef BSD
72
# if defined(ultrix)
73
#  define BSD 198902
74
# endif
75
#endif
76
77
/*****************************************************************/
78
79
#if !defined(BSD) && !defined(HPUX) && !defined(CONVEX) && !defined(__linux)
80
# define NEED_VFORK
81
#endif
82
83
#if (!defined(BSD) || (BSD < 198902)) && !defined(__linux) && \
84
	!defined(IRIX) && !defined(NeXT) && !defined(HPUX)
85
# define NEED_STRCASECMP
86
#endif
87
88
#if (!defined(BSD) || (BSD < 198911)) && !defined(__linux) &&\
89
	!defined(IRIX) && !defined(UNICOS) && !defined(HPUX)
90
# define NEED_STRDUP
91
#endif
92
93
#if (!defined(BSD) || (BSD < 198911)) && !defined(POSIX) && !defined(NeXT)
94
# define NEED_STRERROR
95
#endif
96
97
#if defined(HPUX) || defined(AIX) || defined(UNIXPC)
98
# define NEED_FLOCK
99
#endif
100
101
#ifndef POSIX
102
# define NEED_SETSID
103
#endif
104
105
#if (defined(POSIX) && !defined(BSD)) && !defined(__linux)
106
# define NEED_GETDTABLESIZE
107
#endif
108
109
#ifdef POSIX
110
#include <unistd.h>
111
#ifdef _POSIX_SAVED_IDS
112
# define HAVE_SAVED_UIDS
113
#endif
114
#endif
115
116
#if !defined(ATT) && !defined(__linux) && !defined(IRIX) && !defined(UNICOS)
117
# define USE_SIGCHLD
118
#endif
119
120
#if !defined(AIX) && !defined(UNICOS)
121
# define SYS_TIME_H 1
122
#else
123
# define SYS_TIME_H 0
124
#endif
125
126
#if defined(BSD) && !defined(POSIX)
127
# define USE_UTIMES
128
#endif
129
130
#if defined(AIX) || defined(HPUX) || defined(IRIX)
131
# define NEED_SETENV
132
#endif
133
134
#if !defined(UNICOS) && !defined(UNIXPC)
135
# define HAS_FCHOWN
136
#endif
137
138
#if !defined(UNICOS) && !defined(UNIXPC)
139
# define HAS_FCHMOD
140
#endif
(-)cron/cron/config.h (-37 / +55 lines)
Lines 1-29 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
/* config.h - configurables for Vixie Cron
22
/* config.h - configurables for ISC Cron
19
 *
23
 *
20
 * $FreeBSD: head/usr.sbin/cron/cron/config.h 50479 1999-08-28 01:35:59Z peter $
24
 * $Id: config.h,v 1.10 2004/01/23 18:56:42 vixie Exp $
21
 */
25
 */
22
26
23
#if !defined(_PATH_SENDMAIL)
24
# define _PATH_SENDMAIL "/usr/lib/sendmail"
25
#endif /*SENDMAIL*/
26
27
/*
27
/*
28
 * these are site-dependent
28
 * these are site-dependent
29
 */
29
 */
Lines 33-76 Link Here
33
#endif
33
#endif
34
34
35
			/*
35
			/*
36
			 * choose one of these MAILCMD commands.  I use
36
			 * choose one of these mailer commands.  some use
37
			 * /bin/mail for speed; it makes biff bark but doesn't
37
			 * /bin/mail for speed; it makes biff bark but doesn't
38
			 * do aliasing.  /usr/lib/sendmail does aliasing but is
38
			 * do aliasing.  sendmail does do aliasing but is
39
			 * a hog for short messages.  aliasing is not needed
39
			 * a hog for short messages.  aliasing is not needed
40
			 * if you make use of the MAILTO= feature in crontabs.
40
			 * if you make use of the MAILTO= feature in crontabs.
41
			 * (hint: MAILTO= was added for this reason).
41
			 * (hint: MAILTO= was added for this reason).
42
			 */
42
			 */
43
43
44
#define MAILCMD _PATH_SENDMAIL					/*-*/
44
#define MAILFMT "%s -FCronDaemon -odi -oem -oi -t" /*-*/
45
#define MAILARGS "%s -FCronDaemon -odi -oem -oi -t"             /*-*/
45
			/* -Fx	 = Set full-name of sender
46
			/* -Fx	 = set full-name of sender
47
			 * -odi	 = Option Deliverymode Interactive
46
			 * -odi	 = Option Deliverymode Interactive
48
			 * -oem	 = Option Errors Mailedtosender
47
			 * -oem	 = Option Errors Mailedtosender
49
			 * -oi   = Option dot message terminator
48
			 * -oi   = Ignore "." alone on a line
50
			 * -t    = read recipients from header of message
49
			 * -t    = Get recipient from headers
51
			 */
50
			 */
51
#define MAILARG _PATH_SENDMAIL				/*-*/
52
52
53
/* #define MAILCMD "/bin/mail" */		/*-*/
53
/* #define MAILFMT "%s -d %s"				
54
/* #define MAILARGS "%s -d  %s" */		/*-*/
54
			 -d = undocumented but common flag: deliver locally?
55
			/* -d = undocumented but common flag: deliver locally?
56
			 */
55
			 */
56
/* #define MAILARG "/bin/mail",mailto */
57
57
58
/* #define MAILCMD "/usr/mmdf/bin/submit" */	/*-*/
58
/* #define MAILFMT "%s -mlrxto %s"			*/
59
/* #define MAILARGS "%s -mlrxto %s" */		/*-*/
59
/* #define MAILARG "/usr/mmdf/bin/submit",mailto	*/
60
60
61
/* #define MAIL_DATE */				/*-*/
61
/* #define MAIL_DATE				*/
62
			/* should we include an ersatz Date: header in
62
			/* should we include an ersatz Date: header in
63
			 * generated mail?  if you are using sendmail
63
			 * generated mail?  if you are using sendmail
64
			 * for MAILCMD, it is better to let sendmail
64
			 * as the mailer, it is better to let sendmail
65
			 * generate the Date: header.
65
			 * generate the Date: header.
66
			 */
66
			 */
67
67
68
			/* if ALLOW_FILE and DENY_FILE are not defined or are
69
			 * defined but neither exists, should crontab(1) be
70
			 * usable only by root?
71
			 */
72
/* #define ALLOW_ONLY_ROOT */			/*-*/
73
74
			/* if you want to use syslog(3) instead of appending
68
			/* if you want to use syslog(3) instead of appending
75
			 * to CRONDIR/LOG_FILE (/var/cron/log, e.g.), define
69
			 * to CRONDIR/LOG_FILE (/var/cron/log, e.g.), define
76
			 * SYSLOG here.  Note that quite a bit of logging
70
			 * SYSLOG here.  Note that quite a bit of logging
Lines 85-87 Link Here
85
			 * places.
79
			 * places.
86
			 */
80
			 */
87
#define SYSLOG	 			/*-*/
81
#define SYSLOG	 			/*-*/
82
83
			/* if you want cron to capitalize its name in ps
84
			 * when running a job.  Does not work on SYSV.
85
			 */
86
/*#define CAPITALIZE_FOR_PS		*/
87
88
			/* if you have a tm_gmtoff member in struct tm.
89
			 * If not, we will have to compute the value ourselves.
90
			 */
91
/*#define HAVE_TM_GMTOFF		*/
92
93
			/* if your OS supports a BSD-style login.conf file */
94
/*#define LOGIN_CAP			*/
95
96
			/* if your OS supports BSD authentication */
97
/*#define BSD_AUTH			*/
98
99
			/* Define this to run crontab setgid instead of   
100
			 * setuid root.  Group access will be used to read
101
			 * the tabs/atjobs dirs and the allow/deny files.
102
			 * If this is not defined then crontab and at
103
			 * must be setuid root.
104
			 */
105
/*#define CRON_GROUP	"crontab"	*/
(-)cron/cron/cron.8 (-2 / +2 lines)
Lines 15-21 Link Here
15
.\" * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
.\" * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
16
.\" */
16
.\" */
17
.\"
17
.\"
18
.\" $FreeBSD: head/usr.sbin/cron/cron/cron.8 267668 2014-06-20 09:57:27Z bapt $
18
.\" $FreeBSD: releng/10.0/usr.sbin/cron/cron/cron.8 180096 2008-06-29 16:56:18Z marck $
19
.\"
19
.\"
20
.Dd June 29, 2008
20
.Dd June 29, 2008
21
.Dt CRON 8
21
.Dt CRON 8
Lines 218-221 Link Here
218
.Xr crontab 5 ,
218
.Xr crontab 5 ,
219
.Xr pam.conf 5
219
.Xr pam.conf 5
220
.Sh AUTHORS
220
.Sh AUTHORS
221
.An Paul Vixie Aq Mt paul@vix.com
221
.An Paul Vixie Aq paul@vix.com
(-)cron/cron/cron.c (-398 / +352 lines)
Lines 1-142 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
#if !defined(lint) && !defined(LINT)
22
//#if !defined(lint) && !defined(LINT)
19
static const char rcsid[] =
23
//static char rcsid[] = "$Id: cron.c,v 1.12 2004/01/23 18:56:42 vixie Exp $";
20
  "$FreeBSD: head/usr.sbin/cron/cron/cron.c 261146 2014-01-25 02:16:09Z ache $";
24
//#endif
21
#endif
22
25
23
#define	MAIN_PROGRAM
26
#define	MAIN_PROGRAM
24
27
#include <libutil.h>
28
#include <sys/mman.h>
25
29
26
#include "cron.h"
30
#include "cron.h"
27
#include <sys/mman.h>
28
#include <sys/signal.h>
29
#if SYS_TIME_H
30
# include <sys/time.h>
31
#else
32
# include <time.h>
33
#endif
34
31
32
enum timejump { negative, small, medium, large };
35
33
36
static	void	usage(void),
34
static	void	usage(void),
37
		run_reboot_jobs(cron_db *),
35
		run_reboot_jobs(cron_db *),
38
		cron_tick(cron_db *, int),
36
		find_jobs(int, cron_db *, int, int),
39
		cron_sync(int),
37
		set_time(int),
40
		cron_sleep(cron_db *, int),
38
		cron_sleep(int),
41
		cron_clean(cron_db *),
42
#ifdef USE_SIGCHLD
43
		sigchld_handler(int),
39
		sigchld_handler(int),
44
#endif
45
		sighup_handler(int),
40
		sighup_handler(int),
41
		sigchld_reaper(void),
42
		quit(int),
46
		parse_args(int c, char *v[]);
43
		parse_args(int c, char *v[]);
47
44
48
static int	run_at_secres(cron_db *);
45
static	volatile sig_atomic_t	got_sighup, got_sigchld;
49
46
static	int			timeRunning, virtualTime, clockTime;
50
static time_t	last_time = 0;
47
static  int			cronSock;
51
static int	dst_enabled = 0;
48
static	long			GMToff;
52
struct pidfh *pfh;
49
static  cron_db 		database;
53
50
54
static void
51
struct pidfh			*pfh;
55
usage() {
52
static void
56
#if DEBUGGING
53
usage(void) {
57
    char **dflags;
54
	const char **dflags;
58
#endif
55
59
56
	fprintf(stderr, "usage: cron [-j jitter] [-J rootjitter] ");
60
	fprintf(stderr, "usage: cron [-j jitter] [-J rootjitter] "
57
	fprintf(stderr, "%s [-n] [-x [", ProgramName);
61
			"[-m mailto] [-s] [-o] [-x debugflag[,...]]\n");
58
	for (dflags = DebugFlagNames; *dflags; dflags++)
62
#if DEBUGGING
59
		fprintf(stderr, "%s%s", *dflags, dflags[1] ? "," : "]");
63
	fprintf(stderr, "\ndebugflags: ");
64
65
        for(dflags = DebugFlagNames; *dflags; dflags++) {
66
		fprintf(stderr, "%s ", *dflags);
67
	}
68
        fprintf(stderr, "\n");
69
#endif
70
60
61
	fprintf(stderr, "]\n");
71
	exit(ERROR_EXIT);
62
	exit(ERROR_EXIT);
72
}
63
}
73
64
74
static void
65
static void
75
open_pidfile(void)
66
open_pidfile(void)
76
{
67
{
77
	char	pidfile[MAX_FNAME];
68
        char    pidfile[MAX_FNAME];
78
	char	buf[MAX_TEMPSTR];
69
        char    buf[MAX_TEMPSTR];
79
	int	otherpid;
70
        int     otherpid;
80
71
81
	(void) snprintf(pidfile, sizeof(pidfile), PIDFILE, PIDDIR);
72
        (void) snprintf(pidfile, sizeof(pidfile), PIDFILE, PIDDIR);
82
	pfh = pidfile_open(pidfile, 0600, &otherpid);
73
        pfh = pidfile_open(pidfile, 0600, &otherpid);
83
	if (pfh == NULL) {
74
        if (pfh == NULL) {
84
		if (errno == EEXIST) {
75
                if (errno == EEXIST) {
85
			snprintf(buf, sizeof(buf),
76
                        snprintf(buf, sizeof(buf),
86
			    "cron already running, pid: %d", otherpid);
77
                            "cron already running, pid: %d", otherpid);
87
		} else {
78
                } else {
88
			snprintf(buf, sizeof(buf),
79
                        snprintf(buf, sizeof(buf),
89
			    "can't open or create %s: %s", pidfile,
80
                            "can't open or create %s: %s", pidfile,
90
			    strerror(errno));
81
                            strerror(errno));
91
		}
82
                }
92
		log_it("CRON", getpid(), "DEATH", buf);
83
                log_it("CRON", getpid(), "DEATH", buf);
93
		errx(ERROR_EXIT, "%s", buf);
84
                errx(ERROR_EXIT, "%s", buf);
94
	}
85
        }
95
}
86
}
96
87
97
int
88
int
98
main(argc, argv)
89
main(int argc, char *argv[]) {
99
	int	argc;
90
	struct sigaction sact;
100
	char	*argv[];
101
{
102
	cron_db	database;
103
	int runnum;
104
	int secres1, secres2;
105
	struct tm *tm;
106
91
107
	ProgramName = argv[0];
92
	ProgramName = argv[0];
108
93
94
	setlocale(LC_ALL, "");
95
109
#if defined(BSD)
96
#if defined(BSD)
110
	setlinebuf(stdout);
97
	setlinebuf(stdout);
111
	setlinebuf(stderr);
98
	setlinebuf(stderr);
112
#endif
99
#endif
113
100
101
	NoFork = 0;
114
	parse_args(argc, argv);
102
	parse_args(argc, argv);
115
103
116
#ifdef USE_SIGCHLD
104
	bzero((char *)&sact, sizeof sact);
117
	(void) signal(SIGCHLD, sigchld_handler);
105
	sigemptyset(&sact.sa_mask);
118
#else
106
	sact.sa_flags = 0;
119
	(void) signal(SIGCLD, SIG_IGN);
107
#ifdef SA_RESTART
108
	sact.sa_flags |= SA_RESTART;
120
#endif
109
#endif
121
	(void) signal(SIGHUP, sighup_handler);
110
	sact.sa_handler = sigchld_handler;
111
	(void) sigaction(SIGCHLD, &sact, NULL);
112
	sact.sa_handler = sighup_handler;
113
	(void) sigaction(SIGHUP, &sact, NULL);
114
	sact.sa_handler = quit;
115
	(void) sigaction(SIGINT, &sact, NULL);
116
	(void) sigaction(SIGTERM, &sact, NULL);
122
117
123
	open_pidfile();
118
	open_pidfile();
119
	cronSock = open_socket();
124
	set_cron_uid();
120
	set_cron_uid();
125
	set_cron_cwd();
121
	set_cron_cwd();
126
122
127
#if defined(POSIX)
123
	if (putenv("PATH="_PATH_DEFPATH) < 0) {
128
	setenv("PATH", _PATH_DEFPATH, 1);
124
		log_it("CRON", getpid(), "DEATH", "can't malloc");
129
#endif
125
		exit(1);
126
	}
130
127
131
	/* if there are no debug flags turned on, fork as a daemon should.
128
	/* if there are no debug flags turned on, fork as a daemon should.
132
	 */
129
	 */
133
# if DEBUGGING
134
	if (DebugFlags) {
130
	if (DebugFlags) {
135
# else
131
#if DEBUGGING
136
	if (0) {
132
		(void) fprintf(stderr, "[%ld] cron started\n", (long)getpid());
137
# endif
133
#endif
138
		(void) fprintf(stderr, "[%d] cron started\n", getpid());
134
	} else if (NoFork == 0) {
139
	} else {
140
		if (daemon(1, 0) == -1) {
135
		if (daemon(1, 0) == -1) {
141
			pidfile_remove(pfh);
136
			pidfile_remove(pfh);
142
			log_it("CRON",getpid(),"DEATH","can't become daemon");
137
			log_it("CRON",getpid(),"DEATH","can't become daemon");
Lines 145-304 Link Here
145
	}
140
	}
146
141
147
	if (madvise(NULL, 0, MADV_PROTECT) != 0)
142
	if (madvise(NULL, 0, MADV_PROTECT) != 0)
148
		log_it("CRON", getpid(), "WARNING", "madvise() failed");
143
		log_it("CRON", getpid(), "WARNING", "madvise() filed");
149
144
150
	pidfile_write(pfh);
145
	pidfile_write(pfh);
151
	database.head = NULL;
146
	database.head = NULL;
152
	database.tail = NULL;
147
	database.tail = NULL;
153
	database.mtime = (time_t) 0;
148
	database.mtime = (time_t) 0;
154
	load_database(&database);
149
	load_database(&database);
155
	secres1 = secres2 = run_at_secres(&database);
150
	set_time(TRUE);
156
	run_reboot_jobs(&database);
151
	run_reboot_jobs(&database);
157
	cron_sync(secres1);
152
	timeRunning = virtualTime = clockTime;
158
	runnum = 0;
153
154
	/*
155
	 * Too many clocks, not enough time (Al. Einstein)
156
	 * These clocks are in minutes since the epoch, adjusted for timezone.
157
	 * virtualTime: is the time it *would* be if we woke up
158
	 * promptly and nobody ever changed the clock. It is
159
	 * monotonically increasing... unless a timejump happens.
160
	 * At the top of the loop, all jobs for 'virtualTime' have run.
161
	 * timeRunning: is the time we last awakened.
162
	 * clockTime: is the time when set_time was last called.
163
	 */
159
	while (TRUE) {
164
	while (TRUE) {
160
# if DEBUGGING
165
		int timeDiff;
161
	    /* if (!(DebugFlags & DTEST)) */
166
		enum timejump wakeupKind;
162
# endif /*DEBUGGING*/
167
163
			cron_sleep(&database, secres1);
168
		/* ... wait for the time (in minutes) to change ... */
164
169
		do {
165
		if (secres1 == 0 || runnum % 60 == 0) {
170
			cron_sleep(timeRunning + 1);
166
			load_database(&database);
171
			set_time(FALSE);
167
			secres2 = run_at_secres(&database);
172
		} while (clockTime == timeRunning);
168
			if (secres2 != secres1) {
173
		timeRunning = clockTime;
169
				secres1 = secres2;
174
170
				if (secres1 != 0) {
175
		/*
171
					runnum = 0;
176
		 * Calculate how the current time differs from our virtual
172
				} else {
177
		 * clock.  Classify the change into one of 4 cases.
173
					/*
178
		 */
174
					 * Going from 1 sec to 60 sec res. If we
179
		timeDiff = timeRunning - virtualTime;
175
					 * are already at minute's boundary, so
180
176
					 * let it run, otherwise schedule for the
181
		/* shortcut for the most common case */
177
					 * next minute.
182
		if (timeDiff == 1) {
178
					 */
183
			virtualTime = timeRunning;
179
					tm = localtime(&TargetTime);
184
			find_jobs(virtualTime, &database, TRUE, TRUE);
180
					if (tm->tm_sec > 0)  {
185
		} else {
181
						cron_sync(secres2);
186
			if (timeDiff > (3*MINUTE_COUNT) ||
182
						continue;
187
			    timeDiff < -(3*MINUTE_COUNT))
183
					}
188
				wakeupKind = large;
184
				}
189
			else if (timeDiff > 5)
190
				wakeupKind = medium;
191
			else if (timeDiff > 0)
192
				wakeupKind = small;
193
			else
194
				wakeupKind = negative;
195
196
			switch (wakeupKind) {
197
			case small:
198
				/*
199
				 * case 1: timeDiff is a small positive number
200
				 * (wokeup late) run jobs for each virtual
201
				 * minute until caught up.
202
				 */
203
				Debug(DSCH, ("[%ld], normal case %d minutes to go\n",
204
				    (long)getpid(), timeDiff))
205
				do {
206
					if (job_runqueue())
207
						sleep(10);
208
					virtualTime++;
209
					find_jobs(virtualTime, &database,
210
					    TRUE, TRUE);
211
				} while (virtualTime < timeRunning);
212
				break;
213
214
			case medium:
215
				/*
216
				 * case 2: timeDiff is a medium-sized positive
217
				 * number, for example because we went to DST
218
				 * run wildcard jobs once, then run any
219
				 * fixed-time jobs that would otherwise be
220
				 * skipped if we use up our minute (possible,
221
				 * if there are a lot of jobs to run) go
222
				 * around the loop again so that wildcard jobs
223
				 * have a chance to run, and we do our
224
				 * housekeeping.
225
				 */
226
				Debug(DSCH, ("[%ld], DST begins %d minutes to go\n",
227
				    (long)getpid(), timeDiff))
228
				/* run wildcard jobs for current minute */
229
				find_jobs(timeRunning, &database, TRUE, FALSE);
230
	
231
				/* run fixed-time jobs for each minute missed */
232
				do {
233
					if (job_runqueue())
234
						sleep(10);
235
					virtualTime++;
236
					find_jobs(virtualTime, &database,
237
					    FALSE, TRUE);
238
					set_time(FALSE);
239
				} while (virtualTime< timeRunning &&
240
				    clockTime == timeRunning);
241
				break;
242
	
243
			case negative:
244
				/*
245
				 * case 3: timeDiff is a small or medium-sized
246
				 * negative num, eg. because of DST ending.
247
				 * Just run the wildcard jobs. The fixed-time
248
				 * jobs probably have already run, and should
249
				 * not be repeated.  Virtual time does not
250
				 * change until we are caught up.
251
				 */
252
				Debug(DSCH, ("[%ld], DST ends %d minutes to go\n",
253
				    (long)getpid(), timeDiff))
254
				find_jobs(timeRunning, &database, TRUE, FALSE);
255
				break;
256
			default:
257
				/*
258
				 * other: time has changed a *lot*,
259
				 * jump virtual time, and run everything
260
				 */
261
				Debug(DSCH, ("[%ld], clock jumped\n",
262
				    (long)getpid()))
263
				virtualTime = timeRunning;
264
				find_jobs(timeRunning, &database, TRUE, TRUE);
185
			}
265
			}
186
		}
266
		}
187
267
188
		/* do this iteration
268
		/* Jobs to be run (if any) are loaded; clear the queue. */
189
		 */
269
		job_runqueue();
190
		cron_tick(&database, secres1);
191
270
192
		/* sleep 1 or 60 seconds
271
		/* Check to see if we received a signal while running jobs. */
193
		 */
272
		if (got_sighup) {
194
		TargetTime += (secres1 != 0) ? 1 : 60;
273
			got_sighup = 0;
195
		runnum += 1;
274
			log_close();
275
		}
276
		if (got_sigchld) {
277
			got_sigchld = 0;
278
			sigchld_reaper();
279
		}
280
		load_database(&database);
196
	}
281
	}
197
}
282
}
198
283
199
200
static void
284
static void
201
run_reboot_jobs(db)
285
run_reboot_jobs(cron_db *db) {
202
	cron_db *db;
286
	user *u;
203
{
287
	entry *e;
204
	register user		*u;
205
	register entry		*e;
206
288
207
	for (u = db->head;  u != NULL;  u = u->next) {
289
	for (u = db->head; u != NULL; u = u->next) {
208
		for (e = u->crontab;  e != NULL;  e = e->next) {
290
		for (e = u->crontab; e != NULL; e = e->next) {
209
			if (e->flags & WHEN_REBOOT) {
291
			if (e->flags & WHEN_REBOOT)
210
				job_add(e, u);
292
				job_add(e, u);
211
			}
212
		}
293
		}
213
	}
294
	}
214
	(void) job_runqueue();
295
	(void) job_runqueue();
215
}
296
}
216
297
217
218
static void
298
static void
219
cron_tick(cron_db *db, int secres)
299
find_jobs(int vtime, cron_db *db, int doWild, int doNonWild) {
220
{
300
	time_t virtualSecond  = vtime * SECONDS_PER_MINUTE;
221
	static struct tm	lasttm;
301
	struct tm *tm = gmtime(&virtualSecond);
222
	static time_t	diff = 0, /* time difference in seconds from the last offset change */
302
	int minute, hour, dom, month, dow;
223
		difflimit = 0; /* end point for the time zone correction */
303
	user *u;
224
	struct tm	otztm; /* time in the old time zone */
304
	entry *e;
225
	int		otzsecond, otzminute, otzhour, otzdom, otzmonth, otzdow;
226
 	register struct tm	*tm = localtime(&TargetTime);
227
	register int		second, minute, hour, dom, month, dow;
228
	register user		*u;
229
	register entry		*e;
230
305
231
	/* make 0-based values out of these so we can use them as indicies
306
	/* make 0-based values out of these so we can use them as indicies
232
	 */
307
	 */
233
	second = (secres == 0) ? 0 : tm->tm_sec -FIRST_SECOND;
234
	minute = tm->tm_min -FIRST_MINUTE;
308
	minute = tm->tm_min -FIRST_MINUTE;
235
	hour = tm->tm_hour -FIRST_HOUR;
309
	hour = tm->tm_hour -FIRST_HOUR;
236
	dom = tm->tm_mday -FIRST_DOM;
310
	dom = tm->tm_mday -FIRST_DOM;
237
	month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
311
	month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
238
	dow = tm->tm_wday -FIRST_DOW;
312
	dow = tm->tm_wday -FIRST_DOW;
239
313
240
	Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d,%d)\n",
314
	Debug(DSCH, ("[%ld] tick(%d,%d,%d,%d,%d) %s %s\n",
241
		getpid(), second, minute, hour, dom, month, dow))
315
		     (long)getpid(), minute, hour, dom, month, dow,
242
316
		     doWild?" ":"No wildcard",doNonWild?" ":"Wildcard only"))
243
	if (dst_enabled && last_time != 0 
244
	&& TargetTime > last_time /* exclude stepping back */
245
	&& tm->tm_gmtoff != lasttm.tm_gmtoff ) {
246
247
		diff = tm->tm_gmtoff - lasttm.tm_gmtoff;
248
249
		if ( diff > 0 ) { /* ST->DST */
250
			/* mark jobs for an earlier run */
251
			difflimit = TargetTime + diff;
252
			for (u = db->head;  u != NULL;  u = u->next) {
253
				for (e = u->crontab;  e != NULL;  e = e->next) {
254
					e->flags &= ~NOT_UNTIL;
255
					if ( e->lastrun >= TargetTime )
256
						e->lastrun = 0;
257
					/* not include the ends of hourly ranges */
258
					if ( e->lastrun < TargetTime - 3600 )
259
						e->flags |= RUN_AT;
260
					else
261
						e->flags &= ~RUN_AT;
262
				}
263
			}
264
		} else { /* diff < 0 : DST->ST */
265
			/* mark jobs for skipping */
266
			difflimit = TargetTime - diff;
267
			for (u = db->head;  u != NULL;  u = u->next) {
268
				for (e = u->crontab;  e != NULL;  e = e->next) {
269
					e->flags |= NOT_UNTIL;
270
					e->flags &= ~RUN_AT;
271
				}
272
			}
273
		}
274
	}
275
276
	if (diff != 0) {
277
		/* if the time was reset of the end of special zone is reached */
278
		if (last_time == 0 || TargetTime >= difflimit) {
279
			/* disable the TZ switch checks */
280
			diff = 0;
281
			difflimit = 0;
282
			for (u = db->head;  u != NULL;  u = u->next) {
283
				for (e = u->crontab;  e != NULL;  e = e->next) {
284
					e->flags &= ~(RUN_AT|NOT_UNTIL);
285
				}
286
			}
287
		} else {
288
			/* get the time in the old time zone */
289
			time_t difftime = TargetTime + tm->tm_gmtoff - diff;
290
			gmtime_r(&difftime, &otztm);
291
292
			/* make 0-based values out of these so we can use them as indicies
293
			 */
294
			otzsecond = (secres == 0) ? 0 : otztm.tm_sec -FIRST_SECOND;
295
			otzminute = otztm.tm_min -FIRST_MINUTE;
296
			otzhour = otztm.tm_hour -FIRST_HOUR;
297
			otzdom = otztm.tm_mday -FIRST_DOM;
298
			otzmonth = otztm.tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
299
			otzdow = otztm.tm_wday -FIRST_DOW;
300
		}
301
	}
302
317
303
	/* the dom/dow situation is odd.  '* * 1,15 * Sun' will run on the
318
	/* the dom/dow situation is odd.  '* * 1,15 * Sun' will run on the
304
	 * first and fifteenth AND every Sunday;  '* * * * Sun' will run *only*
319
	 * first and fifteenth AND every Sunday;  '* * * * Sun' will run *only*
Lines 306-561 Link Here
306
	 * is why we keep 'e->dow_star' and 'e->dom_star'.  yes, it's bizarre.
321
	 * is why we keep 'e->dow_star' and 'e->dom_star'.  yes, it's bizarre.
307
	 * like many bizarre things, it's the standard.
322
	 * like many bizarre things, it's the standard.
308
	 */
323
	 */
309
	for (u = db->head;  u != NULL;  u = u->next) {
324
	for (u = db->head; u != NULL; u = u->next) {
310
		for (e = u->crontab;  e != NULL;  e = e->next) {
325
		for (e = u->crontab; e != NULL; e = e->next) {
311
			Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
326
			Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
312
					  env_get("LOGNAME", e->envp),
327
			    env_get("LOGNAME", e->envp), 
313
					  e->uid, e->gid, e->cmd))
328
			    e->uid, e->gid, e->cmd))
314
329
			if (bit_test(e->minute, minute) &&
315
			if ( diff != 0 && (e->flags & (RUN_AT|NOT_UNTIL)) ) {
330
			    bit_test(e->hour, hour) &&
316
				if (bit_test(e->second, otzsecond)
331
			    bit_test(e->month, month) &&
317
				 && bit_test(e->minute, otzminute)
332
			    ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
318
				 && bit_test(e->hour, otzhour)
319
				 && bit_test(e->month, otzmonth)
320
				 && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
321
					  ? (bit_test(e->dow,otzdow) && bit_test(e->dom,otzdom))
322
					  : (bit_test(e->dow,otzdow) || bit_test(e->dom,otzdom))
323
					)
324
				   ) {
325
					if ( e->flags & RUN_AT ) {
326
						e->flags &= ~RUN_AT;
327
						e->lastrun = TargetTime;
328
						job_add(e, u);
329
						continue;
330
					} else 
331
						e->flags &= ~NOT_UNTIL;
332
				} else if ( e->flags & NOT_UNTIL )
333
					continue;
334
			}
335
336
			if (bit_test(e->second, second)
337
			 && bit_test(e->minute, minute)
338
			 && bit_test(e->hour, hour)
339
			 && bit_test(e->month, month)
340
			 && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
341
			      ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
333
			      ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
342
			      : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
334
			      : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
343
			    )
335
			    )
344
			   ) {
336
			   ) {
345
				e->flags &= ~RUN_AT;
337
				if ((doNonWild &&
346
				e->lastrun = TargetTime;
338
				    !(e->flags & (MIN_STAR|HR_STAR))) || 
347
				job_add(e, u);
339
				    (doWild && (e->flags & (MIN_STAR|HR_STAR))))
340
					job_add(e, u);
348
			}
341
			}
349
		}
342
		}
350
	}
343
	}
351
352
	last_time = TargetTime;
353
	lasttm = *tm;
354
}
344
}
355
345
356
346
/*
357
/* the task here is to figure out how long it's going to be until :00 of the
347
 * Set StartTime and clockTime to the current time.
358
 * following minute and initialize TargetTime to this value.  TargetTime
348
 * These are used for computing what time it really is right now.
359
 * will subsequently slide 60 seconds at a time, with correction applied
349
 * Note that clockTime is a unix wallclock time converted to minutes.
360
 * implicitly in cron_sleep().  it would be nice to let cron execute in
361
 * the "current minute" before going to sleep, but by restarting cron you
362
 * could then get it to execute a given minute's jobs more than once.
363
 * instead we have the chance of missing a minute's jobs completely, but
364
 * that's something sysadmin's know to expect what with crashing computers..
365
 */
350
 */
366
static void
351
static void
367
cron_sync(int secres) {
352
set_time(int initialize) {
368
 	struct tm *tm;
353
	struct tm tm;
354
	static int isdst;
369
355
370
	TargetTime = time((time_t*)0);
356
	StartTime = time(NULL);
371
	if (secres != 0) {
372
		TargetTime += 1;
373
	} else {
374
		tm = localtime(&TargetTime);
375
		TargetTime += (60 - tm->tm_sec);
376
	}
377
}
378
357
379
static void
358
	/* We adjust the time to GMT so we can catch DST changes. */
380
timespec_subtract(struct timespec *result, struct timespec *x,
359
	tm = *localtime(&StartTime);
381
    struct timespec *y)
360
	if (initialize || tm.tm_isdst != isdst) {
382
{
361
		isdst = tm.tm_isdst;
383
	*result = *x;
362
		GMToff = get_gmtoff(&StartTime, &tm);
384
	result->tv_sec -= y->tv_sec;
363
		Debug(DSCH, ("[%ld] GMToff=%ld\n",
385
	result->tv_nsec -= y->tv_nsec;
364
		    (long)getpid(), (long)GMToff))
386
	if (result->tv_nsec < 0) {
387
		result->tv_sec--;
388
		result->tv_nsec += 1000000000;
389
	}
365
	}
366
	clockTime = (StartTime + GMToff) / (time_t)SECONDS_PER_MINUTE;
390
}
367
}
391
368
369
/*
370
 * Try to just hit the next minute.
371
 */
392
static void
372
static void
393
cron_sleep(cron_db *db, int secres)
373
cron_sleep(int target) {
394
{
374
	time_t t1, t2;
395
	int seconds_to_wait;
375
	unsigned char poke;
396
	int rval;
376
	int nfds, fd;
397
	struct timespec ctime, ttime, stime, remtime;
377
	socklen_t sunlen;
398
378
	static fd_set *fdsr;
399
	/*
379
	struct sockaddr_un s_un;
400
	 * Loop until we reach the top of the next minute, sleep when possible.
380
401
	 */
381
	struct timeval seconds_to_wait;
402
382
	seconds_to_wait.tv_usec = 0;
403
	for (;;) {
383
404
		clock_gettime(CLOCK_REALTIME, &ctime);
384
	t1 = time(NULL) + GMToff;
405
		ttime.tv_sec = TargetTime;
385
	seconds_to_wait.tv_sec = (int)(target * SECONDS_PER_MINUTE - t1) + 1;
406
		ttime.tv_nsec = 0;
386
	Debug(DSCH, ("[%ld] Target time=%ld, sec-to-wait=%ld\n",
407
		timespec_subtract(&stime, &ttime, &ctime);
387
	    (long)getpid(), (long)target*SECONDS_PER_MINUTE, seconds_to_wait.tv_sec))
408
388
389
	fdsr = (fd_set *)calloc(howmany(cronSock + 1, NFDBITS),
390
			sizeof(fd_mask));
391
392
	while (seconds_to_wait.tv_sec > 0 && seconds_to_wait.tv_sec < 65) {
393
		poke = RELOAD_CRON;
394
		if (fdsr)
395
			FD_SET(cronSock, fdsr);
409
		/*
396
		/*
410
		 * If the seconds_to_wait value is insane, jump the cron
397
		 * Check to see if we were interrupted by a signal.
398
		 * If so, service the signal(s) then continue sleeping
399
		 * where we left off.
411
		 */
400
		 */
412
401
		nfds = select(cronSock + 1, fdsr, NULL, NULL, &seconds_to_wait);
413
		if (stime.tv_sec < -600 || stime.tv_sec > 600) {
402
		if (nfds == 0)
414
			cron_clean(db);
403
			break;          /* timer expired */
415
			cron_sync(secres);
404
		if (nfds == -1 && errno != EINTR)
416
			continue;
405
			break;          /* an error occurred */
406
		if (nfds > 0) {
407
			Debug(DSCH, ("[%ld] Got a poke on the socket\n",
408
						(long)getpid()))
409
			sunlen = sizeof(s_un);
410
			fd = accept(cronSock, (struct sockaddr *)&s_un, &sunlen);
411
			if (fd >= 0 && fcntl(fd, F_SETFL, O_NONBLOCK) == 0) {
412
				(void) read(fd, &poke, 1);
413
				close(fd);
414
				if (poke & RELOAD_CRON) {
415
					database.mtime = (time_t)0;
416
					load_database(&database);
417
				}
418
			}
417
		}
419
		}
418
420
		else {
419
		seconds_to_wait = (stime.tv_nsec > 0) ? stime.tv_sec + 1 :
421
			if (got_sighup) {
420
		    stime.tv_sec;
422
				got_sighup = 0;
421
423
				log_close();
422
		Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
424
			}
423
			getpid(), (long)TargetTime, seconds_to_wait))
425
			if (got_sigchld) {
424
426
				got_sigchld = 0;
425
		/*
427
				sigchld_reaper();
426
		 * If we've run out of wait time or there are no jobs left
427
		 * to run, break
428
		 */
429
430
		if (stime.tv_sec < 0)
431
			break;
432
		if (job_runqueue() == 0) {
433
			Debug(DSCH, ("[%d] sleeping for %d seconds\n",
434
				getpid(), seconds_to_wait))
435
436
			for (;;) {
437
				rval = nanosleep(&stime, &remtime);
438
				if (rval == 0 || errno != EINTR)
439
					break;
440
				stime.tv_sec = remtime.tv_sec;
441
				stime.tv_nsec = remtime.tv_nsec;
442
			}
428
			}
443
		}
429
		}
430
		t2 = time(NULL) + GMToff;
431
		seconds_to_wait.tv_sec -= (int)(t2 - t1);
432
		t1 = t2;
444
	}
433
	}
445
}
434
}
446
435
447
448
/* if the time was changed abruptly, clear the flags related
449
 * to the daylight time switch handling to avoid strange effects
450
 */
451
452
static void
436
static void
453
cron_clean(db)
437
sighup_handler(int x) {
454
	cron_db	*db;
438
	got_sighup = 1;
455
{
439
}
456
	user		*u;
457
	entry		*e;
458
440
459
	last_time = 0;
441
static void
442
sigchld_handler(int x) {
443
	got_sigchld = 1;
444
}
460
445
461
	for (u = db->head;  u != NULL;  u = u->next) {
446
static void
462
		for (e = u->crontab;  e != NULL;  e = e->next) {
447
quit(int x) {
463
			e->flags &= ~(RUN_AT|NOT_UNTIL);
448
	pidfile_remove(pfh);
464
		}
449
	_exit(0);
465
	}
466
}
450
}
467
451
468
#ifdef USE_SIGCHLD
469
static void
452
static void
470
sigchld_handler(int x)
453
sigchld_reaper(void) {
471
{
454
	WAIT_T waiter;
472
	WAIT_T		waiter;
455
	PID_T pid;
473
	PID_T		pid;
474
456
475
	for (;;) {
457
	do {
476
#ifdef POSIX
477
		pid = waitpid(-1, &waiter, WNOHANG);
458
		pid = waitpid(-1, &waiter, WNOHANG);
478
#else
479
		pid = wait3(&waiter, WNOHANG, (struct rusage *)0);
480
#endif
481
		switch (pid) {
459
		switch (pid) {
482
		case -1:
460
		case -1:
461
			if (errno == EINTR)
462
				continue;
483
			Debug(DPROC,
463
			Debug(DPROC,
484
				("[%d] sigchld...no children\n", getpid()))
464
			      ("[%ld] sigchld...no children\n",
485
			return;
465
			       (long)getpid()))
466
			break;
486
		case 0:
467
		case 0:
487
			Debug(DPROC,
468
			Debug(DPROC,
488
				("[%d] sigchld...no dead kids\n", getpid()))
469
			      ("[%ld] sigchld...no dead kids\n",
489
			return;
470
			       (long)getpid()))
471
			break;
490
		default:
472
		default:
491
			Debug(DPROC,
473
			Debug(DPROC,
492
				("[%d] sigchld...pid #%d died, stat=%d\n",
474
			      ("[%ld] sigchld...pid #%ld died, stat=%d\n",
493
				getpid(), pid, WEXITSTATUS(waiter)))
475
			       (long)getpid(), (long)pid, WEXITSTATUS(waiter)))
476
			break;
494
		}
477
		}
495
	}
478
	} while (pid > 0);
496
}
479
}
497
#endif /*USE_SIGCHLD*/
498
499
480
500
static void
481
static void
501
sighup_handler(int x)
482
parse_args(int argc, char *argv[]) {
502
{
483
	int argch;
503
	log_close();
504
}
505
484
485
	char *endp;
506
486
507
static void
487
	while (-1 != (argch = getopt(argc, argv, "j:J:m:nx:"))) {
508
parse_args(argc, argv)
509
	int	argc;
510
	char	*argv[];
511
{
512
	int	argch;
513
	char	*endp;
514
515
	while ((argch = getopt(argc, argv, "j:J:m:osx:")) != -1) {
516
		switch (argch) {
488
		switch (argch) {
489
		default:
490
			usage();
517
		case 'j':
491
		case 'j':
518
			Jitter = strtoul(optarg, &endp, 10);
492
			Jitter = strtoul(optarg, &endp, 10);
519
			if (*optarg == '\0' || *endp != '\0' || Jitter > 60)
493
			if (*optarg == '\0' || *endp != '\0' || Jitter > 60)
520
				errx(ERROR_EXIT,
494
				errx(ERROR_EXIT,
521
				     "bad value for jitter: %s", optarg);
495
						"bad value for jitter: %s", optarg);
522
			break;
496
			break;
523
		case 'J':
497
		case 'J':
524
			RootJitter = strtoul(optarg, &endp, 10);
498
			RootJitter = strtoul(optarg, &endp, 10);
525
			if (*optarg == '\0' || *endp != '\0' || RootJitter > 60)
499
			if( *optarg == '\0' || *endp != '\0' || RootJitter > 60)
526
				errx(ERROR_EXIT,
500
				errx(ERROR_EXIT,
527
				     "bad value for root jitter: %s", optarg);
501
						"bad value for root jitter: %s", optarg);
528
			break;
502
			break;
529
		case 'm':
503
		case 'm':
530
			defmailto = optarg;
504
			defmailto = optarg;
531
			break;
505
			break;
532
		case 'o':
533
			dst_enabled = 0;
534
			break;
535
		case 's':
536
			dst_enabled = 1;
537
			break;
538
		case 'x':
506
		case 'x':
539
			if (!set_debug_flags(optarg))
507
			if (!set_debug_flags(optarg))
540
				usage();
508
				usage();
541
			break;
509
			break;
542
		default:
510
		case 'n':
543
			usage();
511
			NoFork = 1;
544
		}
512
			break;
545
	}
546
}
547
548
static int
549
run_at_secres(cron_db *db)
550
{
551
	user *u;
552
	entry *e;
553
554
	for (u = db->head;  u != NULL;  u = u->next) {
555
		for (e = u->crontab;  e != NULL;  e = e->next) {
556
			if ((e->flags & SEC_RES) != 0)
557
				return 1;
558
		}
513
		}
559
	}
514
	}
560
	return 0;
561
}
515
}
(-)cron/cron/cron.h (-287 / +26 lines)
Lines 1-307 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
/* cron.h - header for vixie's cron
22
/* cron.h - header for vixie's cron
19
 *
23
 *
20
 * $FreeBSD: head/usr.sbin/cron/cron/cron.h 242101 2012-10-25 22:54:29Z sobomax $
24
 * $Id: cron.h,v 1.6 2004/01/23 18:56:42 vixie Exp $
21
 *
25
 *
22
 * vix 14nov88 [rest of log is in RCS]
26
 * vix 14nov88 [rest of log is in RCS]
23
 * vix 14jan87 [0 or 7 can be sunday; thanks, mwm@berkeley]
27
 * vix 14jan87 [0 or 7 can be sunday; thanks, mwm@berkeley]
24
 * vix 30dec86 [written]
28
 * vix 30dec86 [written]
25
 */
29
 */
26
30
27
/* reorder these #include's at your peril */
31
#define CRON_VERSION "V5.0"
28
29
#include <sys/types.h>
30
#include <sys/param.h>
31
#include "compat.h"
32
32
33
#include <bitstring.h>
33
unsigned Jitter, RootJitter;
34
#include <ctype.h>
34
extern unsigned Jitter, RootJitter;
35
extern struct pidfh *pfh;
35
#include <err.h>
36
#include <err.h>
36
#include <errno.h>
37
#include <libutil.h>
37
#include <libutil.h>
38
#include <pwd.h>
39
#include <signal.h>
40
#include <stdio.h>
41
#include <time.h>
42
#include <sys/wait.h>
43
38
44
#include "pathnames.h"
39
#define SYS_NAME "*system*"
45
#include "config.h"
40
#include "config.h"
46
#include "externs.h"
41
#include "externs.h"
47
42
#include "pathnames.h"
48
	/* these are really immutable, and are
43
#include "macros.h"
49
	 *   defined for symbolic convenience only
44
#include "structs.h"
50
	 * TRUE, FALSE, and ERR must be distinct
45
#include "funcs.h"
51
	 * ERR must be < OK.
46
#include "globals.h"
52
	 */
53
#define TRUE		1
54
#define FALSE		0
55
	/* system calls return this on success */
56
#define OK		0
57
	/*   or this on error */
58
#define ERR		(-1)
59
60
	/* turn this on to get '-x' code */
61
#ifndef DEBUGGING
62
#define DEBUGGING	FALSE
63
#endif
64
65
#define READ_PIPE	0	/* which end of a pipe pair do you read? */
66
#define WRITE_PIPE	1	/*   or write to? */
67
#define STDIN		0	/* what is stdin's file descriptor? */
68
#define STDOUT		1	/*   stdout's? */
69
#define STDERR		2	/*   stderr's? */
70
#define ERROR_EXIT	1	/* exit() with this will scare the shell */
71
#define	OK_EXIT		0	/* exit() with this is considered 'normal' */
72
#define	MAX_FNAME	100	/* max length of internally generated fn */
73
#define	MAX_COMMAND	1000	/* max length of internally generated cmd */
74
#define	MAX_ENVSTR	1000	/* max length of envvar=value\0 strings */
75
#define	MAX_TEMPSTR	100	/* obvious */
76
#define	MAX_UNAME	20	/* max length of username, should be overkill */
77
#define	ROOT_UID	0	/* don't change this, it really must be root */
78
#define	ROOT_USER	"root"	/* ditto */
79
#define	SYS_NAME	"*system*" /* magic owner name for system crontab */
80
81
				/* NOTE: these correspond to DebugFlagNames,
82
				 *	defined below.
83
				 */
84
#define	DEXT		0x0001	/* extend flag for other debug masks */
85
#define	DSCH		0x0002	/* scheduling debug mask */
86
#define	DPROC		0x0004	/* process control debug mask */
87
#define	DPARS		0x0008	/* parsing debug mask */
88
#define	DLOAD		0x0010	/* database loading debug mask */
89
#define	DMISC		0x0020	/* misc debug mask */
90
#define	DTEST		0x0040	/* test mode: don't execute any commands */
91
#define	DBIT		0x0080	/* bit twiddling shown (long) */
92
93
#define	CRON_TAB(u)	"%s/%s", SPOOL_DIR, u
94
#define	REG		register
95
#define	PPC_NULL	((char **)NULL)
96
97
#ifndef MAXHOSTNAMELEN
98
#define MAXHOSTNAMELEN 256
99
#endif
100
101
#define	Skip_Blanks(c, f) \
102
			while (c == '\t' || c == ' ') \
103
				c = get_char(f);
104
105
#define	Skip_Nonblanks(c, f) \
106
			while (c!='\t' && c!=' ' && c!='\n' && c != EOF) \
107
				c = get_char(f);
108
109
#define	Skip_Line(c, f) \
110
			do {c = get_char(f);} while (c != '\n' && c != EOF);
111
112
#if DEBUGGING
113
# define Debug(mask, message) \
114
			if ( (DebugFlags & (mask) ) == (mask) ) \
115
				printf message;
116
#else /* !DEBUGGING */
117
# define Debug(mask, message) \
118
			;
119
#endif /* DEBUGGING */
120
121
#define	MkLower(ch)	(isupper(ch) ? tolower(ch) : ch)
122
#define	MkUpper(ch)	(islower(ch) ? toupper(ch) : ch)
123
#define	Set_LineNum(ln)	{Debug(DPARS|DEXT,("linenum=%d\n",ln)); \
124
			 LineNumber = ln; \
125
			}
126
127
#define	FIRST_SECOND	0
128
#define	LAST_SECOND	59
129
#define	SECOND_COUNT	(LAST_SECOND - FIRST_SECOND + 1)
130
131
#define	FIRST_MINUTE	0
132
#define	LAST_MINUTE	59
133
#define	MINUTE_COUNT	(LAST_MINUTE - FIRST_MINUTE + 1)
134
135
#define	FIRST_HOUR	0
136
#define	LAST_HOUR	23
137
#define	HOUR_COUNT	(LAST_HOUR - FIRST_HOUR + 1)
138
139
#define	FIRST_DOM	1
140
#define	LAST_DOM	31
141
#define	DOM_COUNT	(LAST_DOM - FIRST_DOM + 1)
142
143
#define	FIRST_MONTH	1
144
#define	LAST_MONTH	12
145
#define	MONTH_COUNT	(LAST_MONTH - FIRST_MONTH + 1)
146
147
/* note on DOW: 0 and 7 are both Sunday, for compatibility reasons. */
148
#define	FIRST_DOW	0
149
#define	LAST_DOW	7
150
#define	DOW_COUNT	(LAST_DOW - FIRST_DOW + 1)
151
152
#ifdef LOGIN_CAP
153
/* see init.c */
154
#define RESOURCE_RC "daemon"
155
#endif
156
157
			/* each user's crontab will be held as a list of
158
			 * the following structure.
159
			 *
160
			 * These are the cron commands.
161
			 */
162
163
typedef	struct _entry {
164
	struct _entry	*next;
165
	uid_t		uid;
166
	gid_t		gid;
167
#ifdef LOGIN_CAP
168
	char            *class;
169
#endif
170
	char		**envp;
171
	char		*cmd;
172
	bitstr_t	bit_decl(second, SECOND_COUNT);
173
	bitstr_t	bit_decl(minute, MINUTE_COUNT);
174
	bitstr_t	bit_decl(hour,   HOUR_COUNT);
175
	bitstr_t	bit_decl(dom,    DOM_COUNT);
176
	bitstr_t	bit_decl(month,  MONTH_COUNT);
177
	bitstr_t	bit_decl(dow,    DOW_COUNT);
178
	int		flags;
179
#define	DOM_STAR	0x01
180
#define	DOW_STAR	0x02
181
#define	WHEN_REBOOT	0x04
182
#define	RUN_AT	0x08
183
#define	NOT_UNTIL	0x10
184
#define	SEC_RES		0x20
185
	time_t	lastrun;
186
} entry;
187
188
			/* the crontab database will be a list of the
189
			 * following structure, one element per user
190
			 * plus one for the system.
191
			 *
192
			 * These are the crontabs.
193
			 */
194
195
typedef	struct _user {
196
	struct _user	*next, *prev;	/* links */
197
	char		*name;
198
	time_t		mtime;		/* last modtime of crontab */
199
	entry		*crontab;	/* this person's crontab */
200
} user;
201
202
typedef	struct _cron_db {
203
	user		*head, *tail;	/* links */
204
	time_t		mtime;		/* last modtime on spooldir */
205
} cron_db;
206
207
208
void		set_cron_uid(void),
209
		set_cron_cwd(void),
210
		load_database(cron_db *),
211
		open_logfile(void),
212
		sigpipe_func(void),
213
		job_add(entry *, user *),
214
		do_command(entry *, user *),
215
		link_user(cron_db *, user *),
216
		unlink_user(cron_db *, user *),
217
		free_user(user *),
218
		env_free(char **),
219
		unget_char(int, FILE *),
220
		free_entry(entry *),
221
		skip_comments(FILE *),
222
		log_it(char *, int, char *, char *),
223
		log_close(void);
224
225
int		job_runqueue(void),
226
		set_debug_flags(char *),
227
		get_char(FILE *),
228
		get_string(char *, int, FILE *, char *),
229
		swap_uids(void),
230
		swap_uids_back(void),
231
		load_env(char *, FILE *),
232
		cron_pclose(FILE *),
233
		strcmp_until(char *, char *, int),
234
		allowed(char *),
235
		strdtb(char *);
236
237
char		*env_get(char *, char **),
238
		*arpadate(time_t *),
239
		*mkprints(unsigned char *, unsigned int),
240
		*first_word(char *, char *),
241
		**env_init(void),
242
		**env_copy(char **),
243
		**env_set(char **, char *);
244
245
user		*load_user(int, struct passwd *, char *),
246
		*find_user(cron_db *, char *);
247
248
entry		*load_entry(FILE *, void (*)(char *),
249
				 struct passwd *, char **);
250
251
FILE		*cron_popen(char *, char *, entry *);
252
253
254
				/* in the C tradition, we only create
255
				 * variables for the main program, just
256
				 * extern them elsewhere.
257
				 */
258
259
#ifdef MAIN_PROGRAM
260
# if !defined(LINT) && !defined(lint)
261
char	*copyright[] = {
262
		"@(#) Copyright 1988,1989,1990,1993,1994 by Paul Vixie",
263
		"@(#) All rights reserved"
264
	};
265
# endif
266
267
char	*MonthNames[] = {
268
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
269
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
270
		NULL
271
	};
272
273
char	*DowNames[] = {
274
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
275
		NULL
276
	};
277
278
char	*ProgramName,
279
	*defmailto;
280
int	LineNumber;
281
unsigned Jitter,
282
	RootJitter;
283
time_t	TargetTime;
284
285
# if DEBUGGING
286
int	DebugFlags;
287
char	*DebugFlagNames[] = {	/* sync with #defines */
288
		"ext", "sch", "proc", "pars", "load", "misc", "test", "bit",
289
		NULL		/* NULL must be last element */
290
	};
291
# endif /* DEBUGGING */
292
#else /*MAIN_PROGRAM*/
293
extern	char	*copyright[],
294
		*MonthNames[],
295
		*DowNames[],
296
		*ProgramName,
297
		*defmailto;
298
extern	int	LineNumber;
299
extern unsigned	Jitter,
300
		RootJitter;
301
extern	time_t	TargetTime;
302
extern struct pidfh *pfh;
303
# if DEBUGGING
304
extern	int	DebugFlags;
305
extern	char	*DebugFlagNames[];
306
# endif /* DEBUGGING */
307
#endif /*MAIN_PROGRAM*/
(-)cron/cron/database.c (-79 / +75 lines)
Lines 1-55 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
#if !defined(lint) && !defined(LINT)
22
//#if !defined(lint) && !defined(LINT)
19
static const char rcsid[] =
23
//static char rcsid[] = "$Id: database.c,v 1.7 2004/01/23 18:56:42 vixie Exp $";
20
  "$FreeBSD: head/usr.sbin/cron/cron/database.c 173412 2007-11-07 10:53:41Z kevlo $";
24
//#endif
21
#endif
22
25
23
/* vix 26jan87 [RCS has the log]
26
/* vix 26jan87 [RCS has the log]
24
 */
27
 */
25
28
26
27
#include "cron.h"
29
#include "cron.h"
28
#include <fcntl.h>
29
#include <sys/stat.h>
30
#include <sys/file.h>
31
32
30
33
#define TMAX(a,b) ((a)>(b)?(a):(b))
31
#define TMAX(a,b) ((a)>(b)?(a):(b))
34
32
35
33
static	void		process_crontab(const char *, const char *,
36
static	void		process_crontab(char *, char *, char *,
34
					const char *, struct stat *,
37
					     struct stat *,
35
					cron_db *, cron_db *);
38
					     cron_db *, cron_db *);
39
40
36
41
void
37
void
42
load_database(old_db)
38
load_database(cron_db *old_db) {
43
	cron_db		*old_db;
39
	struct stat statbuf, syscron_stat;
44
{
40
	cron_db new_db;
45
	DIR		*dir;
41
	DIR_T *dp;
46
	struct stat	statbuf;
42
	DIR *dir;
47
	struct stat	syscron_stat;
43
	user *u, *nu;
48
	DIR_T   	*dp;
49
	cron_db		new_db;
50
	user		*u, *nu;
51
44
52
	Debug(DLOAD, ("[%d] load_database()\n", getpid()))
45
	Debug(DLOAD, ("[%ld] load_database()\n", (long)getpid()))
53
46
54
	/* before we start loading any data, do a stat on SPOOL_DIR
47
	/* before we start loading any data, do a stat on SPOOL_DIR
55
	 * so that if anything changes as of this moment (i.e., before we've
48
	 * so that if anything changes as of this moment (i.e., before we've
Lines 73-80 Link Here
73
	 * time this function is called.
66
	 * time this function is called.
74
	 */
67
	 */
75
	if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
68
	if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
76
		Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
69
		Debug(DLOAD, ("[%ld] spool dir mtime unch, no load needed.\n",
77
			      getpid()))
70
			      (long)getpid()))
78
		return;
71
		return;
79
	}
72
	}
80
73
Lines 86-96 Link Here
86
	new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
79
	new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
87
	new_db.head = new_db.tail = NULL;
80
	new_db.head = new_db.tail = NULL;
88
81
89
	if (syscron_stat.st_mtime) {
82
	if (syscron_stat.st_mtime)
90
		process_crontab("root", SYS_NAME,
83
		process_crontab("root", NULL, SYSCRONTAB, &syscron_stat,
91
				SYSCRONTAB, &syscron_stat,
92
				&new_db, old_db);
84
				&new_db, old_db);
93
	}
94
85
95
	/* we used to keep this dir open all the time, for the sake of
86
	/* we used to keep this dir open all the time, for the sake of
96
	 * efficiency.  however, we need to close it in every fork, and
87
	 * efficiency.  however, we need to close it in every fork, and
Lines 102-109 Link Here
102
	}
93
	}
103
94
104
	while (NULL != (dp = readdir(dir))) {
95
	while (NULL != (dp = readdir(dir))) {
105
		char	fname[MAXNAMLEN+1],
96
		char fname[MAXNAMLEN+1], tabname[MAXNAMLEN+1];
106
			tabname[MAXNAMLEN+1];
107
97
108
		/* avoid file names beginning with ".".  this is good
98
		/* avoid file names beginning with ".".  this is good
109
		 * because we would otherwise waste two guaranteed calls
99
		 * because we would otherwise waste two guaranteed calls
Lines 113-121 Link Here
113
		if (dp->d_name[0] == '.')
103
		if (dp->d_name[0] == '.')
114
			continue;
104
			continue;
115
105
116
		(void) strncpy(fname, dp->d_name, sizeof(fname));
106
		if (strlen(dp->d_name) >= sizeof fname)
117
		fname[sizeof(fname)-1] = '\0';
107
			continue;	/* XXX log? */
118
		(void) snprintf(tabname, sizeof tabname, CRON_TAB(fname));
108
		(void) strlcpy(fname, dp->d_name, sizeof(fname));
109
		
110
		if (!glue_strings(tabname, sizeof tabname, SPOOL_DIR,
111
				  fname, '/'))
112
			continue;	/* XXX log? */
119
113
120
		process_crontab(fname, fname, tabname,
114
		process_crontab(fname, fname, tabname,
121
				&statbuf, &new_db, old_db);
115
				&statbuf, &new_db, old_db);
Lines 144-155 Link Here
144
	Debug(DLOAD, ("load_database is done\n"))
138
	Debug(DLOAD, ("load_database is done\n"))
145
}
139
}
146
140
147
148
void
141
void
149
link_user(db, u)
142
link_user(cron_db *db, user *u) {
150
	cron_db	*db;
151
	user	*u;
152
{
153
	if (db->head == NULL)
143
	if (db->head == NULL)
154
		db->head = u;
144
		db->head = u;
155
	if (db->tail)
145
	if (db->tail)
Lines 159-170 Link Here
159
	db->tail = u;
149
	db->tail = u;
160
}
150
}
161
151
162
163
void
152
void
164
unlink_user(db, u)
153
unlink_user(cron_db *db, user *u) {
165
	cron_db	*db;
166
	user	*u;
167
{
168
	if (u->prev == NULL)
154
	if (u->prev == NULL)
169
		db->head = u->next;
155
		db->head = u->next;
170
	else
156
	else
Lines 176-218 Link Here
176
		u->next->prev = u->prev;
162
		u->next->prev = u->prev;
177
}
163
}
178
164
179
180
user *
165
user *
181
find_user(db, name)
166
find_user(cron_db *db, const char *name) {
182
	cron_db	*db;
167
	user *u;
183
	char	*name;
184
{
185
	char	*env_get();
186
	user	*u;
187
168
188
	for (u = db->head;  u != NULL;  u = u->next)
169
	for (u = db->head;  u != NULL;  u = u->next)
189
		if (!strcmp(u->name, name))
170
		if (strcmp(u->name, name) == 0)
190
			break;
171
			break;
191
	return u;
172
	return (u);
192
}
173
}
193
174
194
195
static void
175
static void
196
process_crontab(uname, fname, tabname, statbuf, new_db, old_db)
176
process_crontab(const char *uname, const char *fname, const char *tabname,
197
	char		*uname;
177
		struct stat *statbuf, cron_db *new_db, cron_db *old_db)
198
	char		*fname;
199
	char		*tabname;
200
	struct stat	*statbuf;
201
	cron_db		*new_db;
202
	cron_db		*old_db;
203
{
178
{
204
	struct passwd	*pw = NULL;
179
	struct passwd *pw = NULL;
205
	int		crontab_fd = OK - 1;
180
	int crontab_fd = OK - 1;
206
	user		*u;
181
	user *u;
207
182
208
	if (strcmp(fname, SYS_NAME) && !(pw = getpwnam(uname))) {
183
	if (fname == NULL) {
184
		/* must be set to something for logging purposes.
185
		 */
186
		fname = "*system*";
187
	} else if ((pw = getpwnam(uname)) == NULL) {
209
		/* file doesn't have a user in passwd file.
188
		/* file doesn't have a user in passwd file.
210
		 */
189
		 */
211
		log_it(fname, getpid(), "ORPHAN", "no passwd entry");
190
		log_it(fname, getpid(), "ORPHAN", "no passwd entry");
212
		goto next_crontab;
191
		goto next_crontab;
213
	}
192
	}
214
193
215
	if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
194
	if ((crontab_fd = open(tabname, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < OK) {
216
		/* crontab not accessible?
195
		/* crontab not accessible?
217
		 */
196
		 */
218
		log_it(fname, getpid(), "CAN'T OPEN", tabname);
197
		log_it(fname, getpid(), "CAN'T OPEN", tabname);
Lines 223-228 Link Here
223
		log_it(fname, getpid(), "FSTAT FAILED", tabname);
202
		log_it(fname, getpid(), "FSTAT FAILED", tabname);
224
		goto next_crontab;
203
		goto next_crontab;
225
	}
204
	}
205
	if (!S_ISREG(statbuf->st_mode)) {
206
		log_it(fname, getpid(), "NOT REGULAR", tabname);
207
		goto next_crontab;
208
	}
209
	if ((statbuf->st_mode & 07777) != 0600) {
210
		log_it(fname, getpid(), "BAD FILE MODE", tabname);
211
		goto next_crontab;
212
	}
213
	if (statbuf->st_uid != ROOT_UID && (pw == NULL ||
214
	    statbuf->st_uid != pw->pw_uid || strcmp(uname, pw->pw_name) != 0)) {
215
		log_it(fname, getpid(), "WRONG FILE OWNER", tabname);
216
		goto next_crontab;
217
	}
218
	if (statbuf->st_nlink != 1) {
219
		log_it(fname, getpid(), "BAD LINK COUNT", tabname);
220
		goto next_crontab;
221
	}
226
222
227
	Debug(DLOAD, ("\t%s:", fname))
223
	Debug(DLOAD, ("\t%s:", fname))
228
	u = find_user(old_db, fname);
224
	u = find_user(old_db, fname);
Lines 255-261 Link Here
255
		link_user(new_db, u);
251
		link_user(new_db, u);
256
	}
252
	}
257
253
258
next_crontab:
254
 next_crontab:
259
	if (crontab_fd >= OK) {
255
	if (crontab_fd >= OK) {
260
		Debug(DLOAD, (" [done]\n"))
256
		Debug(DLOAD, (" [done]\n"))
261
		close(crontab_fd);
257
		close(crontab_fd);
(-)cron/cron/do_command.c (-266 / +235 lines)
Lines 1-54 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
#if !defined(lint) && !defined(LINT)
22
//#if !defined(lint) && !defined(LINT)
19
static const char rcsid[] =
23
//static char rcsid[] = "$Id: do_command.c,v 1.9 2004/01/23 18:56:42 vixie Exp $";
20
  "$FreeBSD: head/usr.sbin/cron/cron/do_command.c 228990 2011-12-30 10:58:14Z uqs $";
24
//#endif
21
#endif
22
23
25
24
#include "cron.h"
26
#include "cron.h"
25
#include <sys/signal.h>
27
26
#if defined(sequent)
28
#if defined(sequent)
27
# include <sys/universe.h>
29
# include <sys/universe.h>
28
#endif
30
#endif
29
#if defined(SYSLOG)
31
30
# include <syslog.h>
31
#endif
32
#if defined(LOGIN_CAP)
32
#if defined(LOGIN_CAP)
33
# include <login_cap.h>
33
# include <login_cap.h>
34
#endif
34
#endif
35
35
#ifdef PAM
36
#ifdef PAM
36
# include <security/pam_appl.h>
37
# include <security/pam_appl.h>
37
# include <security/openpam.h>
38
# include <security/openpam.h>
38
#endif
39
#endif
39
40
static void		child_process(entry *, user *);
40
41
static int		safe_p(const char *, const char *);
41
static void		child_process(entry *, user *),
42
			do_univ(user *);
43
44
42
45
void
43
void
46
do_command(e, u)
44
do_command(entry *e, user *u) {
47
	entry	*e;
48
	user	*u;
49
{
50
	Debug(DPROC, ("[%d] do_command(%s, (%s,%d,%d))\n",
45
	Debug(DPROC, ("[%d] do_command(%s, (%s,%d,%d))\n",
51
		getpid(), e->cmd, u->name, e->uid, e->gid))
46
		      getpid(), e->cmd, u->name, e->uid, e->gid))
52
47
53
	/* fork to become asynchronous -- parent process is done immediately,
48
	/* fork to become asynchronous -- parent process is done immediately,
54
	 * and continues to run the normal cron code, which means return to
49
	 * and continues to run the normal cron code, which means return to
Lines 59-99 Link Here
59
	 */
54
	 */
60
	switch (fork()) {
55
	switch (fork()) {
61
	case -1:
56
	case -1:
62
		log_it("CRON",getpid(),"error","can't fork");
57
		log_it("CRON", getpid(), "error", "can't fork");
63
		break;
58
		break;
64
	case 0:
59
	case 0:
65
		/* child process */
60
		/* child process */
66
		pidfile_close(pfh);
61
		pidfile_close(pfh);
67
		child_process(e, u);
62
		child_process(e, u);
68
		Debug(DPROC, ("[%d] child process done, exiting\n", getpid()))
63
		Debug(DPROC, ("[%ld] child process done, exiting\n",
64
			      (long)getpid()))
69
		_exit(OK_EXIT);
65
		_exit(OK_EXIT);
70
		break;
66
		break;
71
	default:
67
	default:
72
		/* parent process */
68
		/* parent process */
73
		break;
69
		break;
74
	}
70
	}
75
	Debug(DPROC, ("[%d] main process returning to work\n", getpid()))
71
	Debug(DPROC, ("[%ld] main process returning to work\n",(long)getpid()))
76
}
72
}
77
73
78
79
static void
74
static void
80
child_process(e, u)
75
child_process(entry *e, user *u) {
81
	entry	*e;
76
	int stdin_pipe[2], stdout_pipe[2];
82
	user	*u;
77
	char *input_data, *usernm, *mailto;
83
{
78
	int children = 0;
84
	int		stdin_pipe[2], stdout_pipe[2];
79
85
	register char	*input_data;
86
	char		*usernm, *mailto;
87
	int		children = 0;
88
# if defined(LOGIN_CAP)
80
# if defined(LOGIN_CAP)
89
	struct passwd	*pwd;
81
	struct passwd *pwd;
90
	login_cap_t *lc;
82
	login_cap_t *lc;
91
# endif
83
# endif
92
84
93
	Debug(DPROC, ("[%d] child_process('%s')\n", getpid(), e->cmd))
85
	Debug(DPROC, ("[%ld] child_process('%s')\n", (long)getpid(), e->cmd))
86
94
87
95
	/* mark ourselves as different to PS command watchers by upshifting
88
	/* mark ourselves as different to PS command watchers by upshiting
96
	 * our program name.  This has no effect on some kernels.
89
	 * our program name. This has no effect on some kernels.
97
	 */
90
	 */
98
	setproctitle("running job");
91
	setproctitle("running job");
99
92
Lines 103-190 Link Here
103
	mailto = env_get("MAILTO", e->envp);
96
	mailto = env_get("MAILTO", e->envp);
104
97
105
#ifdef PAM
98
#ifdef PAM
106
	/* use PAM to see if the user's account is available,
99
        /* use PAM to see if the user's account is available,
107
	 * i.e., not locked or expired or whatever.  skip this
100
         * i.e., not locked or expired or whatever.  skip this
108
	 * for system tasks from /etc/crontab -- they can run
101
         * for system tasks from /etc/crontab -- they can run
109
	 * as any user.
102
         * as any user.
110
	 */
103
         */
111
	if (strcmp(u->name, SYS_NAME)) {	/* not equal */
104
        if (strcmp(u->name, SYS_NAME)) {        /* not equal */
112
		pam_handle_t *pamh = NULL;
105
                pam_handle_t *pamh = NULL;
113
		int pam_err;
106
                int pam_err;
114
		struct pam_conv pamc = {
107
                struct pam_conv pamc = {
115
			.conv = openpam_nullconv,
108
                        .conv = openpam_nullconv,
116
			.appdata_ptr = NULL
109
                        .appdata_ptr = NULL
117
		};
110
                };
118
111
119
		Debug(DPROC, ("[%d] checking account with PAM\n", getpid()))
112
                Debug(DPROC, ("[%d] checking account with PAM\n", getpid()))
120
113
121
		/* u->name keeps crontab owner name while LOGNAME is the name
114
                /* u->name keeps crontab owner name while LOGNAME is the name
122
		 * of user to run command on behalf of.  they should be the
115
                 * of user to run command on behalf of.  they should be the
123
		 * same for a task from a per-user crontab.
116
                 * same for a task from a per-user crontab.
124
		 */
117
                 */
125
		if (strcmp(u->name, usernm)) {
118
                if (strcmp(u->name, usernm)) {
126
			log_it(usernm, getpid(), "username ambiguity", u->name);
119
                        log_it(usernm, getpid(), "username ambiguity", u->name);
127
			exit(ERROR_EXIT);
120
                        exit(ERROR_EXIT);
128
		}
121
                }
129
122
130
		pam_err = pam_start("cron", usernm, &pamc, &pamh);
123
                pam_err = pam_start("cron", usernm, &pamc, &pamh);
131
		if (pam_err != PAM_SUCCESS) {
124
                if (pam_err != PAM_SUCCESS) {
132
			log_it("CRON", getpid(), "error", "can't start PAM");
125
                        log_it("CRON", getpid(), "error", "can't start PAM");
133
			exit(ERROR_EXIT);
126
                        exit(ERROR_EXIT);
134
		}
127
                }
128
129
                pam_err = pam_acct_mgmt(pamh, PAM_SILENT);
130
                /* Expired password shouldn't prevent the job from running. */
131
                if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD) {
132
                        log_it(usernm, getpid(), "USER", "account unavailable");
133
                        exit(ERROR_EXIT);
134
                }
135
135
136
		pam_err = pam_acct_mgmt(pamh, PAM_SILENT);
136
                pam_end(pamh, pam_err);
137
		/* Expired password shouldn't prevent the job from running. */
137
        }
138
		if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD) {
139
			log_it(usernm, getpid(), "USER", "account unavailable");
140
			exit(ERROR_EXIT);
141
		}
142
143
		pam_end(pamh, pam_err);
144
	}
145
#endif
138
#endif
146
139
147
#ifdef USE_SIGCHLD
148
	/* our parent is watching for our death by catching SIGCHLD.  we
140
	/* our parent is watching for our death by catching SIGCHLD.  we
149
	 * do not care to watch for our children's deaths this way -- we
141
	 * do not care to watch for our children's deaths this way -- we
150
	 * use wait() explicitly.  so we have to disable the signal (which
142
	 * use wait() explicitly.  so we have to reset the signal (which
151
	 * was inherited from the parent).
143
	 * was inherited from the parent).
152
	 */
144
	 */
153
	(void) signal(SIGCHLD, SIG_DFL);
145
	(void) signal(SIGCHLD, SIG_DFL);
154
#else
155
	/* on system-V systems, we are ignoring SIGCLD.  we have to stop
156
	 * ignoring it now or the wait() in cron_pclose() won't work.
157
	 * because of this, we have to wait() for our children here, as well.
158
	 */
159
	(void) signal(SIGCLD, SIG_DFL);
160
#endif /*BSD*/
161
146
162
	/* create some pipes to talk to our future child
147
	/* create some pipes to talk to our future child
163
	 */
148
	 */
164
	pipe(stdin_pipe);	/* child's stdin */
149
	pipe(stdin_pipe);	/* child's stdin */
165
	pipe(stdout_pipe);	/* child's stdout */
150
	pipe(stdout_pipe);	/* child's stdout */
166
151
	
167
	/* since we are a forked process, we can diddle the command string
152
	/* since we are a forked process, we can diddle the command string
168
	 * we were passed -- nobody else is going to use it again, right?
153
	 * we were passed -- nobody else is going to use it again, right?
169
	 *
154
	 *
170
	 * if a % is present in the command, previous characters are the
155
	 * if a % is present in the command, previous characters are the
171
	 * command, and subsequent characters are the additional input to
156
	 * command, and subsequent characters are the additional input to
172
	 * the command.  Subsequent %'s will be transformed into newlines,
157
	 * the command.  An escaped % will have the escape character stripped
158
	 * from it.  Subsequent %'s will be transformed into newlines,
173
	 * but that happens later.
159
	 * but that happens later.
174
	 *
175
	 * If there are escaped %'s, remove the escape character.
176
	 */
160
	 */
177
	/*local*/{
161
	/*local*/{
178
		register int escaped = FALSE;
162
		int escaped = FALSE;
179
		register int ch;
163
		int ch;
180
		register char *p;
164
		char *p;
181
165
182
		for (input_data = p = e->cmd; (ch = *input_data);
166
		for (input_data = p = e->cmd;
167
		     (ch = *input_data) != '\0';
183
		     input_data++, p++) {
168
		     input_data++, p++) {
184
			if (p != input_data)
169
			if (p != input_data)
185
			    *p = ch;
170
				*p = ch;
186
			if (escaped) {
171
			if (escaped) {
187
				if (ch == '%' || ch == '\\')
172
				if (ch == '%')
188
					*--p = ch;
173
					*--p = ch;
189
				escaped = FALSE;
174
				escaped = FALSE;
190
				continue;
175
				continue;
Lines 205-230 Link Here
205
	 */
190
	 */
206
	switch (vfork()) {
191
	switch (vfork()) {
207
	case -1:
192
	case -1:
208
		log_it("CRON",getpid(),"error","can't vfork");
193
		log_it("CRON", getpid(), "error", "can't vfork");
209
		exit(ERROR_EXIT);
194
		exit(ERROR_EXIT);
210
		/*NOTREACHED*/
195
		/*NOTREACHED*/
211
	case 0:
196
	case 0:
212
		Debug(DPROC, ("[%d] grandchild process Vfork()'ed\n",
197
		Debug(DPROC, ("[%ld] grandchild process vfork()'ed\n",
213
			      getpid()))
198
			      (long)getpid()))
214
215
		if (e->uid == ROOT_UID)
199
		if (e->uid == ROOT_UID)
216
			Jitter = RootJitter;
200
			Jitter = RootJitter;
217
		if (Jitter != 0) {
201
		if (Jitter != 0) {
218
			srandom(getpid());
202
			srandom(getpid());
219
			sleep(random() % Jitter);
203
			sleep(random() % Jitter);
220
		}
204
		}
221
222
		/* write a log message.  we've waited this long to do it
205
		/* write a log message.  we've waited this long to do it
223
		 * because it was not until now that we knew the PID that
206
		 * because it was not until now that we knew the PID that
224
		 * the actual user command shell was going to get and the
207
		 * the actual user command shell was going to get and the
225
		 * PID is part of the log message.
208
		 * PID is part of the log message.
226
		 */
209
		 */
227
		/*local*/{
210
		if ((e->flags & DONT_LOG) == 0) {
228
			char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
211
			char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
229
212
230
			log_it(usernm, getpid(), "CMD", x);
213
			log_it(usernm, getpid(), "CMD", x);
Lines 233-241 Link Here
233
216
234
		/* that's the last thing we'll log.  close the log files.
217
		/* that's the last thing we'll log.  close the log files.
235
		 */
218
		 */
236
#ifdef SYSLOG
219
		log_close();
237
		closelog();
238
#endif
239
220
240
		/* get new pgrp, void tty, etc.
221
		/* get new pgrp, void tty, etc.
241
		 */
222
		 */
Lines 253-327 Link Here
253
		/* grandchild process.  make std{in,out} be the ends of
234
		/* grandchild process.  make std{in,out} be the ends of
254
		 * pipes opened by our daddy; make stderr go to stdout.
235
		 * pipes opened by our daddy; make stderr go to stdout.
255
		 */
236
		 */
256
		close(STDIN);	dup2(stdin_pipe[READ_PIPE], STDIN);
237
		if (stdin_pipe[READ_PIPE] != STDIN) {
257
		close(STDOUT);	dup2(stdout_pipe[WRITE_PIPE], STDOUT);
238
			dup2(stdin_pipe[READ_PIPE], STDIN);
258
		close(STDERR);	dup2(STDOUT, STDERR);
239
			close(stdin_pipe[READ_PIPE]);
259
240
		}
260
		/* close the pipes we just dup'ed.  The resources will remain.
241
		if (stdout_pipe[WRITE_PIPE] != STDOUT) {
261
		 */
242
			dup2(stdout_pipe[WRITE_PIPE], STDOUT);
262
		close(stdin_pipe[READ_PIPE]);
243
			close(stdout_pipe[WRITE_PIPE]);
263
		close(stdout_pipe[WRITE_PIPE]);
244
		}
264
245
		dup2(STDOUT, STDERR);
265
		/* set our login universe.  Do this in the grandchild
246
266
		 * so that the child can invoke /usr/lib/sendmail
247
267
		 * without surprises.
248
#ifdef LOGIN_CAP
268
		 */
249
 /* Set user's entire context, but skip the environment
269
		do_univ(u);
250
                 * as cron provides a separate interface for this
270
251
                 */
271
# if defined(LOGIN_CAP)
252
                if ((pwd = getpwnam(usernm)) == NULL)
272
		/* Set user's entire context, but skip the environment
253
                        pwd = getpwuid(e->uid);
273
		 * as cron provides a separate interface for this
254
                lc = NULL;
274
		 */
255
                if (pwd != NULL) {
275
		if ((pwd = getpwnam(usernm)) == NULL)
256
                        pwd->pw_gid = e->gid;
276
			pwd = getpwuid(e->uid);
257
                        if (e->class != NULL)
277
		lc = NULL;
258
                                lc = login_getclass(e->class);
278
		if (pwd != NULL) {
259
                }
279
			pwd->pw_gid = e->gid;
260
                if (pwd &&
280
			if (e->class != NULL)
261
                    setusercontext(lc, pwd, e->uid,
281
				lc = login_getclass(e->class);
262
                            LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETENV)) == 0)
282
		}
263
                        (void) endpwent();
283
		if (pwd &&
264
                else {
284
		    setusercontext(lc, pwd, e->uid,
265
                        /* fall back to the old method */
285
			    LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETENV)) == 0)
266
                        (void) endpwent();
286
			(void) endpwent();
267
287
		else {
268
288
			/* fall back to the old method */
269
#endif /* LOGIN_CAP */
289
			(void) endpwent();
270
                    /* set our directory, uid and gid.  Set gid first,
290
# endif
271
                         * since once we set uid, we've lost root privileges.
291
			/* set our directory, uid and gid.  Set gid first,
272
                         */
292
			 * since once we set uid, we've lost root privileges.
273
                        if (setgid(e->gid) != 0) {
293
			 */
274
                                log_it(usernm, getpid(),
294
			if (setgid(e->gid) != 0) {
275
                                    "error", "setgid failed");
295
				log_it(usernm, getpid(),
276
                                exit(ERROR_EXIT);
296
				    "error", "setgid failed");
277
                        }
297
				exit(ERROR_EXIT);
298
			}
299
# if defined(BSD)
278
# if defined(BSD)
300
			if (initgroups(usernm, e->gid) != 0) {
279
                        if (initgroups(usernm, e->gid) != 0) {
301
				log_it(usernm, getpid(),
280
                                log_it(usernm, getpid(),
302
				    "error", "initgroups failed");
281
                                    "error", "initgroups failed");
303
				exit(ERROR_EXIT);
282
                                exit(ERROR_EXIT);
304
			}
283
                        }
305
# endif
284
# endif
306
			if (setlogin(usernm) != 0) {
285
                        if (setlogin(usernm) != 0) {
307
				log_it(usernm, getpid(),
286
                                log_it(usernm, getpid(),
308
				    "error", "setlogin failed");
287
                                    "error", "setlogin failed");
309
				exit(ERROR_EXIT);
288
                                exit(ERROR_EXIT);
310
			}
289
                        }
311
			if (setuid(e->uid) != 0) {
290
                        if (setuid(e->uid) != 0) {
312
				log_it(usernm, getpid(),
291
                                log_it(usernm, getpid(),
313
				    "error", "setuid failed");
292
                                    "error", "setuid failed");
314
				exit(ERROR_EXIT);
293
                                exit(ERROR_EXIT);
315
			}
294
                        }
316
			/* we aren't root after this..*/
295
                        /* we aren't root after this..*/
317
#if defined(LOGIN_CAP)
296
#if defined(LOGIN_CAP)
318
		}
297
                }
319
		if (lc != NULL)
298
                if (lc != NULL)
320
			login_close(lc);
299
                        login_close(lc);
321
#endif
300
#endif
301
322
		chdir(env_get("HOME", e->envp));
302
		chdir(env_get("HOME", e->envp));
323
303
324
		/* exec the command.
304
		/*
305
		 * Exec the command.
325
		 */
306
		 */
326
		{
307
		{
327
			char	*shell = env_get("SHELL", e->envp);
308
			char	*shell = env_get("SHELL", e->envp);
Lines 336-342 Link Here
336
			}
317
			}
337
# endif /*DEBUGGING*/
318
# endif /*DEBUGGING*/
338
			execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
319
			execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
339
			warn("execl: couldn't exec `%s'", shell);
320
			fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
321
			perror("execl");
340
			_exit(ERROR_EXIT);
322
			_exit(ERROR_EXIT);
341
		}
323
		}
342
		break;
324
		break;
Lines 351-357 Link Here
351
	 * the user's command.
333
	 * the user's command.
352
	 */
334
	 */
353
335
354
	Debug(DPROC, ("[%d] child continues, closing pipes\n", getpid()))
336
	Debug(DPROC, ("[%ld] child continues, closing pipes\n",(long)getpid()))
355
337
356
	/* close the ends of the pipe that will only be referenced in the
338
	/* close the ends of the pipe that will only be referenced in the
357
	 * grandchild process...
339
	 * grandchild process...
Lines 371-387 Link Here
371
	 */
353
	 */
372
354
373
	if (*input_data && fork() == 0) {
355
	if (*input_data && fork() == 0) {
374
		register FILE	*out = fdopen(stdin_pipe[WRITE_PIPE], "w");
356
		FILE *out = fdopen(stdin_pipe[WRITE_PIPE], "w");
375
		register int	need_newline = FALSE;
357
		int need_newline = FALSE;
376
		register int	escaped = FALSE;
358
		int escaped = FALSE;
377
		register int	ch;
359
		int ch;
378
360
379
		if (out == NULL) {
361
		if (out == NULL) {
380
			warn("fdopen failed in child2");
362
			warn("fdopen in child2");
381
			_exit(ERROR_EXIT);
363
			_exit(ERROR_EXIT);
382
		}
364
		}
383
365
384
		Debug(DPROC, ("[%d] child2 sending data to grandchild\n", getpid()))
366
		Debug(DPROC, ("[%ld] child2 sending data to grandchild\n",
367
			      (long)getpid()))
385
368
386
		/* close the pipe we don't use, since we inherited it and
369
		/* close the pipe we don't use, since we inherited it and
387
		 * are part of its reference count now.
370
		 * are part of its reference count now.
Lines 393-399 Link Here
393
		 *	%  -> \n
376
		 *	%  -> \n
394
		 *	\x -> \x	for all x != %
377
		 *	\x -> \x	for all x != %
395
		 */
378
		 */
396
		while ((ch = *input_data++)) {
379
		while ((ch = *input_data++) != '\0') {
397
			if (escaped) {
380
			if (escaped) {
398
				if (ch != '%')
381
				if (ch != '%')
399
					putc('\\', out);
382
					putc('\\', out);
Lines 417-423 Link Here
417
		 */
400
		 */
418
		fclose(out);
401
		fclose(out);
419
402
420
		Debug(DPROC, ("[%d] child2 done sending to grandchild\n", getpid()))
403
		Debug(DPROC, ("[%ld] child2 done sending to grandchild\n",
404
			      (long)getpid()))
421
		exit(0);
405
		exit(0);
422
	}
406
	}
423
407
Lines 435-491 Link Here
435
	 * when the grandchild exits, we'll get EOF.
419
	 * when the grandchild exits, we'll get EOF.
436
	 */
420
	 */
437
421
438
	Debug(DPROC, ("[%d] child reading output from grandchild\n", getpid()))
422
	Debug(DPROC, ("[%ld] child reading output from grandchild\n",
423
		      (long)getpid()))
439
424
440
	/*local*/{
425
	/*local*/{
441
		register FILE	*in = fdopen(stdout_pipe[READ_PIPE], "r");
426
		FILE	*in = fdopen(stdout_pipe[READ_PIPE], "r");
442
		register int	ch;
427
		int	ch = getc(in);
443
428
444
		if (in == NULL) {
429
		if (in == NULL) {
445
			warn("fdopen failed in child");
430
			warn("fdopen failed in child");
446
			_exit(ERROR_EXIT);
431
			_exit(ERROR_EXIT);
447
		}
432
		}
448
433
449
		ch = getc(in);
450
		if (ch != EOF) {
434
		if (ch != EOF) {
451
			register FILE	*mail;
435
			FILE	*mail;
452
			register int	bytes = 1;
436
			int	bytes = 1;
453
			int		status = 0;
437
			int	status = 0;
454
438
455
			Debug(DPROC|DEXT,
439
			Debug(DPROC|DEXT,
456
				("[%d] got data (%x:%c) from grandchild\n",
440
			      ("[%ld] got data (%x:%c) from grandchild\n",
457
					getpid(), ch, ch))
441
			       (long)getpid(), ch, ch))
458
442
459
			/* get name of recipient.  this is MAILTO if set to a
443
			/* get name of recipient.  this is MAILTO if set to a
460
			 * valid local username; USER otherwise.
444
			 * valid local username; USER otherwise.
461
			 */
445
			 */
462
			if (mailto == NULL) {
446
			if (mailto == NULL) {
463
				/* MAILTO not present, set to USER,
447
                                /* MAILTO not present, set to USER,
464
				 * unless globally overriden.
448
                                 * unless globally overriden.
465
				 */
449
                                 */
466
				if (defmailto)
450
                                if (defmailto)
467
					mailto = defmailto;
451
                                        mailto = defmailto;
468
				else
452
                                else
469
					mailto = usernm;
453
                                        mailto = usernm;
470
			}
454
                        }
471
			if (mailto && *mailto == '\0')
455
                        if (mailto && *mailto == '\0')
472
				mailto = NULL;
456
                                mailto = NULL;
473
457
458
		
474
			/* if we are supposed to be mailing, MAILTO will
459
			/* if we are supposed to be mailing, MAILTO will
475
			 * be non-NULL.  only in this case should we set
460
			 * be non-NULL.  only in this case should we set
476
			 * up the mail command and subjects and stuff...
461
			 * up the mail command and subjects and stuff...
477
			 */
462
			 */
478
463
479
			if (mailto) {
464
			if (mailto && safe_p(usernm, mailto)) {
480
				register char	**env;
465
				char	**env;
481
				auto char	mailcmd[MAX_COMMAND];
466
				char	mailcmd[MAX_COMMAND];
482
				auto char	hostname[MAXHOSTNAMELEN];
467
				char	hostname[MAXHOSTNAMELEN];
483
468
484
				(void) gethostname(hostname, MAXHOSTNAMELEN);
469
				gethostname(hostname, MAXHOSTNAMELEN);
485
				(void) snprintf(mailcmd, sizeof(mailcmd),
470
				if (strlens(MAILFMT, MAILARG, NULL) + 1
486
					       MAILARGS, MAILCMD);
471
				    >= sizeof mailcmd) {
472
					fprintf(stderr, "mailcmd too long\n");
473
					(void) _exit(ERROR_EXIT);
474
				}
475
				(void)snprintf(mailcmd, sizeof(mailcmd), MAILFMT, MAILARG);
487
				if (!(mail = cron_popen(mailcmd, "w", e))) {
476
				if (!(mail = cron_popen(mailcmd, "w", e))) {
488
					warn("%s", MAILCMD);
477
					warn("%s", mailcmd);
489
					(void) _exit(ERROR_EXIT);
478
					(void) _exit(ERROR_EXIT);
490
				}
479
				}
491
				fprintf(mail, "From: %s (Cron Daemon)\n", usernm);
480
				fprintf(mail, "From: %s (Cron Daemon)\n", usernm);
Lines 493-502 Link Here
493
				fprintf(mail, "Subject: Cron <%s@%s> %s\n",
482
				fprintf(mail, "Subject: Cron <%s@%s> %s\n",
494
					usernm, first_word(hostname, "."),
483
					usernm, first_word(hostname, "."),
495
					e->cmd);
484
					e->cmd);
496
# if defined(MAIL_DATE)
485
#ifdef MAIL_DATE
497
				fprintf(mail, "Date: %s\n",
486
				fprintf(mail, "Date: %s\n",
498
					arpadate(&TargetTime));
487
					arpadate(&StartTime));
499
# endif /* MAIL_DATE */
488
#endif /*MAIL_DATE*/
500
				for (env = e->envp;  *env;  env++)
489
				for (env = e->envp;  *env;  env++)
501
					fprintf(mail, "X-Cron-Env: <%s>\n",
490
					fprintf(mail, "X-Cron-Env: <%s>\n",
502
						*env);
491
						*env);
Lines 523-530 Link Here
523
			 */
512
			 */
524
513
525
			if (mailto) {
514
			if (mailto) {
526
				Debug(DPROC, ("[%d] closing pipe to mail\n",
515
				Debug(DPROC, ("[%ld] closing pipe to mail\n",
527
					getpid()))
516
					      (long)getpid()))
528
				/* Note: the pclose will probably see
517
				/* Note: the pclose will probably see
529
				 * the termination of the grandchild
518
				 * the termination of the grandchild
530
				 * in addition to the mail process, since
519
				 * in addition to the mail process, since
Lines 550-617 Link Here
550
539
551
		} /*if data from grandchild*/
540
		} /*if data from grandchild*/
552
541
553
		Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
542
		Debug(DPROC, ("[%ld] got EOF from grandchild\n",
543
			      (long)getpid()))
554
544
555
		fclose(in);	/* also closes stdout_pipe[READ_PIPE] */
545
		fclose(in);	/* also closes stdout_pipe[READ_PIPE] */
556
	}
546
	}
557
547
558
	/* wait for children to die.
548
	/* wait for children to die.
559
	 */
549
	 */
560
	for (;  children > 0;  children--)
550
	for (; children > 0; children--) {
561
	{
551
		WAIT_T waiter;
562
		WAIT_T		waiter;
552
		PID_T pid;
563
		PID_T		pid;
553
564
554
		Debug(DPROC, ("[%ld] waiting for grandchild #%d to finish\n",
565
		Debug(DPROC, ("[%d] waiting for grandchild #%d to finish\n",
555
			      (long)getpid(), children))
566
			getpid(), children))
556
		while ((pid = wait(&waiter)) < OK && errno == EINTR)
567
		pid = wait(&waiter);
557
			;
568
		if (pid < OK) {
558
		if (pid < OK) {
569
			Debug(DPROC, ("[%d] no more grandchildren--mail written?\n",
559
			Debug(DPROC,
570
				getpid()))
560
			      ("[%ld] no more grandchildren--mail written?\n",
561
			       (long)getpid()))
571
			break;
562
			break;
572
		}
563
		}
573
		Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x",
564
		Debug(DPROC, ("[%ld] grandchild #%ld finished, status=%04x",
574
			getpid(), pid, WEXITSTATUS(waiter)))
565
			      (long)getpid(), (long)pid, WEXITSTATUS(waiter)))
575
		if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
566
		if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
576
			Debug(DPROC, (", dumped core"))
567
			Debug(DPROC, (", dumped core"))
577
		Debug(DPROC, ("\n"))
568
		Debug(DPROC, ("\n"))
578
	}
569
	}
579
}
570
}
580
571
581
572
static int
582
static void
573
safe_p(const char *usernm, const char *s) {
583
do_univ(u)
574
	static const char safe_delim[] = "@!:%-.,";     /* conservative! */
584
	user	*u;
575
	const char *t;
585
{
576
	int ch, first;
586
#if defined(sequent)
577
587
/* Dynix (Sequent) hack to put the user associated with
578
	for (t = s, first = 1; (ch = *t++) != '\0'; first = 0) {
588
 * the passed user structure into the ATT universe if
579
		if (isascii(ch) && isprint(ch) &&
589
 * necessary.  We have to dig the gecos info out of
580
		    (isalnum(ch) || (!first && strchr(safe_delim, ch))))
590
 * the user's password entry to see if the magic
581
			continue;
591
 * "universe(att)" string is present.
582
		log_it(usernm, getpid(), "UNSAFE", s);
592
 */
583
		return (FALSE);
593
594
	struct	passwd	*p;
595
	char	*s;
596
	int	i;
597
598
	p = getpwuid(u->uid);
599
	(void) endpwent();
600
601
	if (p == NULL)
602
		return;
603
604
	s = p->pw_gecos;
605
606
	for (i = 0; i < 4; i++)
607
	{
608
		if ((s = strchr(s, ',')) == NULL)
609
			return;
610
		s++;
611
	}
584
	}
612
	if (strcmp(s, "universe(att)"))
585
	return (TRUE);
613
		return;
614
615
	(void) universe(U_ATT);
616
#endif
617
}
586
}
(-)cron/cron/externs.h (-114 / +98 lines)
Lines 1-78 Link Here
1
/*	$FreeBSD: head/usr.sbin/cron/cron/externs.h 173412 2007-11-07 10:53:41Z kevlo $	*/
2
3
/* Copyright 1993,1994 by Paul Vixie
1
/* Copyright 1993,1994 by Paul Vixie
4
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
5
 *
8
 *
6
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
7
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
8
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
9
 * notice.  May be sold if buildable source is provided to buyer.  No
10
 * warrantee of any kind, express or implied, is included with this
11
 * software; use at your own risk, responsibility for damages (if any) to
12
 * anyone resulting from the use of this software rests entirely with the
13
 * user.
14
 *
12
 *
15
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
 */
20
 */
19
21
20
#if defined(POSIX) || defined(ATT)
22
/* reorder these #include's at your peril */
21
# include <stdlib.h>
23
22
# include <unistd.h>
24
#include <sys/param.h>
23
# include <string.h>
25
#include <sys/types.h>
24
# include <dirent.h>
26
#include <sys/time.h>
25
# define DIR_T	struct dirent
27
#include <sys/wait.h>
26
# define WAIT_T	int
28
#include <sys/fcntl.h>
27
# define WAIT_IS_INT 1
29
#include <sys/file.h>
30
#include <sys/stat.h>
31
32
#include <bitstring.h>
33
#include <ctype.h>
34
#ifndef isascii
35
#define isascii(c)      ((unsigned)(c)<=0177)
36
#endif
37
#include <dirent.h>
38
#include <errno.h>
39
#include <fcntl.h>
40
#include <grp.h>
41
#include <locale.h>
42
#include <pwd.h>
43
#include <signal.h>
44
#include <stdarg.h>
45
#include <stdio.h>
46
#include <stdlib.h>
47
#include <string.h>
48
#include <time.h>
49
#include <unistd.h>
50
#include <utime.h>
51
52
#include <sys/types.h>
53
#include <sys/socket.h>
54
#include <sys/un.h>
55
56
57
#if defined(SYSLOG)
58
# include <syslog.h>
59
#endif
60
61
#if defined(LOGIN_CAP)
62
# include <login_cap.h>
63
#endif /*LOGIN_CAP*/
64
65
#if defined(BSD_AUTH)
66
# include <bsd_auth.h>
67
#endif /*BSD_AUTH*/
68
69
#define DIR_T	struct dirent
70
#define WAIT_T	int
71
#define SIG_T	sig_t
72
#define TIME_T	time_t
73
#define PID_T	pid_t
74
75
#ifndef TZNAME_ALREADY_DEFINED
28
extern char *tzname[2];
76
extern char *tzname[2];
29
# define TZONE(tm) tzname[(tm).tm_isdst]
30
#endif
77
#endif
78
#define TZONE(tm) tzname[(tm).tm_isdst]
31
79
32
#if defined(UNIXPC)
80
#if (defined(BSD)) && (BSD >= 198606) || defined(__linux)
33
# undef WAIT_T
81
# define HAVE_FCHOWN
34
# undef WAIT_IS_INT
82
# define HAVE_FCHMOD
35
# define WAIT_T	union wait
36
#endif
37
38
#if defined(POSIX)
39
# define SIG_T	sig_t
40
# define TIME_T	time_t
41
# define PID_T pid_t
42
#endif
43
44
#if defined(ATT)
45
# define SIG_T	void
46
# define TIME_T	long
47
# define PID_T int
48
#endif
49
50
#if !defined(POSIX) && !defined(ATT)
51
/* classic BSD */
52
extern	time_t		time();
53
extern	unsigned	sleep();
54
extern	struct tm	*localtime();
55
extern	struct passwd	*getpwnam();
56
extern	int		errno;
57
extern	void		perror(), exit(), free();
58
extern	char		*getenv(), *strcpy(), *strchr(), *strtok();
59
extern	void		*malloc(), *realloc();
60
# define SIG_T	void
61
# define TIME_T	long
62
# define PID_T int
63
# define WAIT_T	union wait
64
# define DIR_T	struct direct
65
# include <sys/dir.h>
66
# define TZONE(tm) (tm).tm_zone
67
#endif
83
#endif
68
84
85
#ifdef POSIX
86
#include <unistd.h>
87
#ifdef _POSIX_SAVED_IDS
88
# define HAVE_SAVED_UIDS
89
#endif
90
#endif
91
92
#define MY_UID(pw) getuid()
93
#define MY_GID(pw) getgid()
94
69
/* getopt() isn't part of POSIX.  some systems define it in <stdlib.h> anyway.
95
/* getopt() isn't part of POSIX.  some systems define it in <stdlib.h> anyway.
70
 * of those that do, some complain that our definition is different and some
96
 * of those that do, some complain that our definition is different and some
71
 * do not.  to add to the misery and confusion, some systems define getopt()
97
 * do not.  to add to the misery and confusion, some systems define getopt()
72
 * in ways that we cannot predict or comprehend, yet do not define the adjunct
98
 * in ways that we cannot predict or comprehend, yet do not define the adjunct
73
 * external variables needed for the interface.
99
 * external variables needed for the interface.
74
 */
100
 */
75
#if (!defined(BSD) || (BSD < 198911)) && !defined(ATT) && !defined(UNICOS)
101
#if (!defined(BSD) || (BSD < 198911))
76
int	getopt(int, char * const *, const char *);
102
int	getopt(int, char * const *, const char *);
77
#endif
103
#endif
78
104
Lines 81-147 Link Here
81
extern	int optind, opterr, optopt;
107
extern	int optind, opterr, optopt;
82
#endif
108
#endif
83
109
84
#if WAIT_IS_INT
110
/* digital unix needs this but does not give us a way to identify it.
85
# ifndef WEXITSTATUS
111
 */
86
#  define WEXITSTATUS(x) (((x) >> 8) & 0xff)
87
# endif
88
# ifndef WTERMSIG
89
#  define WTERMSIG(x)	((x) & 0x7f)
90
# endif
91
# ifndef WCOREDUMP
92
#  define WCOREDUMP(x)	((x) & 0x80)
93
# endif
94
#else /*WAIT_IS_INT*/
95
# ifndef WEXITSTATUS
96
#  define WEXITSTATUS(x) ((x).w_retcode)
97
# endif
98
# ifndef WTERMSIG
99
#  define WTERMSIG(x)	((x).w_termsig)
100
# endif
101
# ifndef WCOREDUMP
102
#  define WCOREDUMP(x)	((x).w_coredump)
103
# endif
104
#endif /*WAIT_IS_INT*/
105
106
#ifndef WIFSIGNALED
107
#define WIFSIGNALED(x)	(WTERMSIG(x) != 0)
108
#endif
109
#ifndef WIFEXITED
110
#define WIFEXITED(x)	(WTERMSIG(x) == 0)
111
#endif
112
113
#ifdef NEED_STRCASECMP
114
extern	int		strcasecmp(char *, char *);
115
#endif
116
117
#ifdef NEED_STRDUP
118
extern	char		*strdup(char *);
119
#endif
120
121
#ifdef NEED_STRERROR
122
extern	char		*strerror(int);
123
#endif
124
125
#ifdef NEED_FLOCK
126
extern	int		flock(int, int);
112
extern	int		flock(int, int);
113
114
/* not all systems who provide flock() provide these definitions.
115
 */
116
#ifndef LOCK_SH
127
# define LOCK_SH 1
117
# define LOCK_SH 1
128
# define LOCK_EX 2
129
# define LOCK_NB 4
130
# define LOCK_UN 8
131
#endif
118
#endif
132
119
#ifndef LOCK_EX
133
#ifdef NEED_SETSID
120
# define LOCK_EX 2
134
extern	int		setsid(void);
135
#endif
121
#endif
136
122
#ifndef LOCK_NB
137
#ifdef NEED_GETDTABLESIZE
123
# define LOCK_NB 4
138
extern	int		getdtablesize(void);
139
#endif
124
#endif
140
125
#ifndef LOCK_UN
141
#ifdef NEED_SETENV
126
# define LOCK_UN 8
142
extern	int		setenv(char *, char *, int);
143
#endif
127
#endif
144
128
145
#ifdef NEED_VFORK
129
#ifndef WCOREDUMP
146
extern	PID_T		vfork(void);
130
# define WCOREDUMP(st)          (((st) & 0200) != 0)
147
#endif
131
#endif
(-)cron/cron/funcs.h (+81 lines)
Line 0 Link Here
1
/*
2
 * $Id: funcs.h,v 1.9 2004/01/23 18:56:42 vixie Exp $
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
/* Notes:
23
 *	This file has to be included by cron.h after data structure defs.
24
 *	We should reorg this into sections by module.
25
 */
26
27
void		set_cron_uid(void),
28
		set_cron_cwd(void),
29
		load_database(cron_db *),
30
		open_logfile(void),
31
		sigpipe_func(void),
32
		job_add(entry *, user *),
33
		do_command(entry *, user *),
34
		link_user(cron_db *, user *),
35
		unlink_user(cron_db *, user *),
36
		free_user(user *),
37
		env_free(char **),
38
		unget_char(int, FILE *),
39
		free_entry(entry *),
40
		acquire_daemonlock(int),
41
		skip_comments(FILE *),
42
		log_it(const char *, int, const char *, const char *),
43
		log_close(void),
44
		mkprint(char *, unsigned char *, int);
45
46
int		job_runqueue(void),
47
		set_debug_flags(const char *),
48
		get_char(FILE *),
49
		get_string(char *, int, FILE *, char *),
50
		swap_uids(void),
51
		swap_uids_back(void),
52
		load_env(char *, FILE *),
53
		cron_pclose(FILE *),
54
		glue_strings(char *, size_t, const char *, const char *, char),
55
		strcmp_until(const char *, const char *, char),
56
		allowed(char *),
57
		strdtb(char *),
58
		open_socket(void);
59
60
size_t		strlens(const char *, ...);
61
62
char		*env_get(char *, char **),
63
		*arpadate(time_t *),
64
		*mkprints(unsigned char *, unsigned int),
65
		*first_word(char *, char *),
66
		**env_init(void),
67
		**env_copy(char **),
68
		**env_set(char **, char *);
69
70
user		*load_user(int, struct passwd *, const char *),
71
		*find_user(cron_db *, const char *);
72
73
entry		*load_entry(FILE *, void (*)(), struct passwd *, char **);
74
75
FILE		*cron_popen(char *, char *, entry *);
76
77
struct passwd	*pw_dup(const struct passwd *);
78
79
#ifndef HAVE_TM_GMTOFF
80
long		get_gmtoff(time_t *, struct tm *);
81
#endif
(-)cron/cron/globals.h (+80 lines)
Line 0 Link Here
1
/*
2
 * $Id: globals.h,v 1.10 2004/01/23 19:03:33 vixie Exp $
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
#ifdef MAIN_PROGRAM
23
# define XTRN
24
# define INIT(x) = x
25
#else
26
# define XTRN extern
27
# define INIT(x)
28
#endif
29
30
XTRN const char *copyright[]
31
#ifdef MAIN_PROGRAM
32
	= {
33
		"@(#) ISC Cron V4.1",
34
		"@(#) Copyright 1988,1989,1990,1993,1994 by Paul Vixie",
35
		"@(#) Copyright 1997,2000 by Internet Software Consortium, Inc.",
36
		"@(#) Copyright 2004 by Internet Systems Consortium, Inc.",
37
		"@(#) All rights reserved",
38
		NULL
39
	}
40
#endif
41
	;
42
43
XTRN const char *MonthNames[]
44
#ifdef MAIN_PROGRAM
45
	= {
46
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
47
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
48
		NULL
49
	}
50
#endif
51
	;
52
53
XTRN const char *DowNames[]
54
#ifdef MAIN_PROGRAM
55
	= {
56
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun",
57
		NULL
58
	}
59
#endif
60
	;
61
62
XTRN char	*ProgramName INIT("amnesia");
63
XTRN char	*defmailto;
64
XTRN int	LineNumber INIT(0);
65
XTRN time_t	StartTime INIT(0);
66
XTRN int	NoFork INIT(0);
67
68
#if DEBUGGING
69
XTRN int	DebugFlags INIT(0);
70
XTRN const char *DebugFlagNames[]
71
#ifdef MAIN_PROGRAM
72
	= {
73
		"ext", "sch", "proc", "pars", "load", "misc", "test", "bit",
74
		NULL
75
	}
76
#endif
77
	;
78
#else
79
#define	DebugFlags	0
80
#endif /* DEBUGGING */
(-)cron/cron/job.c (-37 / +34 lines)
Lines 1-76 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
#if !defined(lint) && !defined(LINT)
22
//#if !defined(lint) && !defined(LINT)
19
static const char rcsid[] =
23
//static char rcsid[] = "$Id: job.c,v 1.6 2004/01/23 18:56:43 vixie Exp $";
20
  "$FreeBSD: head/usr.sbin/cron/cron/job.c 50479 1999-08-28 01:35:59Z peter $";
24
//#endif
21
#endif
22
23
25
24
#include "cron.h"
26
#include "cron.h"
25
27
26
27
typedef	struct _job {
28
typedef	struct _job {
28
	struct _job	*next;
29
	struct _job	*next;
29
	entry		*e;
30
	entry		*e;
30
	user		*u;
31
	user		*u;
31
} job;
32
} job;
32
33
33
34
static job	*jhead = NULL, *jtail = NULL;
34
static job	*jhead = NULL, *jtail = NULL;
35
35
36
37
void
36
void
38
job_add(e, u)
37
job_add(entry *e, user *u) {
39
	register entry *e;
38
	job *j;
40
	register user *u;
41
{
42
	register job *j;
43
39
44
	/* if already on queue, keep going */
40
	/* if already on queue, keep going */
45
	for (j=jhead; j; j=j->next)
41
	for (j = jhead; j != NULL; j = j->next)
46
		if (j->e == e && j->u == u) { return; }
42
		if (j->e == e && j->u == u)
43
			return;
47
44
48
	/* build a job queue element */
45
	/* build a job queue element */
49
	if ((j = (job*)malloc(sizeof(job))) == NULL)
46
	if ((j = (job *)malloc(sizeof(job))) == NULL)
50
		return;
47
		return;
51
	j->next = (job*) NULL;
48
	j->next = NULL;
52
	j->e = e;
49
	j->e = e;
53
	j->u = u;
50
	j->u = u;
54
51
55
	/* add it to the tail */
52
	/* add it to the tail */
56
	if (!jhead) { jhead=j; }
53
	if (jhead == NULL)
57
	else { jtail->next=j; }
54
		jhead = j;
55
	else
56
		jtail->next = j;
58
	jtail = j;
57
	jtail = j;
59
}
58
}
60
59
61
62
int
60
int
63
job_runqueue()
61
job_runqueue(void) {
64
{
62
	job *j, *jn;
65
	register job	*j, *jn;
63
	int run = 0;
66
	register int	run = 0;
67
64
68
	for (j=jhead; j; j=jn) {
65
	for (j = jhead; j; j = jn) {
69
		do_command(j->e, j->u);
66
		do_command(j->e, j->u);
70
		jn = j->next;
67
		jn = j->next;
71
		free(j);
68
		free(j);
72
		run++;
69
		run++;
73
	}
70
	}
74
	jhead = jtail = NULL;
71
	jhead = jtail = NULL;
75
	return run;
72
	return (run);
76
}
73
}
(-)cron/cron/macros.h (+136 lines)
Line 0 Link Here
1
/*
2
 * $Id: macros.h,v 1.9 2004/01/23 18:56:43 vixie Exp $
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
	/* these are really immutable, and are
23
	 *   defined for symbolic convenience only
24
	 * TRUE, FALSE, and ERR must be distinct
25
	 * ERR must be < OK.
26
	 */
27
#define TRUE		1
28
#define FALSE		0
29
	/* system calls return this on success */
30
#define OK		0
31
	/*   or this on error */
32
#define ERR		(-1)
33
34
	/* turn this on to get '-x' code */
35
#ifndef DEBUGGING
36
#define DEBUGGING	FALSE
37
#endif
38
39
#define	INIT_PID	1	/* parent of orphans */
40
#define READ_PIPE	0	/* which end of a pipe pair do you read? */
41
#define WRITE_PIPE	1	/*   or write to? */
42
#define STDIN		0	/* what is stdin's file descriptor? */
43
#define STDOUT		1	/*   stdout's? */
44
#define STDERR		2	/*   stderr's? */
45
#define ERROR_EXIT	1	/* exit() with this will scare the shell */
46
#define	OK_EXIT		0	/* exit() with this is considered 'normal' */
47
#define	MAX_FNAME	100	/* max length of internally generated fn */
48
#define	MAX_COMMAND	1000	/* max length of internally generated cmd */
49
#define	MAX_ENVSTR	1000	/* max length of envvar=value\0 strings */
50
#define	MAX_TEMPSTR	100	/* obvious */
51
#define	MAX_UNAME	33	/* max length of username, should be overkill */
52
#define	ROOT_UID	0	/* don't change this, it really must be root */
53
#define	ROOT_USER	"root"	/* ditto */
54
55
				/* NOTE: these correspond to DebugFlagNames,
56
				 *	defined below.
57
				 */
58
#define	DEXT		0x0001	/* extend flag for other debug masks */
59
#define	DSCH		0x0002	/* scheduling debug mask */
60
#define	DPROC		0x0004	/* process control debug mask */
61
#define	DPARS		0x0008	/* parsing debug mask */
62
#define	DLOAD		0x0010	/* database loading debug mask */
63
#define	DMISC		0x0020	/* misc debug mask */
64
#define	DTEST		0x0040	/* test mode: don't execute any commands */
65
66
#define	PPC_NULL	((const char **)NULL)
67
68
#ifndef MAXHOSTNAMELEN
69
#define MAXHOSTNAMELEN 64
70
#endif
71
72
#define	Skip_Blanks(c, f) \
73
			while (c == '\t' || c == ' ') \
74
				c = get_char(f);
75
76
#define	Skip_Nonblanks(c, f) \
77
			while (c!='\t' && c!=' ' && c!='\n' && c != EOF) \
78
				c = get_char(f);
79
80
#if DEBUGGING
81
# define Debug(mask, message) \
82
			if ((DebugFlags & (mask)) != 0) \
83
				printf message;
84
#else /* !DEBUGGING */
85
# define Debug(mask, message) \
86
			;
87
#endif /* DEBUGGING */
88
89
#define	MkUpper(ch)	(islower(ch) ? toupper(ch) : ch)
90
#define	Set_LineNum(ln)	{Debug(DPARS|DEXT,("linenum=%d\n",ln)); \
91
			 LineNumber = ln; \
92
			}
93
94
#ifdef HAVE_TM_GMTOFF
95
#define	get_gmtoff(c, t)	((t)->tm_gmtoff)
96
#endif
97
98
#define	SECONDS_PER_MINUTE	60
99
#define	SECONDS_PER_HOUR	3600
100
101
#define FIRST_SECOND    0
102
#define LAST_SECOND     59
103
#define SECOND_COUNT (LAST_SECOND - FIRST_SECOND + 1)
104
105
#define	FIRST_MINUTE	0
106
#define	LAST_MINUTE	59
107
#define	MINUTE_COUNT	(LAST_MINUTE - FIRST_MINUTE + 1)
108
109
#define	FIRST_HOUR	0
110
#define	LAST_HOUR	23
111
#define	HOUR_COUNT	(LAST_HOUR - FIRST_HOUR + 1)
112
113
#define	FIRST_DOM	1
114
#define	LAST_DOM	31
115
#define	DOM_COUNT	(LAST_DOM - FIRST_DOM + 1)
116
117
#define	FIRST_MONTH	1
118
#define	LAST_MONTH	12
119
#define	MONTH_COUNT	(LAST_MONTH - FIRST_MONTH + 1)
120
121
/* note on DOW: 0 and 7 are both Sunday, for compatibility reasons. */
122
#define	FIRST_DOW	0
123
#define	LAST_DOW	7
124
#define	DOW_COUNT	(LAST_DOW - FIRST_DOW + 1)
125
126
/*
127
 * Because crontab/at files may be owned by their respective users we
128
 * take extreme care in opening them.  If the OS lacks the O_NOFOLLOW
129
 * we will just have to live without it.  In order for this to be an
130
 * issue an attacker would have to subvert group CRON_GROUP.
131
 */
132
#ifndef O_NOFOLLOW
133
#define O_NOFOLLOW	0
134
#endif
135
136
#define        RELOAD_CRON     0x2
(-)cron/cron/pathnames.h (-24 / +52 lines)
Lines 1-31 Link Here
1
/* Copyright 1993,1994 by Paul Vixie
1
/* Copyright 1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
/*
22
/*
19
 * $FreeBSD: head/usr.sbin/cron/cron/pathnames.h 50479 1999-08-28 01:35:59Z peter $
23
 * $Id: pathnames.h,v 1.9 2004/01/23 18:56:43 vixie Exp $
20
 */
24
 */
21
25
26
#ifndef _PATHNAMES_H_
27
#define _PATHNAMES_H_
28
22
#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX)
29
#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX)
23
# include <paths.h>
30
# include <paths.h>
24
#endif /*BSD*/
31
#endif /*BSD*/
25
32
26
#ifndef CRONDIR
33
#ifndef CRONDIR
27
			/* CRONDIR is where crond(8) and crontab(1) both chdir
34
			/* CRONDIR is where cron(8) and crontab(1) both chdir
28
			 * to; SPOOL_DIR, ALLOW_FILE, DENY_FILE, and LOG_FILE
35
			 * to; SPOOL_DIR, CRON_ALLOW, CRON_DENY, and LOG_FILE
29
			 * are all relative to this directory.
36
			 * are all relative to this directory.
30
			 */
37
			 */
31
#define CRONDIR		"/var/cron"
38
#define CRONDIR		"/var/cron"
Lines 34-57 Link Here
34
			/* SPOOLDIR is where the crontabs live.
41
			/* SPOOLDIR is where the crontabs live.
35
			 * This directory will have its modtime updated
42
			 * This directory will have its modtime updated
36
			 * whenever crontab(1) changes a crontab; this is
43
			 * whenever crontab(1) changes a crontab; this is
37
			 * the signal for crond(8) to look at each individual
44
			 * the signal for cron(8) to look at each individual
38
			 * crontab file and reload those whose modtimes are
45
			 * crontab file and reload those whose modtimes are
39
			 * newer than they were last time around (or which
46
			 * newer than they were last time around (or which
40
			 * didn't exist last time around...)
47
			 * didn't exist last time around...)
41
			 */
48
			 */
42
#define SPOOL_DIR	"tabs"
49
#define SPOOL_DIR	"tabs"
43
50
44
			/* undefining these turns off their features.  note
51
			/* cron allow/deny file.  At least cron.deny must
45
			 * that ALLOW_FILE and DENY_FILE must both be defined
52
			 * exist for ordinary users to run crontab.
46
			 * in order to enable the allow/deny code.  If neither
53
			 */
47
			 * LOG_FILE or SYSLOG is defined, we don't log.  If
54
#define	ALLOW_FILE	"allow"
48
			 * both are defined, we log both ways.
55
#define	DENY_FILE	"deny"
49
			 */
56
50
#define	ALLOW_FILE	"allow"		/*-*/
57
			/* undefining this turns off logging to a file.  If
51
#define DENY_FILE	"deny"		/*-*/
58
			 * neither LOG_FILE or SYSLOG is defined, we don't log.
52
/*#define LOG_FILE        "log"*/           /*-*/
59
			 * If both are defined, we log both ways.  Note that if
60
			 * LOG_CRON is defined by <syslog.h>, LOG_FILE will not
61
			 * be used.
62
			 */
63
#define LOG_FILE	"log"
53
64
54
			/* where should the daemon stick its PID?
65
			/* where should the daemon stick its PID?
66
			 * PIDDIR must end in '/'.
55
			 */
67
			 */
56
#ifdef _PATH_VARRUN
68
#ifdef _PATH_VARRUN
57
# define PIDDIR	_PATH_VARRUN
69
# define PIDDIR	_PATH_VARRUN
Lines 59-64 Link Here
59
# define PIDDIR "/etc/"
71
# define PIDDIR "/etc/"
60
#endif
72
#endif
61
#define PIDFILE		"%scron.pid"
73
#define PIDFILE		"%scron.pid"
74
#define SOCKFILE        ".sock"
75
#define _PATH_CRON_PID	PIDDIR PIDFILE
62
76
63
			/* 4.3BSD-style crontab */
77
			/* 4.3BSD-style crontab */
64
#define SYSCRONTAB	"/etc/crontab"
78
#define SYSCRONTAB	"/etc/crontab"
Lines 72-77 Link Here
72
# define EDITOR "/usr/ucb/vi"
86
# define EDITOR "/usr/ucb/vi"
73
#endif
87
#endif
74
88
89
#ifndef _PATH_SENDMAIL
90
# define _PATH_SENDMAIL "/usr/lib/sendmail"
91
#endif
92
75
#ifndef _PATH_BSHELL
93
#ifndef _PATH_BSHELL
76
# define _PATH_BSHELL "/bin/sh"
94
# define _PATH_BSHELL "/bin/sh"
77
#endif
95
#endif
Lines 79-81 Link Here
79
#ifndef _PATH_DEFPATH
97
#ifndef _PATH_DEFPATH
80
# define _PATH_DEFPATH "/usr/bin:/bin"
98
# define _PATH_DEFPATH "/usr/bin:/bin"
81
#endif
99
#endif
100
101
#ifndef _PATH_TMP
102
# define _PATH_TMP "/tmp"
103
#endif
104
105
#ifndef _PATH_DEVNULL
106
# define _PATH_DEVNULL "/dev/null"
107
#endif
108
109
#endif /* _PATHNAMES_H_ */
(-)cron/cron/popen.c (-1 / +1 lines)
Lines 28-34 Link Here
28
static char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 2/14/89";
28
static char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 2/14/89";
29
#endif
29
#endif
30
static const char rcsid[] =
30
static const char rcsid[] =
31
  "$FreeBSD: head/usr.sbin/cron/cron/popen.c 159527 2006-06-11 21:13:49Z maxim $";
31
  "$FreeBSD: releng/10.0/usr.sbin/cron/cron/popen.c 159527 2006-06-11 21:13:49Z maxim $";
32
#endif /* not lint */
32
#endif /* not lint */
33
33
34
#include "cron.h"
34
#include "cron.h"
(-)cron/cron/structs.h (+68 lines)
Line 0 Link Here
1
/*
2
 * $Id: structs.h,v 1.7 2004/01/23 18:56:43 vixie Exp $
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
typedef	struct _entry {
23
	struct _entry	*next;
24
	uid_t	uid;
25
	gid_t	gid;
26
#ifdef LOGIN_CAP
27
	char	*class;
28
#endif
29
	char		**envp;
30
	char		*cmd;
31
	bitstr_t	bit_decl(second, SECOND_COUNT);
32
	bitstr_t	bit_decl(minute, MINUTE_COUNT);
33
	bitstr_t	bit_decl(hour,   HOUR_COUNT);
34
	bitstr_t	bit_decl(dom,    DOM_COUNT);
35
	bitstr_t	bit_decl(month,  MONTH_COUNT);
36
	bitstr_t	bit_decl(dow,    DOW_COUNT);
37
	int		flags;
38
#define	MIN_STAR	0x01
39
#define	HR_STAR		0x02
40
#define	DOM_STAR	0x04
41
#define	DOW_STAR	0x08
42
#define	WHEN_REBOOT	0x10
43
#define	DONT_LOG	0x20
44
	time_t		lastrun;
45
} entry;
46
47
			/* the crontab database will be a list of the
48
			 * following structure, one element per user
49
			 * plus one for the system.
50
			 *
51
			 * These are the crontabs.
52
			 */
53
54
typedef	struct _user {
55
	struct _user	*next, *prev;	/* links */
56
	char		*name;
57
	time_t		mtime;		/* last modtime of crontab */
58
	entry		*crontab;	/* this person's crontab */
59
} user;
60
61
typedef	struct _cron_db {
62
	user		*head, *tail;	/* links */
63
	time_t		mtime;		/* last modtime on spooldir */
64
} cron_db;
65
				/* in the C tradition, we only create
66
				 * variables for the main program, just
67
				 * extern them elsewhere.
68
				 */
(-)cron/cron/user.c (-53 / +46 lines)
Lines 1-38 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
#if !defined(lint) && !defined(LINT)
22
//#if !defined(lint) && !defined(LINT)
19
static const char rcsid[] =
23
//static char rcsid[] = "$Id: user.c,v 1.5 2004/01/23 18:56:43 vixie Exp $";
20
  "$FreeBSD: head/usr.sbin/cron/cron/user.c 50479 1999-08-28 01:35:59Z peter $";
24
//#endif
21
#endif
22
25
23
/* vix 26jan87 [log is in RCS file]
26
/* vix 26jan87 [log is in RCS file]
24
 */
27
 */
25
28
26
27
#include "cron.h"
29
#include "cron.h"
28
30
29
static char *User_name;
31
static char *User_name;
30
31
void
32
void
32
free_user(u)
33
free_user(user *u) {
33
	user	*u;
34
	entry *e, *ne;
34
{
35
	entry	*e, *ne;
36
35
37
	free(u->name);
36
	free(u->name);
38
	for (e = u->crontab;  e != NULL;  e = ne) {
37
	for (e = u->crontab;  e != NULL;  e = ne) {
Lines 43-98 Link Here
43
}
42
}
44
43
45
static void
44
static void
46
log_error(msg)
45
log_error(char *msg) {
47
	char	*msg;
48
{
49
	log_it(User_name, getpid(), "PARSE", msg);
46
	log_it(User_name, getpid(), "PARSE", msg);
50
}
47
}
51
48
52
user *
49
user *
53
load_user(crontab_fd, pw, name)
50
load_user(int crontab_fd, struct passwd	*pw, const char *name) {
54
	int		crontab_fd;
51
	char envstr[MAX_ENVSTR];
55
	struct passwd	*pw;		/* NULL implies syscrontab */
52
	FILE *file;
56
	char		*name;
53
	user *u;
57
{
54
	entry *e;
58
	char	envstr[MAX_ENVSTR];
55
	int status, save_errno;
59
	FILE	*file;
56
	char **envp, **tenvp;
60
	user	*u;
61
	entry	*e;
62
	int	status;
63
	char	**envp, **tenvp;
64
57
65
	if (!(file = fdopen(crontab_fd, "r"))) {
58
	if (!(file = fdopen(crontab_fd, "r"))) {
66
		warn("fdopen on crontab_fd in load_user");
59
		perror("fdopen on crontab_fd in load_user");
67
		return NULL;
60
		return (NULL);
68
	}
61
	}
69
62
70
	Debug(DPARS, ("load_user()\n"))
63
	Debug(DPARS, ("load_user()\n"))
71
64
72
	/* file is open.  build user entry, then read the crontab file.
65
	/* file is open.  build user entry, then read the crontab file.
73
	 */
66
	 */
74
	if ((u = (user *) malloc(sizeof(user))) == NULL) {
67
	if ((u = (user *) malloc(sizeof(user))) == NULL)
75
		errno = ENOMEM;
68
		return (NULL);
76
		return NULL;
77
	}
78
	if ((u->name = strdup(name)) == NULL) {
69
	if ((u->name = strdup(name)) == NULL) {
70
		save_errno = errno;
79
		free(u);
71
		free(u);
80
		errno = ENOMEM;
72
		errno = save_errno;
81
		return NULL;
73
		return (NULL);
82
	}
74
	}
83
	u->crontab = NULL;
75
	u->crontab = NULL;
84
76
85
	/* 
77
	/* init environment.  this will be copied/augmented for each entry.
86
	 * init environment.  this will be copied/augmented for each entry.
87
	 */
78
	 */
88
	if ((envp = env_init()) == NULL) {
79
	if ((envp = env_init()) == NULL) {
80
		save_errno = errno;
89
		free(u->name);
81
		free(u->name);
90
		free(u);
82
		free(u);
91
		return NULL;
83
		errno = save_errno;
84
		return (NULL);
92
	}
85
	}
93
86
94
	/*
87
	/* load the crontab
95
	 * load the crontab
96
	 */
88
	 */
97
	while ((status = load_env(envstr, file)) >= OK) {
89
	while ((status = load_env(envstr, file)) >= OK) {
98
		switch (status) {
90
		switch (status) {
Lines 101-107 Link Here
101
			u = NULL;
93
			u = NULL;
102
			goto done;
94
			goto done;
103
		case FALSE:
95
		case FALSE:
104
			User_name = u->name;    /* for log_error */
96
			User_name = u->name;
105
			e = load_entry(file, log_error, pw, envp);
97
			e = load_entry(file, log_error, pw, envp);
106
			if (e) {
98
			if (e) {
107
				e->next = u->crontab;
99
				e->next = u->crontab;
Lines 109-121 Link Here
109
			}
101
			}
110
			break;
102
			break;
111
		case TRUE:
103
		case TRUE:
112
			if ((tenvp = env_set(envp, envstr))) {
104
			if ((tenvp = env_set(envp, envstr)) == NULL) {
113
				envp = tenvp;
105
				save_errno = errno;
114
			} else {
115
				free_user(u);
106
				free_user(u);
116
				u = NULL;
107
				u = NULL;
108
				errno = save_errno;
117
				goto done;
109
				goto done;
118
			}
110
			}
111
			envp = tenvp;
119
			break;
112
			break;
120
		}
113
		}
121
	}
114
	}
Lines 124-128 Link Here
124
	env_free(envp);
117
	env_free(envp);
125
	fclose(file);
118
	fclose(file);
126
	Debug(DPARS, ("...load_user() done\n"))
119
	Debug(DPARS, ("...load_user() done\n"))
127
	return u;
120
	return (u);
128
}
121
}
(-)cron/crontab/Makefile (-4 / +3 lines)
Lines 1-11 Link Here
1
# $FreeBSD: head/usr.sbin/cron/crontab/Makefile 267233 2014-06-08 17:29:31Z bdrewery $
1
# $FreeBSD: releng/10.0/usr.sbin/cron/crontab/Makefile 185040 2008-11-18 00:12:15Z matteo $
2
2
3
BINDIR=	/usr/bin
3
BINDIR=	/usr/bin
4
4
5
PROG=	crontab
5
PROG=	crontab
6
MAN=	crontab.1 crontab.5
6
MAN=	crontab.1 crontab.5
7
BINOWN=	root
7
BINOWN=	root
8
BINMODE=4555
8
BINGRP= crontab
9
BINMODE=2555
9
PRECIOUSPROG=
10
PRECIOUSPROG=
10
11
11
WARNS?=	3
12
WARNS?=	3
Lines 15-20 Link Here
15
DPADD=	${LIBCRON} ${LIBMD} ${LIBUTIL}
16
DPADD=	${LIBCRON} ${LIBMD} ${LIBUTIL}
16
LDADD=	${LIBCRON} -lmd -lutil
17
LDADD=	${LIBCRON} -lmd -lutil
17
18
18
NO_PIE=	yes
19
20
.include <bsd.prog.mk>
19
.include <bsd.prog.mk>
(-)cron/crontab/crontab.1 (-2 / +2 lines)
Lines 15-21 Link Here
15
.\" * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
.\" * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
16
.\" */
16
.\" */
17
.\"
17
.\"
18
.\" $FreeBSD: head/usr.sbin/cron/crontab/crontab.1 267668 2014-06-20 09:57:27Z bapt $
18
.\" $FreeBSD: releng/10.0/usr.sbin/cron/crontab/crontab.1 208054 2010-05-14 01:25:30Z brueffer $
19
.\"
19
.\"
20
.Dd May 13, 2010
20
.Dd May 13, 2010
21
.Dt CRONTAB 1
21
.Dt CRONTAB 1
Lines 142-145 Link Here
142
differs from previous versions of Vixie Cron, as well as from the classic
142
differs from previous versions of Vixie Cron, as well as from the classic
143
SVR3 syntax.
143
SVR3 syntax.
144
.Sh AUTHORS
144
.Sh AUTHORS
145
.An Paul Vixie Aq Mt paul@vix.com
145
.An Paul Vixie Aq paul@vix.com
(-)cron/crontab/crontab.5 (-2 / +2 lines)
Lines 15-21 Link Here
15
.\" * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
.\" * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
16
.\" */
16
.\" */
17
.\"
17
.\"
18
.\" $FreeBSD: head/usr.sbin/cron/crontab/crontab.5 267668 2014-06-20 09:57:27Z bapt $
18
.\" $FreeBSD: releng/10.0/usr.sbin/cron/crontab/crontab.5 242101 2012-10-25 22:54:29Z sobomax $
19
.\"
19
.\"
20
.Dd April 28, 2012
20
.Dd April 28, 2012
21
.Dt CRONTAB 5
21
.Dt CRONTAB 5
Lines 295-301 Link Here
295
commands that can appear in place of the first five fields
295
commands that can appear in place of the first five fields
296
are extensions.
296
are extensions.
297
.Sh AUTHORS
297
.Sh AUTHORS
298
.An Paul Vixie Aq Mt paul@vix.com
298
.An Paul Vixie Aq paul@vix.com
299
.Sh BUGS
299
.Sh BUGS
300
If you are in one of the 70-odd countries that observe Daylight
300
If you are in one of the 70-odd countries that observe Daylight
301
Savings Time, jobs scheduled during the rollback or advance may be
301
Savings Time, jobs scheduled during the rollback or advance may be
(-)cron/crontab/crontab.c (-338 / +387 lines)
Lines 1-24 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * From Id: crontab.c,v 2.13 1994/01/17 03:20:37 vixie Exp
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
20
 */
18
21
19
#if !defined(lint) && !defined(LINT)
22
#if !defined(lint) && !defined(LINT)
20
static const char rcsid[] =
23
static char rcsid[] = "$Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $";
21
  "$FreeBSD: head/usr.sbin/cron/crontab/crontab.c 239991 2012-09-01 14:45:15Z ed $";
22
#endif
24
#endif
23
25
24
/* crontab - install and manage per-user crontab files
26
/* crontab - install and manage per-user crontab files
Lines 29-64 Link Here
29
#define	MAIN_PROGRAM
31
#define	MAIN_PROGRAM
30
32
31
#include "cron.h"
33
#include "cron.h"
32
#include <errno.h>
33
#include <fcntl.h>
34
#include <md5.h>
35
#include <paths.h>
36
#include <sys/file.h>
37
#include <sys/stat.h>
38
#ifdef USE_UTIMES
39
# include <sys/time.h>
40
#else
41
# include <time.h>
42
# include <utime.h>
43
#endif
44
#if defined(POSIX)
45
# include <locale.h>
46
#endif
47
48
#define MD5_SIZE 33
49
#define NHEADER_LINES 3
34
#define NHEADER_LINES 3
50
35
51
52
enum opt_t	{ opt_unknown, opt_list, opt_delete, opt_edit, opt_replace };
36
enum opt_t	{ opt_unknown, opt_list, opt_delete, opt_edit, opt_replace };
53
37
54
#if DEBUGGING
38
#if DEBUGGING
55
static char	*Options[] = { "???", "list", "delete", "edit", "replace" };
39
static char	*Options[] = { "???", "list", "delete", "edit", "replace" };
40
static char	*getoptargs = "u:lerx:";
41
#else
42
static char	*getoptargs = "u:ler";
56
#endif
43
#endif
57
44
58
59
static	PID_T		Pid;
45
static	PID_T		Pid;
60
static	char		User[MAX_UNAME], RealUser[MAX_UNAME];
46
static	char		User[MAX_UNAME], RealUser[MAX_UNAME];
61
static	char		Filename[MAX_FNAME];
47
static	char		Filename[MAX_FNAME], TempFilename[MAX_FNAME];
62
static	FILE		*NewCrontab;
48
static	FILE		*NewCrontab;
63
static	int		CheckErrorCount;
49
static	int		CheckErrorCount;
64
static	enum opt_t	Option;
50
static	enum opt_t	Option;
Lines 66-160 Link Here
66
static	void		list_cmd(void),
52
static	void		list_cmd(void),
67
			delete_cmd(void),
53
			delete_cmd(void),
68
			edit_cmd(void),
54
			edit_cmd(void),
69
			poke_daemon(void),
55
			poke_daemon(unsigned char),
70
			check_error(char *),
56
			check_error(const char *),
71
			parse_args(int c, char *v[]);
57
			parse_args(int c, char *v[]),
58
			die(int);
72
static	int		replace_cmd(void);
59
static	int		replace_cmd(void);
73
60
74
75
static void
61
static void
76
usage(char *msg)
62
usage(const char *msg) {
77
{
63
	fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg);
78
	fprintf(stderr, "crontab: usage error: %s\n", msg);
64
	fprintf(stderr, "usage:\t%s [-u user] file\n", ProgramName);
79
	fprintf(stderr, "%s\n%s\n",
65
	fprintf(stderr, "\t%s [-u user] [ -e | -l | -r ]\n", ProgramName);
80
		"usage: crontab [-u user] file",
66
	fprintf(stderr, "\t\t(default operation is replace, per 1003.2)\n");
81
		"       crontab [-u user] { -e | -l | -r }");
67
	fprintf(stderr, "\t-e\t(edit user's crontab)\n");
68
	fprintf(stderr, "\t-l\t(list user's crontab)\n");
69
	fprintf(stderr, "\t-r\t(delete user's crontab)\n");
82
	exit(ERROR_EXIT);
70
	exit(ERROR_EXIT);
83
}
71
}
84
72
85
86
int
73
int
87
main(int argc, char *argv[])
74
main(int argc, char *argv[]) {
88
{
75
	int exitstatus;
89
	int	exitstatus;
90
76
91
	Pid = getpid();
77
	Pid = getpid();
92
	ProgramName = argv[0];
78
	ProgramName = argv[0];
93
79
94
#if defined(POSIX)
95
	setlocale(LC_ALL, "");
80
	setlocale(LC_ALL, "");
96
#endif
97
81
98
#if defined(BSD)
82
#if defined(BSD)
99
	setlinebuf(stderr);
83
	setlinebuf(stderr);
100
#endif
84
#endif
101
	parse_args(argc, argv);		/* sets many globals, opens a file */
85
	parse_args(argc, argv);		/* sets many globals, opens a file */
102
	set_cron_uid();
103
	set_cron_cwd();
86
	set_cron_cwd();
104
	if (!allowed(User)) {
87
	if (!allowed(RealUser)) {
105
		warnx("you (%s) are not allowed to use this program", User);
88
		fprintf(stderr,
89
			"You (%s) are not allowed to use this program (%s)\n",
90
			User, ProgramName);
91
		fprintf(stderr, "See crontab(1) for more information\n");
106
		log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
92
		log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
107
		exit(ERROR_EXIT);
93
		exit(ERROR_EXIT);
108
	}
94
	}
109
	exitstatus = OK_EXIT;
95
	exitstatus = OK_EXIT;
110
	switch (Option) {
96
	switch (Option) {
111
	case opt_list:		list_cmd();
112
				break;
113
	case opt_delete:	delete_cmd();
114
				break;
115
	case opt_edit:		edit_cmd();
116
				break;
117
	case opt_replace:	if (replace_cmd() < 0)
118
					exitstatus = ERROR_EXIT;
119
				break;
120
	case opt_unknown:
97
	case opt_unknown:
121
				break;
98
		exitstatus = ERROR_EXIT;
99
		break;
100
	case opt_list:
101
		list_cmd();
102
		break;
103
	case opt_delete:
104
		delete_cmd();
105
		break;
106
	case opt_edit:
107
		edit_cmd();
108
		break;
109
	case opt_replace:
110
		if (replace_cmd() < 0)
111
			exitstatus = ERROR_EXIT;
112
		break;
113
	default:
114
		abort();
122
	}
115
	}
123
	exit(exitstatus);
116
	exit(exitstatus);
124
	/*NOTREACHED*/
117
	/*NOTREACHED*/
125
}
118
}
126
119
127
128
static void
120
static void
129
parse_args(argc, argv)
121
parse_args(int argc, char *argv[]) {
130
	int	argc;
122
	int argch;
131
	char	*argv[];
123
132
{
124
	if (!(pw = getpwuid(getuid()))) 
133
	int		argch;
125
		errx(ERROR_EXIT, "%s: your UID isn't in the password file.", 
134
	char		resolved_path[PATH_MAX];
126
				ProgramName);
135
127
	if (strlen(pw->pw_name) >= sizeof User) 
136
	if (!(pw = getpwuid(getuid())))
128
		errx(ERROR_EXIT, "username too long\n");
137
		errx(ERROR_EXIT, "your UID isn't in the passwd file, bailing out");
129
138
	bzero(pw->pw_passwd, strlen(pw->pw_passwd));
130
	strlcpy(User, pw->pw_name, sizeof(User));
139
	(void) strncpy(User, pw->pw_name, (sizeof User)-1);
131
	strlcpy(RealUser, User, sizeof(RealUser));
140
	User[(sizeof User)-1] = '\0';
141
	strcpy(RealUser, User);
142
	Filename[0] = '\0';
132
	Filename[0] = '\0';
143
	Option = opt_unknown;
133
	Option = opt_unknown;
144
	while ((argch = getopt(argc, argv, "u:lerx:")) != -1) {
134
	while (-1 != (argch = getopt(argc, argv, getoptargs))) {
145
		switch (argch) {
135
		switch (argch) {
136
#if DEBUGGING
146
		case 'x':
137
		case 'x':
147
			if (!set_debug_flags(optarg))
138
			if (!set_debug_flags(optarg))
148
				usage("bad debug option");
139
				usage("bad debug option");
149
			break;
140
			break;
141
#endif
150
		case 'u':
142
		case 'u':
151
			if (getuid() != ROOT_UID)
143
			if (MY_UID(pw) != ROOT_UID) 
152
				errx(ERROR_EXIT, "must be privileged to use -u");
144
				errx(ERROR_EXIT, "must be privileged to use -u");
153
			if (!(pw = getpwnam(optarg)))
145
154
				errx(ERROR_EXIT, "user `%s' unknown", optarg);
146
			if (!(pw = getpwnam(optarg))) 
155
			bzero(pw->pw_passwd, strlen(pw->pw_passwd));
147
				errx(ERROR_EXIT, "%s: user %s unknown", ProgramName, optarg);
156
			(void) strncpy(User, pw->pw_name, (sizeof User)-1);
148
157
			User[(sizeof User)-1] = '\0';
149
			if (strlen(optarg) >= sizeof User)
150
				usage("username too long");
151
			(void) strlcpy(User, optarg, sizeof(User));
158
			break;
152
			break;
159
		case 'l':
153
		case 'l':
160
			if (Option != opt_unknown)
154
			if (Option != opt_unknown)
Lines 179-388 Link Here
179
	endpwent();
173
	endpwent();
180
174
181
	if (Option != opt_unknown) {
175
	if (Option != opt_unknown) {
182
		if (argv[optind] != NULL) {
176
		if (argv[optind] != NULL)
183
			usage("no arguments permitted after this option");
177
			usage("no arguments permitted after this option");
184
		}
185
	} else {
178
	} else {
186
		if (argv[optind] != NULL) {
179
		if (argv[optind] != NULL) {
187
			Option = opt_replace;
180
			Option = opt_replace;
188
			(void) strncpy (Filename, argv[optind], (sizeof Filename)-1);
181
			if (strlen(argv[optind]) >= sizeof Filename)
189
			Filename[(sizeof Filename)-1] = '\0';
182
				usage("filename too long");
190
183
			(void) strlcpy (Filename, argv[optind], sizeof(Filename));
191
		} else {
184
		} else
192
			usage("file name must be specified for replace");
185
			usage("file name must be specified for replace");
193
		}
194
	}
186
	}
195
187
196
	if (Option == opt_replace) {
188
	if (Option == opt_replace) {
197
		/* relinquish the setuid status of the binary during
198
		 * the open, lest nonroot users read files they should
199
		 * not be able to read.  we can't use access() here
200
		 * since there's a race condition.  thanks go out to
201
		 * Arnt Gulbrandsen <agulbra@pvv.unit.no> for spotting
202
		 * the race.
203
		 */
204
205
		if (swap_uids() < OK)
206
			err(ERROR_EXIT, "swapping uids");
207
208
		/* we have to open the file here because we're going to
189
		/* we have to open the file here because we're going to
209
		 * chdir(2) into /var/cron before we get around to
190
		 * chdir(2) into /var/cron before we get around to
210
		 * reading the file.
191
		 * reading the file.
211
		 */
192
		 */
212
		if (!strcmp(Filename, "-")) {
193
		if (!strcmp(Filename, "-"))
213
			NewCrontab = stdin;
194
			NewCrontab = stdin;
214
		} else if (realpath(Filename, resolved_path) != NULL &&
195
		else {
215
		    !strcmp(resolved_path, SYSCRONTAB)) {
196
			/* relinquish the setuid status of the binary during
216
			err(ERROR_EXIT, SYSCRONTAB " must be edited manually");
197
			 * the open, lest nonroot users read files they should
217
		} else {
198
			 * not be able to read.  we can't use access() here
218
			if (!(NewCrontab = fopen(Filename, "r")))
199
			 * since there's a race condition.  thanks go out to
219
				err(ERROR_EXIT, "%s", Filename);
200
			 * Arnt Gulbrandsen <agulbra@pvv.unit.no> for spotting
220
		}
201
			 * the race.
221
		if (swap_uids_back() < OK)
202
			 */
222
			err(ERROR_EXIT, "swapping uids back");
223
	}
224
203
225
	Debug(DMISC, ("user=%s, file=%s, option=%s\n",
204
			if (swap_uids() < OK) 
226
		      User, Filename, Options[(int)Option]))
205
				errx(ERROR_EXIT, "swapping uids");
227
}
228
206
229
static void
207
			if (!(NewCrontab = fopen(Filename, "r"))) 
230
copy_file(FILE *in, FILE *out) {
208
				errx(ERROR_EXIT, "%s", Filename);
231
	int	x, ch;
232
209
233
	Set_LineNum(1)
210
			if (swap_uids_back() < OK) 
234
	/* ignore the top few comments since we probably put them there.
211
				errx(ERROR_EXIT, "swapping uids back");
235
	 */
236
	for (x = 0;  x < NHEADER_LINES;  x++) {
237
		ch = get_char(in);
238
		if (EOF == ch)
239
			break;
240
		if ('#' != ch) {
241
			putc(ch, out);
242
			break;
243
		}
212
		}
244
		while (EOF != (ch = get_char(in)))
245
			if (ch == '\n')
246
				break;
247
		if (EOF == ch)
248
			break;
249
	}
213
	}
250
214
251
	/* copy the rest of the crontab (if any) to the output file.
215
	Debug(DMISC, ("user=%s, file=%s, option=%s\n",
252
	 */
216
		      User, Filename, Options[(int)Option]))
253
	if (EOF != ch)
254
		while (EOF != (ch = get_char(in)))
255
			putc(ch, out);
256
}
217
}
257
218
258
static void
219
static void
259
list_cmd() {
220
list_cmd(void) {
260
	char	n[MAX_FNAME];
221
	char n[MAX_FNAME];
261
	FILE	*f;
222
	FILE *f;
223
	int ch;
262
224
263
	log_it(RealUser, Pid, "LIST", User);
225
	log_it(RealUser, Pid, "LIST", User);
264
	(void) snprintf(n, sizeof(n), CRON_TAB(User));
226
	if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) 
227
		errx(ERROR_EXIT, "path too long");
228
265
	if (!(f = fopen(n, "r"))) {
229
	if (!(f = fopen(n, "r"))) {
266
		if (errno == ENOENT)
230
		if (errno == ENOENT)
267
			errx(ERROR_EXIT, "no crontab for %s", User);
231
			fprintf(stderr, "no crontab for %s\n", User);
268
		else
232
		else
269
			err(ERROR_EXIT, "%s", n);
233
			perror(n);
234
		exit(ERROR_EXIT);
270
	}
235
	}
271
236
272
	/* file is open. copy to stdout, close.
237
	/* file is open. copy to stdout, close.
273
	 */
238
	 */
274
	copy_file(f, stdout);
239
	Set_LineNum(1)
240
	while (EOF != (ch = get_char(f)))
241
		putchar(ch);
275
	fclose(f);
242
	fclose(f);
276
}
243
}
277
244
278
279
static void
245
static void
280
delete_cmd() {
246
delete_cmd(void) {
281
	char	n[MAX_FNAME];
247
	char n[MAX_FNAME];
282
	int ch, first;
283
284
	if (isatty(STDIN_FILENO)) {
285
		(void)fprintf(stderr, "remove crontab for %s? ", User);
286
		first = ch = getchar();
287
		while (ch != '\n' && ch != EOF)
288
			ch = getchar();
289
		if (first != 'y' && first != 'Y')
290
			return;
291
	}
292
248
293
	log_it(RealUser, Pid, "DELETE", User);
249
	log_it(RealUser, Pid, "DELETE", User);
294
	(void) snprintf(n, sizeof(n), CRON_TAB(User));
250
	if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) 
295
	if (unlink(n)) {
251
		errx(ERROR_EXIT, "path to long");
252
253
	if (unlink(n) != 0) {
296
		if (errno == ENOENT)
254
		if (errno == ENOENT)
297
			errx(ERROR_EXIT, "no crontab for %s", User);
255
			fprintf(stderr, "no crontab for %s\n", User);
298
		else
256
		else
299
			err(ERROR_EXIT, "%s", n);
257
			perror(n);
258
		exit(ERROR_EXIT);
300
	}
259
	}
301
	poke_daemon();
260
	poke_daemon(RELOAD_CRON);
302
}
261
}
303
262
304
305
static void
263
static void
306
check_error(msg)
264
check_error(const char *msg) {
307
	char	*msg;
308
{
309
	CheckErrorCount++;
265
	CheckErrorCount++;
310
	fprintf(stderr, "\"%s\":%d: %s\n", Filename, LineNumber-1, msg);
266
	fprintf(stderr, "\"%s\":%d: %s\n", Filename, LineNumber-1, msg);
311
}
267
}
312
268
313
314
static void
269
static void
315
edit_cmd() {
270
edit_cmd(void) {
316
	char		n[MAX_FNAME], q[MAX_TEMPSTR], *editor;
271
	char n[MAX_FNAME], q[MAX_TEMPSTR], *editor;
317
	FILE		*f;
272
	FILE *f;
318
	int		t;
273
	int ch, t, x;
319
	struct stat	statbuf, fsbuf;
274
	struct stat statbuf, fsbuf;
320
	WAIT_T		waiter;
275
	struct utimbuf utimebuf;
321
	PID_T		pid, xpid;
276
	WAIT_T waiter;
322
	mode_t		um;
277
	PID_T pid, xpid;
323
	int		syntax_error = 0;
324
	char		orig_md5[MD5_SIZE];
325
	char		new_md5[MD5_SIZE];
326
278
327
	log_it(RealUser, Pid, "BEGIN EDIT", User);
279
	log_it(RealUser, Pid, "BEGIN EDIT", User);
328
	(void) snprintf(n, sizeof(n), CRON_TAB(User));
280
	if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) 
281
		errx(ERROR_EXIT, "path too long");
282
329
	if (!(f = fopen(n, "r"))) {
283
	if (!(f = fopen(n, "r"))) {
330
		if (errno != ENOENT)
284
		if (errno != ENOENT) {
331
			err(ERROR_EXIT, "%s", n);
285
			perror(n);
332
		warnx("no crontab for %s - using an empty one", User);
286
			exit(ERROR_EXIT);
333
		if (!(f = fopen(_PATH_DEVNULL, "r")))
287
		}
334
			err(ERROR_EXIT, _PATH_DEVNULL);
288
		fprintf(stderr, "no crontab for %s - using an empty one\n",
289
			User);
290
		if (!(f = fopen(_PATH_DEVNULL, "r"))) {
291
			perror(_PATH_DEVNULL);
292
			exit(ERROR_EXIT);
293
		}
335
	}
294
	}
336
295
337
	um = umask(077);
296
	if (fstat(fileno(f), &statbuf) < 0) {
338
	(void) snprintf(Filename, sizeof(Filename), "/tmp/crontab.XXXXXXXXXX");
297
		perror("fstat");
339
	if ((t = mkstemp(Filename)) == -1) {
298
		goto fatal;
340
		warn("%s", Filename);
299
	}
341
		(void) umask(um);
300
	utimebuf.actime = statbuf.st_atime;
301
	utimebuf.modtime = statbuf.st_mtime;
302
303
	/* Turn off signals. */
304
	(void)signal(SIGHUP, SIG_IGN);
305
	(void)signal(SIGINT, SIG_IGN);
306
	(void)signal(SIGQUIT, SIG_IGN);
307
308
	if (!glue_strings(Filename, sizeof Filename, _PATH_TMP,
309
	    "crontab.XXXXXXXXXX", '/')) {
310
		fprintf(stderr, "path too long\n");
311
		goto fatal;
312
	}
313
	if (-1 == (t = mkstemp(Filename))) {
314
		perror(Filename);
342
		goto fatal;
315
		goto fatal;
343
	}
316
	}
344
	(void) umask(um);
345
#ifdef HAS_FCHOWN
317
#ifdef HAS_FCHOWN
346
	if (fchown(t, getuid(), getgid()) < 0) {
318
	if (fchown(t, MY_UID(pw), MY_GID(pw)) < 0) {
319
		perror("fchown");
320
		goto fatal;
321
	}
347
#else
322
#else
348
	if (chown(Filename, getuid(), getgid()) < 0) {
323
	if (chown(Filename, MY_UID(pw), -1) < 0) {
349
#endif
324
		perror("chown");
350
		warn("fchown");
351
		goto fatal;
325
		goto fatal;
352
	}
326
	}
327
#endif
353
	if (!(NewCrontab = fdopen(t, "r+"))) {
328
	if (!(NewCrontab = fdopen(t, "r+"))) {
354
		warn("fdopen");
329
		warn("fdopen");
355
		goto fatal;
330
		goto fatal;
356
	}
331
	}
357
332
358
	copy_file(f, NewCrontab);
333
	Set_LineNum(1)
334
335
	/* ignore the top few comments since we probably put them there.
336
	 */
337
	x = 0;
338
	while (EOF != (ch = get_char(f))) {
339
		if ('#' != ch) {
340
			putc(ch, NewCrontab);
341
			break;
342
		}
343
		while (EOF != (ch = get_char(f)))
344
			if (ch == '\n')
345
				break;
346
		if (++x >= NHEADER_LINES)
347
			break;
348
	}
349
350
	/* copy the rest of the crontab (if any) to the temp file.
351
	 */
352
	if (EOF != ch)
353
		while (EOF != (ch = get_char(f)))
354
			putc(ch, NewCrontab);
359
	fclose(f);
355
	fclose(f);
360
	if (fflush(NewCrontab))
356
	if (fflush(NewCrontab) < OK) 
361
		err(ERROR_EXIT, "%s", Filename);
357
		errx(ERROR_EXIT, "%s", Filename);
362
	if (fstat(t, &fsbuf) < 0) {
358
	if (fstat(t, &fsbuf) < 0) {
363
		warn("unable to fstat temp file");
359
		warn("unable to fstat temp file");
364
		goto fatal;
360
		goto fatal;
365
	}
361
	}
362
363
	utime(Filename, &utimebuf);
366
 again:
364
 again:
367
	if (swap_uids() < OK)
365
	rewind(NewCrontab);
368
		err(ERROR_EXIT, "swapping uids");
366
	if (ferror(NewCrontab)) {
369
	if (stat(Filename, &statbuf) < 0) {
367
		fprintf(stderr, "%s: error while writing new crontab to %s\n",
370
		warn("stat");
368
			ProgramName, Filename);
371
 fatal:		unlink(Filename);
369
 fatal:
370
		unlink(Filename);
372
		exit(ERROR_EXIT);
371
		exit(ERROR_EXIT);
373
	}
372
	}
374
	if (swap_uids_back() < OK)
375
		err(ERROR_EXIT, "swapping uids back");
376
	if (statbuf.st_dev != fsbuf.st_dev || statbuf.st_ino != fsbuf.st_ino)
377
		errx(ERROR_EXIT, "temp file must be edited in place");
378
	if (MD5File(Filename, orig_md5) == NULL) {
379
		warn("MD5");
380
		goto fatal;
381
	}
382
373
383
	if ((!(editor = getenv("VISUAL")))
374
	if (((editor = getenv("VISUAL")) == NULL || *editor == '\0') &&
384
	 && (!(editor = getenv("EDITOR")))
375
	    ((editor = getenv("EDITOR")) == NULL || *editor == '\0')) {
385
	    ) {
386
		editor = EDITOR;
376
		editor = EDITOR;
387
	}
377
	}
388
378
Lines 396-413 Link Here
396
386
397
	switch (pid = fork()) {
387
	switch (pid = fork()) {
398
	case -1:
388
	case -1:
399
		warn("fork");
389
		perror("fork");
400
		goto fatal;
390
		goto fatal;
401
	case 0:
391
	case 0:
402
		/* child */
392
		/* child */
403
		if (setuid(getuid()) < 0)
393
		if (setgid(MY_GID(pw)) < 0) 
404
			err(ERROR_EXIT, "setuid(getuid())");
394
			errx(ERROR_EXIT, "setgid(getgid())");
405
		if (chdir("/tmp") < 0)
395
406
			err(ERROR_EXIT, "chdir(/tmp)");
396
		if (setuid(MY_UID(pw)) < 0) 
407
		if (strlen(editor) + strlen(Filename) + 2 >= MAX_TEMPSTR)
397
			errx(ERROR_EXIT, "setuid(getuid())");
408
			errx(ERROR_EXIT, "editor or filename too long");
398
409
		execlp(editor, editor, Filename, (char *)NULL);
399
		if (chdir(_PATH_TMP) < 0) 
410
		err(ERROR_EXIT, "%s", editor);
400
			errx(ERROR_EXIT, _PATH_TMP);
401
402
		if (!glue_strings(q, sizeof q, editor, Filename, ' ')) 
403
			errx(ERROR_EXIT, "%s: editor command line too long",
404
					ProgramName);
405
406
		execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", q, (char *)0);
407
		perror(editor);
408
		exit(ERROR_EXIT);
411
		/*NOTREACHED*/
409
		/*NOTREACHED*/
412
	default:
410
	default:
413
		/* parent */
411
		/* parent */
Lines 415-488 Link Here
415
	}
413
	}
416
414
417
	/* parent */
415
	/* parent */
418
	{
416
	for (;;) {
419
	void (*sig[3])(int signal);
417
		xpid = waitpid(pid, &waiter, WUNTRACED);
420
	sig[0] = signal(SIGHUP, SIG_IGN);
418
		if (xpid == -1) {
421
	sig[1] = signal(SIGINT, SIG_IGN);
419
			if (errno != EINTR)
422
	sig[2] = signal(SIGTERM, SIG_IGN);
420
				fprintf(stderr, "%s: waitpid() failed waiting for PID %ld from \"%s\": %s\n",
423
	xpid = wait(&waiter);
421
					ProgramName, (long)pid, editor, strerror(errno));
424
	signal(SIGHUP, sig[0]);
422
		} else if (xpid != pid) {
425
	signal(SIGINT, sig[1]);
423
			fprintf(stderr, "%s: wrong PID (%ld != %ld) from \"%s\"\n",
426
	signal(SIGTERM, sig[2]);
424
				ProgramName, (long)xpid, (long)pid, editor);
427
	}
425
			goto fatal;
428
	if (xpid != pid) {
426
		} else if (WIFSTOPPED(waiter)) {
429
		warnx("wrong PID (%d != %d) from \"%s\"", xpid, pid, editor);
427
			kill(getpid(), WSTOPSIG(waiter));
430
		goto fatal;
428
		} else if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
431
	}
429
			fprintf(stderr, "%s: \"%s\" exited with status %d\n",
432
	if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
430
				ProgramName, editor, WEXITSTATUS(waiter));
433
		warnx("\"%s\" exited with status %d", editor, WEXITSTATUS(waiter));
431
			goto fatal;
434
		goto fatal;
432
		} else if (WIFSIGNALED(waiter)) {
435
	}
433
			fprintf(stderr,
436
	if (WIFSIGNALED(waiter)) {
434
				"%s: \"%s\" killed; signal %d (%score dumped)\n",
437
		warnx("\"%s\" killed; signal %d (%score dumped)",
435
				ProgramName, editor, WTERMSIG(waiter),
438
			editor, WTERMSIG(waiter), WCOREDUMP(waiter) ?"" :"no ");
436
				WCOREDUMP(waiter) ?"" :"no ");
439
		goto fatal;
437
			goto fatal;
440
	}
438
		} else
441
	if (swap_uids() < OK)
439
			break;
442
		err(ERROR_EXIT, "swapping uids");
440
	}
443
	if (stat(Filename, &statbuf) < 0) {
441
	(void)signal(SIGHUP, SIG_DFL);
444
		warn("stat");
442
	(void)signal(SIGINT, SIG_DFL);
445
		goto fatal;
443
	(void)signal(SIGQUIT, SIG_DFL);
446
	}
444
	if (fstat(t, &statbuf) < 0) {
447
	if (statbuf.st_dev != fsbuf.st_dev || statbuf.st_ino != fsbuf.st_ino)
445
		perror("fstat");
448
		errx(ERROR_EXIT, "temp file must be edited in place");
446
		goto fatal;
449
	if (MD5File(Filename, new_md5) == NULL) {
447
	}
450
		warn("MD5");
448
	if (utimebuf.modtime == statbuf.st_mtime) {
451
		goto fatal;
449
		fprintf(stderr, "%s: no changes made to crontab\n",
452
	}
450
			ProgramName);
453
	if (swap_uids_back() < OK)
454
		err(ERROR_EXIT, "swapping uids back");
455
	if (strcmp(orig_md5, new_md5) == 0 && !syntax_error) {
456
		warnx("no changes made to crontab");
457
		goto remove;
451
		goto remove;
458
	}
452
	}
459
	warnx("installing new crontab");
453
	fprintf(stderr, "%s: installing new crontab\n", ProgramName);
460
	switch (replace_cmd()) {
454
	switch (replace_cmd()) {
461
	case 0:			/* Success */
455
	case 0:
462
		break;
456
		break;
463
	case -1:		/* Syntax error */
457
	case -1:
464
		for (;;) {
458
		for (;;) {
465
			printf("Do you want to retry the same edit? ");
459
			printf("Do you want to retry the same edit? ");
466
			fflush(stdout);
460
			fflush(stdout);
467
			q[0] = '\0';
461
			q[0] = '\0';
468
			(void) fgets(q, sizeof q, stdin);
462
			(void) fgets(q, sizeof q, stdin);
469
			switch (islower(q[0]) ? q[0] : tolower(q[0])) {
463
			switch (q[0]) {
470
			case 'y':
464
			case 'y':
471
				syntax_error = 1;
465
			case 'Y':
472
				goto again;
466
				goto again;
473
			case 'n':
467
			case 'n':
468
			case 'N':
474
				goto abandon;
469
				goto abandon;
475
			default:
470
			default:
476
				fprintf(stderr, "Enter Y or N\n");
471
				fprintf(stderr, "Enter Y or N\n");
477
			}
472
			}
478
		}
473
		}
479
		/*NOTREACHED*/
474
		/*NOTREACHED*/
480
	case -2:		/* Install error */
475
	case -2:
481
	abandon:
476
	abandon:
482
		warnx("edits left in %s", Filename);
477
		fprintf(stderr, "%s: edits left in %s\n",
478
			ProgramName, Filename);
483
		goto done;
479
		goto done;
484
	default:
480
	default:
485
		warnx("panic: bad switch() in replace_cmd()");
481
		fprintf(stderr, "%s: panic: bad switch() in replace_cmd()\n",
482
			ProgramName);
486
		goto fatal;
483
		goto fatal;
487
	}
484
	}
488
 remove:
485
 remove:
Lines 491-530 Link Here
491
	log_it(RealUser, Pid, "END EDIT", User);
488
	log_it(RealUser, Pid, "END EDIT", User);
492
}
489
}
493
490
494
495
/* returns	0	on success
491
/* returns	0	on success
496
 *		-1	on syntax error
492
 *		-1	on syntax error
497
 *		-2	on install error
493
 *		-2	on install error
498
 */
494
 */
499
static int
495
static int
500
replace_cmd() {
496
replace_cmd(void) {
501
	char	n[MAX_FNAME], envstr[MAX_ENVSTR], tn[MAX_FNAME];
497
	char n[MAX_FNAME], envstr[MAX_ENVSTR];
502
	FILE	*tmp;
498
	FILE *tmp;
503
	int	ch, eof;
499
	int ch, eof, fd;
504
	entry	*e;
500
	int error = 0;
505
	time_t	now = time(NULL);
501
	entry *e;
506
	char	**envp = env_init();
502
	uid_t file_owner;
503
	time_t now = time(NULL);
504
	char **envp = env_init();
507
505
508
	if (envp == NULL) {
506
	if (envp == NULL) {
509
		warnx("cannot allocate memory");
507
		fprintf(stderr, "%s: Cannot allocate memory.\n", ProgramName);
510
		return (-2);
508
		return (-2);
511
	}
509
	}
512
510
513
	(void) snprintf(n, sizeof(n), "tmp.%d", Pid);
511
	if (!glue_strings(TempFilename, sizeof TempFilename, SPOOL_DIR,
514
	(void) snprintf(tn, sizeof(tn), CRON_TAB(n));
512
	    "tmp.XXXXXXXXXX", '/')) {
515
513
		TempFilename[0] = '\0';
516
	if (!(tmp = fopen(tn, "w+"))) {
514
		fprintf(stderr, "path too long\n");
517
		warn("%s", tn);
515
		return (-2);
516
	}
517
	if ((fd = mkstemp(TempFilename)) == -1 || !(tmp = fdopen(fd, "w+"))) {
518
		perror(TempFilename);
519
		if (fd != -1) {
520
			close(fd);
521
			unlink(TempFilename);
522
		}
523
		TempFilename[0] = '\0';
518
		return (-2);
524
		return (-2);
519
	}
525
	}
520
526
527
	(void) signal(SIGHUP, die);
528
	(void) signal(SIGINT, die);
529
	(void) signal(SIGQUIT, die);
530
521
	/* write a signature at the top of the file.
531
	/* write a signature at the top of the file.
522
	 *
532
	 *
523
	 * VERY IMPORTANT: make sure NHEADER_LINES agrees with this code.
533
	 * VERY IMPORTANT: make sure NHEADER_LINES agrees with this code.
524
	 */
534
	 */
525
	fprintf(tmp, "# DO NOT EDIT THIS FILE - edit the master and reinstall.\n");
535
	fprintf(tmp, "# DO NOT EDIT THIS FILE - edit the master and reinstall.\n");
526
	fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
536
	fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
527
	fprintf(tmp, "# (Cron version -- %s)\n", rcsid);
537
	fprintf(tmp, "# (Cron version %s -- %s)\n", CRON_VERSION, rcsid);
528
538
529
	/* copy the crontab to the tmp
539
	/* copy the crontab to the tmp
530
	 */
540
	 */
Lines 532-544 Link Here
532
	Set_LineNum(1)
542
	Set_LineNum(1)
533
	while (EOF != (ch = get_char(NewCrontab)))
543
	while (EOF != (ch = get_char(NewCrontab)))
534
		putc(ch, tmp);
544
		putc(ch, tmp);
535
	ftruncate(fileno(tmp), ftell(tmp));
545
	ftruncate(fileno(tmp), ftell(tmp));	/* XXX redundant with "w+"? */
536
	fflush(tmp);  rewind(tmp);
546
	fflush(tmp);  rewind(tmp);
537
547
538
	if (ferror(tmp)) {
548
	if (ferror(tmp)) {
539
		warnx("error while writing new crontab to %s", tn);
549
		fprintf(stderr, "%s: error while writing new crontab to %s\n",
540
		fclose(tmp);  unlink(tn);
550
			ProgramName, TempFilename);
541
		return (-2);
551
		fclose(tmp);
552
		error = -2;
553
		goto done;
542
	}
554
	}
543
555
544
	/* check the syntax of the file being installed.
556
	/* check the syntax of the file being installed.
Lines 553-558 Link Here
553
	while (!CheckErrorCount && !eof) {
565
	while (!CheckErrorCount && !eof) {
554
		switch (load_env(envstr, tmp)) {
566
		switch (load_env(envstr, tmp)) {
555
		case ERR:
567
		case ERR:
568
			/* check for data before the EOF */
569
			if (envstr[0] != '\0') {
570
				Set_LineNum(LineNumber + 1);
571
				check_error("premature EOF");
572
			}
556
			eof = TRUE;
573
			eof = TRUE;
557
			break;
574
			break;
558
		case FALSE:
575
		case FALSE:
Lines 566-643 Link Here
566
	}
583
	}
567
584
568
	if (CheckErrorCount != 0) {
585
	if (CheckErrorCount != 0) {
569
		warnx("errors in crontab file, can't install");
586
		fprintf(stderr, "errors in crontab file, can't install.\n");
570
		fclose(tmp);  unlink(tn);
587
		fclose(tmp);
571
		return (-1);
588
		error = -1;
589
		goto done;
572
	}
590
	}
573
591
592
	file_owner = (getgid() == getegid()) ? ROOT_UID : pw->pw_uid;
593
574
#ifdef HAS_FCHOWN
594
#ifdef HAS_FCHOWN
575
	if (fchown(fileno(tmp), ROOT_UID, -1) < OK)
595
	if (fchown(fileno(tmp), file_owner, -1) < OK) {
576
#else
596
		perror("fchown");
577
	if (chown(tn, ROOT_UID, -1) < OK)
597
		fclose(tmp);
578
#endif
598
		error = -2;
579
	{
599
		goto done;
580
		warn("chown");
581
		fclose(tmp);  unlink(tn);
582
		return (-2);
583
	}
600
	}
584
585
#ifdef HAS_FCHMOD
586
	if (fchmod(fileno(tmp), 0600) < OK)
587
#else
601
#else
588
	if (chmod(tn, 0600) < OK)
602
	if (chown(TempFilename, file_owner, -1) < OK) {
589
#endif
603
		perror("chown");
590
	{
604
		fclose(tmp);
591
		warn("chown");
605
		error = -2;
592
		fclose(tmp);  unlink(tn);
606
		goto done;
593
		return (-2);
594
	}
607
	}
608
#endif
595
609
596
	if (fclose(tmp) == EOF) {
610
	if (fclose(tmp) == EOF) {
597
		warn("fclose");
611
		perror("fclose");
598
		unlink(tn);
612
		error = -2;
599
		return (-2);
613
		goto done;
600
	}
614
	}
601
615
602
	(void) snprintf(n, sizeof(n), CRON_TAB(User));
616
	if (!glue_strings(n, sizeof n, SPOOL_DIR, User, '/')) {
603
	if (rename(tn, n)) {
617
		fprintf(stderr, "path too long\n");
604
		warn("error renaming %s to %s", tn, n);
618
		error = -2;
605
		unlink(tn);
619
		goto done;
606
		return (-2);
607
	}
620
	}
608
621
	if (rename(TempFilename, n)) {
622
		fprintf(stderr, "%s: error renaming %s to %s\n",
623
			ProgramName, TempFilename, n);
624
		perror("rename");
625
		error = -2;
626
		goto done;
627
	}
628
	TempFilename[0] = '\0';
609
	log_it(RealUser, Pid, "REPLACE", User);
629
	log_it(RealUser, Pid, "REPLACE", User);
610
630
611
	/*
631
	poke_daemon(RELOAD_CRON);
612
	 * Creating the 'tn' temp file has already updated the
613
	 * modification time of the spool directory.  Sleep for a
614
	 * second to ensure that poke_daemon() sets a later
615
	 * modification time.  Otherwise, this can race with the cron
616
	 * daemon scanning for updated crontabs.
617
	 */
618
	sleep(1);
619
620
	poke_daemon();
621
632
622
	return (0);
633
done:
634
	(void) signal(SIGHUP, SIG_DFL);
635
	(void) signal(SIGINT, SIG_DFL);
636
	(void) signal(SIGQUIT, SIG_DFL);
637
	if (TempFilename[0]) {
638
		(void) unlink(TempFilename);
639
		TempFilename[0] = '\0';
640
	}
641
	return (error);
623
}
642
}
624
643
625
626
static void
644
static void
627
poke_daemon() {
645
poke_daemon(unsigned char cookie) {
646
	int sock = -1;
647
	struct sockaddr_un s_un;
628
#ifdef USE_UTIMES
648
#ifdef USE_UTIMES
629
	struct timeval tvs[2];
649
	struct timeval tvs[1];
630
650
	
631
	(void)gettimeofday(&tvs[0], NULL);
651
	(void)gettimeofday(&tvs, NULL);
632
	tvs[1] = tvs[0];
652
	if (utime(SPOOL_DIR, tvs) < OK) {
633
	if (utimes(SPOOL_DIR, tvs) < OK) {
634
		warn("can't update mtime on spooldir %s", SPOOL_DIR);
653
		warn("can't update mtime on spooldir %s", SPOOL_DIR);
635
		return;
654
		return;
636
	}
655
	}
637
#else
656
#else
638
	if (utime(SPOOL_DIR, NULL) < OK) {
657
	if (utime(SPOOL_DIR, NULL) < OK) {
639
		warn("can't update mtime on spooldir %s", SPOOL_DIR);
658
		warn("cant't update mtime on spooldir %s", SPOOL_DIR);
640
		return;
659
		return;
641
	}
660
	}
642
#endif /*USE_UTIMES*/
661
#endif /*USE_UTIMES*/
662
663
	memset(&s_un, '\0', sizeof(s_un));
664
	if ((unsigned long)snprintf(s_un.sun_path, sizeof(s_un.sun_path), "%s/%s/%s",
665
				CRONDIR, SPOOL_DIR, SOCKFILE) >= sizeof(s_un.sun_path)) {
666
		fprintf(stderr, "%s: %s/%s: path too long\n",
667
				ProgramName, CRONDIR, SOCKFILE);
668
		return;
669
	}
670
	
671
	s_un.sun_family = PF_LOCAL;
672
#ifdef SUN_LEN
673
	s_un.sun_len = SUN_LEN(&s_un);
674
#endif
675
	(void) signal(SIGPIPE, SIG_IGN);
676
	if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) >= 0 &&
677
			connect(sock, (struct sockaddr *)&s_un, sizeof(s_un)) == 0)
678
		write(sock, &cookie, 1);
679
	else
680
		fprintf(stderr, "%s: warning, cron does not appear to be "
681
				"running.\n", ProgramName);
682
	if (sock >= 0)
683
		close(sock);
684
	(void) signal(SIGPIPE, SIG_DFL);
685
}
686
687
static void
688
die(int x) {
689
	if (TempFilename[0])
690
		(void) unlink(TempFilename);
691
	_exit(ERROR_EXIT);
643
}
692
}
(-)cron/doc/CHANGES (-1 / +1 lines)
Lines 1-4 Link Here
1
$FreeBSD: head/usr.sbin/cron/doc/CHANGES 228990 2011-12-30 10:58:14Z uqs $
1
$FreeBSD: releng/10.0/usr.sbin/cron/doc/CHANGES 228990 2011-12-30 10:58:14Z uqs $
2
--------
2
--------
3
3
4
Vixie Cron		Changes from V2 to V3
4
Vixie Cron		Changes from V2 to V3
(-)cron/doc/CONVERSION (-1 / +1 lines)
Lines 1-4 Link Here
1
$FreeBSD: head/usr.sbin/cron/doc/CONVERSION 72091 2001-02-06 11:21:58Z asmodai $
1
$FreeBSD: releng/10.0/usr.sbin/cron/doc/CONVERSION 72091 2001-02-06 11:21:58Z asmodai $
2
2
3
Conversion of BSD 4.[23] crontab files:
3
Conversion of BSD 4.[23] crontab files:
4
4
(-)cron/doc/FEATURES (-1 / +1 lines)
Lines 1-4 Link Here
1
$FreeBSD: head/usr.sbin/cron/doc/FEATURES 50479 1999-08-28 01:35:59Z peter $
1
$FreeBSD: releng/10.0/usr.sbin/cron/doc/FEATURES 50479 1999-08-28 01:35:59Z peter $
2
2
3
Features of Vixie's cron relative to BSD 4.[23] and SysV crons:
3
Features of Vixie's cron relative to BSD 4.[23] and SysV crons:
4
4
(-)cron/doc/INSTALL (-1 / +1 lines)
Lines 15-21 Link Here
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
16
 */
16
 */
17
17
18
$FreeBSD: head/usr.sbin/cron/doc/INSTALL 50479 1999-08-28 01:35:59Z peter $
18
$FreeBSD: releng/10.0/usr.sbin/cron/doc/INSTALL 50479 1999-08-28 01:35:59Z peter $
19
19
20
Read the comments at the top of the Makefile, then edit the area marked
20
Read the comments at the top of the Makefile, then edit the area marked
21
'configurable stuff'.
21
'configurable stuff'.
(-)cron/doc/MAIL (-1 / +1 lines)
Lines 3-9 Link Here
3
  version of cron.  it is presented here for its entertainment value.
3
  version of cron.  it is presented here for its entertainment value.
4
  --vix ]
4
  --vix ]
5
5
6
$FreeBSD: head/usr.sbin/cron/doc/MAIL 228990 2011-12-30 10:58:14Z uqs $
6
$FreeBSD: releng/10.0/usr.sbin/cron/doc/MAIL 228990 2011-12-30 10:58:14Z uqs $
7
7
8
From ptsfa!lll-crg!ames!acornrc!bob Wed Dec 31 10:07:08 1986
8
From ptsfa!lll-crg!ames!acornrc!bob Wed Dec 31 10:07:08 1986
9
Date: Wed, 31 Dec 86 08:59:31 pst
9
Date: Wed, 31 Dec 86 08:59:31 pst
(-)cron/doc/Makefile.vixie (-1 / +1 lines)
Lines 17-23 Link Here
17
17
18
# Makefile for vixie's cron
18
# Makefile for vixie's cron
19
#
19
#
20
# $FreeBSD: head/usr.sbin/cron/doc/Makefile.vixie 50479 1999-08-28 01:35:59Z peter $
20
# $FreeBSD: releng/10.0/usr.sbin/cron/doc/Makefile.vixie 50479 1999-08-28 01:35:59Z peter $
21
#
21
#
22
# vix 03mar88 [moved to RCS, rest of log is in there]
22
# vix 03mar88 [moved to RCS, rest of log is in there]
23
# vix 30mar87 [goodbye, time.c; hello, getopt]
23
# vix 30mar87 [goodbye, time.c; hello, getopt]
(-)cron/doc/README (-1 / +1 lines)
Lines 69-72 Link Here
69
	if you like it, change your /etc/{rc,rc.local} to use it instead of
69
	if you like it, change your /etc/{rc,rc.local} to use it instead of
70
		the old one.
70
		the old one.
71
71
72
$FreeBSD: head/usr.sbin/cron/doc/README 50479 1999-08-28 01:35:59Z peter $
72
$FreeBSD: releng/10.0/usr.sbin/cron/doc/README 50479 1999-08-28 01:35:59Z peter $
(-)cron/lib/Makefile (-1 / +1 lines)
Lines 1-4 Link Here
1
# $FreeBSD: head/usr.sbin/cron/lib/Makefile 185042 2008-11-18 00:59:26Z matteo $
1
# $FreeBSD: releng/10.0/usr.sbin/cron/lib/Makefile 185042 2008-11-18 00:59:26Z matteo $
2
2
3
LIB=	cron
3
LIB=	cron
4
INTERNALLIB=
4
INTERNALLIB=
(-)cron/lib/compat.c (-237 lines)
Lines 1-237 Link Here
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[] = "$FreeBSD: head/usr.sbin/cron/lib/compat.c 69793 2000-12-09 09:35:55Z obrien $";
20
#endif
21
22
/* vix 30dec93 [broke this out of misc.c - see RCS log for history]
23
 * vix 15jan87 [added TIOCNOTTY, thanks csg@pyramid]
24
 */
25
26
27
#include "cron.h"
28
#ifdef NEED_GETDTABLESIZE
29
# include <limits.h>
30
#endif
31
#if defined(NEED_SETSID) && defined(BSD)
32
# include <sys/ioctl.h>
33
#endif
34
#include <errno.h>
35
#include <paths.h>
36
37
38
/* the code does not depend on any of vfork's
39
 * side-effects; it just uses it as a quick
40
 * fork-and-exec.
41
 */
42
#ifdef NEED_VFORK
43
PID_T
44
vfork() {
45
	return (fork());
46
}
47
#endif
48
49
50
#ifdef NEED_STRDUP
51
char *
52
strdup(str)
53
	char	*str;
54
{
55
	char	*temp;
56
57
	if ((temp = malloc(strlen(str) + 1)) == NULL) {
58
		errno = ENOMEM;
59
		return NULL;
60
	}
61
	(void) strcpy(temp, str);
62
	return temp;
63
}
64
#endif
65
66
67
#ifdef NEED_STRERROR
68
char *
69
strerror(error)
70
	int error;
71
{
72
	extern char *sys_errlist[];
73
	extern int sys_nerr;
74
	static char buf[32];
75
76
	if ((error <= sys_nerr) && (error > 0)) {
77
		return sys_errlist[error];
78
	}
79
80
	sprintf(buf, "Unknown error: %d", error);
81
	return buf;
82
}
83
#endif
84
85
86
#ifdef NEED_STRCASECMP
87
int
88
strcasecmp(left, right)
89
	char	*left;
90
	char	*right;
91
{
92
	while (*left && (MkLower(*left) == MkLower(*right))) {
93
		left++;
94
		right++;
95
	}
96
	return MkLower(*left) - MkLower(*right);
97
}
98
#endif
99
100
101
#ifdef NEED_SETSID
102
int
103
setsid()
104
{
105
	int	newpgrp;
106
# if defined(BSD)
107
	int	fd;
108
#  if defined(POSIX)
109
	newpgrp = setpgid((pid_t)0, getpid());
110
#  else
111
	newpgrp = setpgrp(0, getpid());
112
#  endif
113
	if ((fd = open(_PATH_TTY, 2)) >= 0)
114
	{
115
		(void) ioctl(fd, TIOCNOTTY, (char*)0);
116
		(void) close(fd);
117
	}
118
# else /*BSD*/
119
	newpgrp = setpgrp();
120
121
	(void) close(STDIN);	(void) open(_PATH_DEVNULL, 0);
122
	(void) close(STDOUT);	(void) open(_PATH_DEVNULL, 1);
123
	(void) close(STDERR);	(void) open(_PATH_DEVNULL, 2);
124
# endif /*BSD*/
125
	return newpgrp;
126
}
127
#endif /*NEED_SETSID*/
128
129
130
#ifdef NEED_GETDTABLESIZE
131
int
132
getdtablesize() {
133
#ifdef _SC_OPEN_MAX
134
	return sysconf(_SC_OPEN_MAX);
135
#else
136
	return _POSIX_OPEN_MAX;
137
#endif
138
}
139
#endif
140
141
142
#ifdef NEED_FLOCK
143
/* The following flock() emulation snarfed intact *) from the HP-UX
144
 * "BSD to HP-UX porting tricks" maintained by
145
 * system@alchemy.chem.utoronto.ca (System Admin (Mike Peterson))
146
 * from the version "last updated: 11-Jan-1993"
147
 * Snarfage done by Jarkko Hietaniemi <Jarkko.Hietaniemi@hut.fi>
148
 * *) well, almost, had to K&R the function entry, HPUX "cc"
149
 * does not grok ANSI function prototypes */
150
 
151
/*
152
 * flock (fd, operation)
153
 *
154
 * This routine performs some file locking like the BSD 'flock'
155
 * on the object described by the int file descriptor 'fd',
156
 * which must already be open.
157
 *
158
 * The operations that are available are:
159
 *
160
 * LOCK_SH  -  get a shared lock.
161
 * LOCK_EX  -  get an exclusive lock.
162
 * LOCK_NB  -  don't block (must be ORed with LOCK_SH or LOCK_EX).
163
 * LOCK_UN  -  release a lock.
164
 *
165
 * Return value: 0 if lock successful, -1 if failed.
166
 *
167
 * Note that whether the locks are enforced or advisory is
168
 * controlled by the presence or absence of the SETGID bit on
169
 * the executable.
170
 *
171
 * Note that there is no difference between shared and exclusive
172
 * locks, since the 'lockf' system call in SYSV doesn't make any
173
 * distinction.
174
 *
175
 * The file "<sys/file.h>" should be modified to contain the definitions
176
 * of the available operations, which must be added manually (see below
177
 * for the values).
178
 */
179
180
/* this code has been reformatted by vixie */
181
182
int
183
flock(fd, operation)
184
	int fd;
185
	int operation;
186
{
187
	int i;
188
189
	switch (operation) {
190
	case LOCK_SH:		/* get a shared lock */
191
	case LOCK_EX:		/* get an exclusive lock */
192
		i = lockf (fd, F_LOCK, 0);
193
		break;
194
195
	case LOCK_SH|LOCK_NB:	/* get a non-blocking shared lock */
196
	case LOCK_EX|LOCK_NB:	/* get a non-blocking exclusive lock */
197
		i = lockf (fd, F_TLOCK, 0);
198
		if (i == -1)
199
			if ((errno == EAGAIN) || (errno == EACCES))
200
				errno = EWOULDBLOCK;
201
		break;
202
203
	case LOCK_UN:		/* unlock */
204
		i = lockf (fd, F_ULOCK, 0);
205
		break;
206
 
207
	default:		/* can't decipher operation */
208
		i = -1;
209
		errno = EINVAL;
210
		break;
211
	}
212
 
213
	return (i);
214
}
215
#endif /*NEED_FLOCK*/
216
217
218
#ifdef NEED_SETENV
219
int
220
setenv(name, value, overwrite)
221
	char *name, *value;
222
	int overwrite;
223
{
224
	char *tmp;
225
226
	if (overwrite && getenv(name))
227
		return -1;
228
229
	if (!(tmp = malloc(strlen(name) + strlen(value) + 2))) {
230
		errno = ENOMEM;
231
		return -1;
232
	}
233
234
	sprintf(tmp, "%s=%s", name, value);
235
	return putenv(tmp);	/* intentionally orphan 'tmp' storage */
236
}
237
#endif
(-)cron/lib/entry.c (-288 / +225 lines)
Lines 1-24 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/*
2
 * Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
3
 * All rights reserved
4
 */
5
6
/*
7
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
8
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
9
 *
4
 * Distribute freely, except: don't remove my name from the source or
10
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
11
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
12
 * copyright notice and this permission notice appear in all copies.
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
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
14
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
15
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
16
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
17
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
21
 */
17
22
18
#if !defined(lint) && !defined(LINT)
23
//#if !defined(lint) && !defined(LINT)
19
static const char rcsid[] =
24
//static char rcsid[] = "$Id: entry.c,v 1.17 2004/01/23 18:56:42 vixie Exp $";
20
  "$FreeBSD: head/usr.sbin/cron/lib/entry.c 242101 2012-10-25 22:54:29Z sobomax $";
25
//#endif
21
#endif
22
26
23
/* vix 26jan87 [RCS'd; rest of log is in RCS file]
27
/* vix 26jan87 [RCS'd; rest of log is in RCS file]
24
 * vix 01jan87 [added line-level error recovery]
28
 * vix 01jan87 [added line-level error recovery]
Lines 26-52 Link Here
26
 * vix 30dec86 [written]
30
 * vix 30dec86 [written]
27
 */
31
 */
28
32
29
30
#include "cron.h"
33
#include "cron.h"
31
#include <grp.h>
32
#ifdef LOGIN_CAP
33
#include <login_cap.h>
34
#endif
35
34
36
typedef	enum ecode {
35
typedef	enum ecode {
37
	e_none, e_minute, e_hour, e_dom, e_month, e_dow,
36
	e_none, e_minute, e_hour, e_dom, e_month, e_dow,
38
	e_cmd, e_timespec, e_username, e_group, e_mem
37
	e_cmd, e_timespec, e_username, e_option, e_memory
39
#ifdef LOGIN_CAP
40
	, e_class
41
#endif
42
} ecode_e;
38
} ecode_e;
43
39
44
static char	get_list(bitstr_t *, int, int, char *[], int, FILE *),
40
static const char *ecodes[] =
45
		get_range(bitstr_t *, int, int, char *[], int, FILE *),
46
		get_number(int *, int, char *[], int, FILE *);
47
static int	set_element(bitstr_t *, int, int, int);
48
49
static char *ecodes[] =
50
	{
41
	{
51
		"no error",
42
		"no error",
52
		"bad minute",
43
		"bad minute",
Lines 57-75 Link Here
57
		"bad command",
48
		"bad command",
58
		"bad time specifier",
49
		"bad time specifier",
59
		"bad username",
50
		"bad username",
60
		"bad group name",
51
		"bad option",
61
		"out of memory",
52
		"out of memory"
62
#ifdef LOGIN_CAP
63
		"bad class name",
64
#endif
65
	};
53
	};
66
54
55
static int	get_list(bitstr_t *, int, int, const char *[], int, FILE *),
56
		get_range(bitstr_t *, int, int, const char *[], int, FILE *),
57
		get_number(int *, int, const char *[], int, FILE *, const char *),
58
		set_element(bitstr_t *, int, int, int);
67
59
68
void
60
void
69
free_entry(e)
61
free_entry(entry *e) {
70
	entry	*e;
62
# ifdef LOGIN_CAP
71
{
72
#ifdef LOGIN_CAP
73
	if (e->class != NULL)
63
	if (e->class != NULL)
74
		free(e->class);
64
		free(e->class);
75
#endif
65
#endif
Lines 80-99 Link Here
80
	free(e);
70
	free(e);
81
}
71
}
82
72
83
84
/* return NULL if eof or syntax error occurs;
73
/* return NULL if eof or syntax error occurs;
85
 * otherwise return a pointer to a new entry.
74
 * otherwise return a pointer to a new entry.
86
 */
75
 */
87
entry *
76
entry *
88
load_entry(file, error_func, pw, envp)
77
load_entry(FILE *file, void (*error_func)(), struct passwd *pw, char **envp) {
89
	FILE		*file;
90
	void		(*error_func)(char *);
91
	struct passwd	*pw;
92
	char		**envp;
93
{
94
	/* this function reads one crontab entry -- the next -- from a file.
78
	/* this function reads one crontab entry -- the next -- from a file.
95
	 * it skips any leading blank lines, ignores comments, and returns
79
	 * it skips any leading blank lines, ignores comments, and returns
96
	 * EOF if for any reason the entry can't be read and parsed.
80
	 * NULL if for any reason the entry can't be read and parsed.
97
	 *
81
	 *
98
	 * the entry is also parsed here.
82
	 * the entry is also parsed here.
99
	 *
83
	 *
Lines 105-115 Link Here
105
	 */
89
	 */
106
90
107
	ecode_e	ecode = e_none;
91
	ecode_e	ecode = e_none;
108
	entry	*e;
92
	entry *e;
109
	int	ch;
93
	int ch;
110
	char	cmd[MAX_COMMAND];
94
	char cmd[MAX_COMMAND];
111
	char	envstr[MAX_ENVSTR];
95
	char envstr[MAX_ENVSTR];
112
	char	**prev_env;
96
	char **tenvp;
113
97
114
	Debug(DPARS, ("load_entry()...about to eat comments\n"))
98
	Debug(DPARS, ("load_entry()...about to eat comments\n"))
115
99
Lines 117-123 Link Here
117
101
118
	ch = get_char(file);
102
	ch = get_char(file);
119
	if (ch == EOF)
103
	if (ch == EOF)
120
		return NULL;
104
		return (NULL);
121
105
122
	/* ch is now the first useful character of a useful line.
106
	/* ch is now the first useful character of a useful line.
123
	 * it may be an @special or it may be the first character
107
	 * it may be an @special or it may be the first character
Lines 126-136 Link Here
126
110
127
	e = (entry *) calloc(sizeof(entry), sizeof(char));
111
	e = (entry *) calloc(sizeof(entry), sizeof(char));
128
112
129
	if (e == NULL) {
130
		warn("load_entry: calloc failed");
131
		return NULL;
132
	}
133
134
	if (ch == '@') {
113
	if (ch == '@') {
135
		/* all of these should be flagged and load-limited; i.e.,
114
		/* all of these should be flagged and load-limited; i.e.,
136
		 * instead of @hourly meaning "0 * * * *" it should mean
115
		 * instead of @hourly meaning "0 * * * *" it should mean
Lines 144-157 Link Here
144
		 * anymore.  too much for my overloaded brain. (vix, jan90)
123
		 * anymore.  too much for my overloaded brain. (vix, jan90)
145
		 * HINT
124
		 * HINT
146
		 */
125
		 */
147
		Debug(DPARS, ("load_entry()...about to test shortcuts\n"))
148
		ch = get_string(cmd, MAX_COMMAND, file, " \t\n");
126
		ch = get_string(cmd, MAX_COMMAND, file, " \t\n");
149
		if (!strcmp("reboot", cmd)) {
127
		if (!strcmp("reboot", cmd)) {
150
			Debug(DPARS, ("load_entry()...reboot shortcut\n"))
151
			e->flags |= WHEN_REBOOT;
128
			e->flags |= WHEN_REBOOT;
152
		} else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){
129
		} else if (!strcmp("yearly", cmd) || !strcmp("annually", cmd)){
153
			Debug(DPARS, ("load_entry()...yearly shortcut\n"))
154
			bit_set(e->second, 0);
155
			bit_set(e->minute, 0);
130
			bit_set(e->minute, 0);
156
			bit_set(e->hour, 0);
131
			bit_set(e->hour, 0);
157
			bit_set(e->dom, 0);
132
			bit_set(e->dom, 0);
Lines 159-166 Link Here
159
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
134
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
160
			e->flags |= DOW_STAR;
135
			e->flags |= DOW_STAR;
161
		} else if (!strcmp("monthly", cmd)) {
136
		} else if (!strcmp("monthly", cmd)) {
162
			Debug(DPARS, ("load_entry()...monthly shortcut\n"))
163
			bit_set(e->second, 0);
164
			bit_set(e->minute, 0);
137
			bit_set(e->minute, 0);
165
			bit_set(e->hour, 0);
138
			bit_set(e->hour, 0);
166
			bit_set(e->dom, 0);
139
			bit_set(e->dom, 0);
Lines 168-214 Link Here
168
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
141
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
169
			e->flags |= DOW_STAR;
142
			e->flags |= DOW_STAR;
170
		} else if (!strcmp("weekly", cmd)) {
143
		} else if (!strcmp("weekly", cmd)) {
171
			Debug(DPARS, ("load_entry()...weekly shortcut\n"))
172
			bit_set(e->second, 0);
173
			bit_set(e->minute, 0);
144
			bit_set(e->minute, 0);
174
			bit_set(e->hour, 0);
145
			bit_set(e->hour, 0);
175
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
146
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
176
			e->flags |= DOM_STAR;
177
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
147
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
178
			bit_set(e->dow, 0);
148
			bit_set(e->dow, 0);
149
			e->flags |= DOW_STAR;
179
		} else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
150
		} else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
180
			Debug(DPARS, ("load_entry()...daily shortcut\n"))
181
			bit_set(e->second, 0);
182
			bit_set(e->minute, 0);
151
			bit_set(e->minute, 0);
183
			bit_set(e->hour, 0);
152
			bit_set(e->hour, 0);
184
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
153
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
185
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
154
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
186
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
155
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
187
		} else if (!strcmp("hourly", cmd)) {
156
		} else if (!strcmp("hourly", cmd)) {
188
			Debug(DPARS, ("load_entry()...hourly shortcut\n"))
189
			bit_set(e->second, 0);
190
			bit_set(e->minute, 0);
157
			bit_set(e->minute, 0);
191
			bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
158
			bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
192
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
159
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
193
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
160
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
194
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
161
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
162
			e->flags |= HR_STAR;
195
		} else if (!strcmp("every_minute", cmd)) {
163
		} else if (!strcmp("every_minute", cmd)) {
196
			Debug(DPARS, ("load_entry()...every_minute shortcut\n"))
164
			Debug(DPARS, ("load_entry()...every_minute shortcut\n"))
197
			bit_set(e->second, 0);
165
                        bit_set(e->second, 0);
198
			bit_nset(e->minute, 0, (LAST_MINUTE-FIRST_MINUTE+1));
166
                        bit_nset(e->minute, 0, (LAST_MINUTE-FIRST_MINUTE+1));
199
			bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
167
                        bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
200
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
168
                        bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
201
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
169
                        bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
202
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
170
                        bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
203
		} else if (!strcmp("every_second", cmd)) {
204
			Debug(DPARS, ("load_entry()...every_second shortcut\n"))
205
			e->flags |= SEC_RES;
206
			bit_nset(e->second, 0, (LAST_SECOND-FIRST_SECOND+1));
207
			bit_nset(e->minute, 0, (LAST_MINUTE-FIRST_MINUTE+1));
208
			bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
209
			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
210
			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
211
			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
212
		} else {
171
		} else {
213
			ecode = e_timespec;
172
			ecode = e_timespec;
214
			goto eof;
173
			goto eof;
Lines 217-230 Link Here
217
		 * username/command.
176
		 * username/command.
218
		 */
177
		 */
219
		Skip_Blanks(ch, file);
178
		Skip_Blanks(ch, file);
220
		if (ch == EOF) {
179
		if (ch == EOF || ch == '\n') {
221
			ecode = e_cmd;
180
			ecode = e_cmd;
222
			goto eof;
181
			goto eof;
223
		}
182
		}
224
	} else {
183
	} else {
225
		Debug(DPARS, ("load_entry()...about to parse numerics\n"))
184
		Debug(DPARS, ("load_entry()...about to parse numerics\n"))
226
		bit_set(e->second, 0);
227
185
186
		if (ch == '*')
187
			e->flags |= MIN_STAR;
228
		ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE,
188
		ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE,
229
			      PPC_NULL, ch, file);
189
			      PPC_NULL, ch, file);
230
		if (ch == EOF) {
190
		if (ch == EOF) {
Lines 235-240 Link Here
235
		/* hours
195
		/* hours
236
		 */
196
		 */
237
197
198
		if (ch == '*')
199
			e->flags |= HR_STAR;
238
		ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR,
200
		ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR,
239
			      PPC_NULL, ch, file);
201
			      PPC_NULL, ch, file);
240
		if (ch == EOF) {
202
		if (ch == EOF) {
Lines 283-431 Link Here
283
		bit_set(e->dow, 7);
245
		bit_set(e->dow, 7);
284
	}
246
	}
285
247
248
	/* check for permature EOL and catch a common typo */
249
	if (ch == '\n' || ch == '*') {
250
		ecode = e_cmd;
251
		goto eof;
252
	}
253
286
	/* ch is the first character of a command, or a username */
254
	/* ch is the first character of a command, or a username */
287
	unget_char(ch, file);
255
	unget_char(ch, file);
288
256
289
	if (!pw) {
257
	if (!pw) {
290
		char		*username = cmd;	/* temp buffer */
258
		char		*username = cmd;	/* temp buffer */
291
		char            *s;
292
		struct group    *grp;
293
#ifdef LOGIN_CAP
294
		login_cap_t *lc;
295
#endif
296
259
297
		Debug(DPARS, ("load_entry()...about to parse username\n"))
260
		Debug(DPARS, ("load_entry()...about to parse username\n"))
298
		ch = get_string(username, MAX_COMMAND, file, " \t");
261
		ch = get_string(username, MAX_COMMAND, file, " \t\n");
299
262
300
		Debug(DPARS, ("load_entry()...got %s\n",username))
263
		Debug(DPARS, ("load_entry()...got %s\n",username))
301
		if (ch == EOF) {
264
		if (ch == EOF || ch == '\n' || ch == '*') {
302
			ecode = e_cmd;
265
			ecode = e_cmd;
303
			goto eof;
266
			goto eof;
304
		}
267
		}
305
268
306
#ifdef LOGIN_CAP
307
		if ((s = strrchr(username, '/')) != NULL) {
308
			*s = '\0';
309
			e->class = strdup(s + 1);
310
			if (e->class == NULL)
311
				warn("strdup(\"%s\")", s + 1);
312
		} else {
313
			e->class = strdup(RESOURCE_RC);
314
			if (e->class == NULL)
315
				warn("strdup(\"%s\")", RESOURCE_RC);
316
		}
317
		if (e->class == NULL) {
318
			ecode = e_mem;
319
			goto eof;
320
		}
321
		if ((lc = login_getclass(e->class)) == NULL) {
322
			ecode = e_class;
323
			goto eof;
324
		}
325
		login_close(lc);
326
#endif
327
		grp = NULL;
328
		if ((s = strrchr(username, ':')) != NULL) {
329
			*s = '\0';
330
			if ((grp = getgrnam(s + 1)) == NULL) {
331
				ecode = e_group;
332
				goto eof;
333
			}
334
		}
335
336
		pw = getpwnam(username);
269
		pw = getpwnam(username);
337
		if (pw == NULL) {
270
		if (pw == NULL) {
338
			ecode = e_username;
271
			ecode = e_username;
339
			goto eof;
272
			goto eof;
340
		}
273
		}
341
		if (grp != NULL)
274
		Debug(DPARS, ("load_entry()...uid %ld, gid %ld\n",
342
			pw->pw_gid = grp->gr_gid;
275
			      (long)pw->pw_uid, (long)pw->pw_gid))
343
		Debug(DPARS, ("load_entry()...uid %d, gid %d\n",pw->pw_uid,pw->pw_gid))
276
# ifdef LOGIN_CAP
344
#ifdef LOGIN_CAP
277
		Debug(DPARS, ("load_entry()...class %s\n", e->class))
345
		Debug(DPARS, ("load_entry()...class %s\n",e->class))
346
#endif
278
#endif
347
	}
279
	}
348
280
349
#ifndef PAM	/* PAM takes care of account expiration by itself */
281
#ifndef PAM
350
	if (pw->pw_expire && time(NULL) >= pw->pw_expire) {
282
	if (pm->pw_expire && time(NULL) >= pw->pw_expire) {
351
		ecode = e_username;
283
		ecode = e_username;
352
		goto eof;
284
		goto eof;
353
	}
285
	}
354
#endif /* !PAM */
286
#endif
355
356
	e->uid = pw->pw_uid;
287
	e->uid = pw->pw_uid;
357
	e->gid = pw->pw_gid;
288
	e->gid = pw->pw_gid;
358
289
359
	/* copy and fix up environment.  some variables are just defaults and
290
	/* copy and fix up environment.  some variables are just defaults and
360
	 * others are overrides.
291
	 * others are overrides.
361
	 */
292
	 */
362
	e->envp = env_copy(envp);
293
	if ((e->envp = env_copy(envp)) == NULL) {
363
	if (e->envp == NULL) {
294
		ecode = e_memory;
364
		warn("env_copy");
365
		ecode = e_mem;
366
		goto eof;
295
		goto eof;
367
	}
296
	}
368
	if (!env_get("SHELL", e->envp)) {
297
	if (!env_get("SHELL", e->envp)) {
369
		prev_env = e->envp;
298
		if (glue_strings(envstr, sizeof envstr, "SHELL",
370
		sprintf(envstr, "SHELL=%s", _PATH_BSHELL);
299
				 _PATH_BSHELL, '=')) {
371
		e->envp = env_set(e->envp, envstr);
300
			if ((tenvp = env_set(e->envp, envstr)) == NULL) {
372
		if (e->envp == NULL) {
301
				ecode = e_memory;
373
			warn("env_set(%s)", envstr);
302
				goto eof;
374
			env_free(prev_env);
303
			}
375
			ecode = e_mem;
304
			e->envp = tenvp;
376
			goto eof;
305
		} else
377
		}
306
			log_it("CRON", getpid(), "error", "can't set SHELL");
378
	}
307
	}
379
	if (!env_get("HOME", e->envp)) {
308
	if (!env_get("HOME", e->envp)) {
380
		prev_env = e->envp;
309
		if (glue_strings(envstr, sizeof envstr, "HOME",
381
		sprintf(envstr, "HOME=%s", pw->pw_dir);
310
				 pw->pw_dir, '=')) {
382
		e->envp = env_set(e->envp, envstr);
311
			if ((tenvp = env_set(e->envp, envstr)) == NULL) {
383
		if (e->envp == NULL) {
312
				ecode = e_memory;
384
			warn("env_set(%s)", envstr);
313
				goto eof;
385
			env_free(prev_env);
314
			}
386
			ecode = e_mem;
315
			e->envp = tenvp;
387
			goto eof;
316
		} else
388
		}
317
			log_it("CRON", getpid(), "error", "can't set HOME");
389
	}
318
	}
319
#ifndef LOGIN_CAP
320
	/* If login.conf is in used we will get the default PATH later. */
390
	if (!env_get("PATH", e->envp)) {
321
	if (!env_get("PATH", e->envp)) {
391
		prev_env = e->envp;
322
		if (glue_strings(envstr, sizeof envstr, "PATH",
392
		sprintf(envstr, "PATH=%s", _PATH_DEFPATH);
323
				 _PATH_DEFPATH, '=')) {
393
		e->envp = env_set(e->envp, envstr);
324
			if ((tenvp = env_set(e->envp, envstr)) == NULL) {
394
		if (e->envp == NULL) {
325
				ecode = e_memory;
395
			warn("env_set(%s)", envstr);
326
				goto eof;
396
			env_free(prev_env);
327
			}
397
			ecode = e_mem;
328
			e->envp = tenvp;
398
			goto eof;
329
		} else
399
		}
330
			log_it("CRON", getpid(), "error", "can't set PATH");
400
	}
331
	}
401
	prev_env = e->envp;
332
#endif /* LOGIN_CAP */
402
	sprintf(envstr, "%s=%s", "LOGNAME", pw->pw_name);
333
	if (glue_strings(envstr, sizeof envstr, "LOGNAME",
403
	e->envp = env_set(e->envp, envstr);
334
			 pw->pw_name, '=')) {
404
	if (e->envp == NULL) {
335
		if ((tenvp = env_set(e->envp, envstr)) == NULL) {
405
		warn("env_set(%s)", envstr);
336
			ecode = e_memory;
406
		env_free(prev_env);
337
			goto eof;
407
		ecode = e_mem;
338
		}
408
		goto eof;
339
		e->envp = tenvp;
409
	}
340
	} else
410
#if defined(BSD)
341
		log_it("CRON", getpid(), "error", "can't set LOGNAME");
411
	prev_env = e->envp;
342
#if defined(BSD) || defined(__linux)
412
	sprintf(envstr, "%s=%s", "USER", pw->pw_name);
343
	if (glue_strings(envstr, sizeof envstr, "USER",
413
	e->envp = env_set(e->envp, envstr);
344
			 pw->pw_name, '=')) {
414
	if (e->envp == NULL) {
345
		if ((tenvp = env_set(e->envp, envstr)) == NULL) {
415
		warn("env_set(%s)", envstr);
346
			ecode = e_memory;
416
		env_free(prev_env);
347
			goto eof;
417
		ecode = e_mem;
348
		}
418
		goto eof;
349
		e->envp = tenvp;
419
	}
350
	} else
351
		log_it("CRON", getpid(), "error", "can't set USER");
420
#endif
352
#endif
421
353
422
	Debug(DPARS, ("load_entry()...about to parse command\n"))
354
	Debug(DPARS, ("load_entry()...about to parse command\n"))
423
355
356
	/* If the first character of the command is '-' it is a cron option.
357
	 */
358
	while ((ch = get_char(file)) == '-') {
359
		switch (ch = get_char(file)) {
360
		case 'q':
361
			e->flags |= DONT_LOG;
362
			Skip_Nonblanks(ch, file)
363
			break;
364
		default:
365
			ecode = e_option;
366
			goto eof;
367
		}
368
		Skip_Blanks(ch, file)
369
		if (ch == EOF || ch == '\n') {
370
			ecode = e_cmd;
371
			goto eof;
372
		}
373
	}
374
	unget_char(ch, file);
375
424
	/* Everything up to the next \n or EOF is part of the command...
376
	/* Everything up to the next \n or EOF is part of the command...
425
	 * too bad we don't know in advance how long it will be, since we
377
	 * too bad we don't know in advance how long it will be, since we
426
	 * need to malloc a string for it... so, we limit it to MAX_COMMAND.
378
	 * need to malloc a string for it... so, we limit it to MAX_COMMAND.
427
	 * XXX - should use realloc().
379
	 */ 
428
	 */
429
	ch = get_string(cmd, MAX_COMMAND, file, "\n");
380
	ch = get_string(cmd, MAX_COMMAND, file, "\n");
430
381
431
	/* a file without a \n before the EOF is rude, so we'll complain...
382
	/* a file without a \n before the EOF is rude, so we'll complain...
Lines 437-473 Link Here
437
388
438
	/* got the command in the 'cmd' string; save it in *e.
389
	/* got the command in the 'cmd' string; save it in *e.
439
	 */
390
	 */
440
	e->cmd = strdup(cmd);
391
	if ((e->cmd = strdup(cmd)) == NULL) {
441
	if (e->cmd == NULL) {
392
		ecode = e_memory;
442
		warn("strdup(\"%s\")", cmd);
443
		ecode = e_mem;
444
		goto eof;
393
		goto eof;
445
	}
394
	}
395
446
	Debug(DPARS, ("load_entry()...returning successfully\n"))
396
	Debug(DPARS, ("load_entry()...returning successfully\n"))
447
397
448
	/* success, fini, return pointer to the entry we just created...
398
	/* success, fini, return pointer to the entry we just created...
449
	 */
399
	 */
450
	return e;
400
	return (e);
451
401
452
 eof:
402
 eof:
453
	free_entry(e);
403
	if (e->envp)
404
		env_free(e->envp);
405
	if (e->cmd)
406
		free(e->cmd);
407
	free(e);
408
	while (ch != '\n' && !feof(file))
409
		ch = get_char(file);
454
	if (ecode != e_none && error_func)
410
	if (ecode != e_none && error_func)
455
		(*error_func)(ecodes[(int)ecode]);
411
		(*error_func)(ecodes[(int)ecode]);
456
	while (ch != EOF && ch != '\n')
412
	return (NULL);
457
		ch = get_char(file);
458
	return NULL;
459
}
413
}
460
414
461
415
static int
462
static char
416
get_list(bitstr_t *bits, int low, int high, const char *names[],
463
get_list(bits, low, high, names, ch, file)
417
	 int ch, FILE *file)
464
	bitstr_t	*bits;		/* one bit per flag, default=FALSE */
465
	int		low, high;	/* bounds, impl. offset for bitstr */
466
	char		*names[];	/* NULL or *[] of names for these elements */
467
	int		ch;		/* current character being processed */
468
	FILE		*file;		/* file being read */
469
{
418
{
470
	register int	done;
419
	int done;
471
420
472
	/* we know that we point to a non-blank character here;
421
	/* we know that we point to a non-blank character here;
473
	 * must do a Skip_Blanks before we exit, so that the
422
	 * must do a Skip_Blanks before we exit, so that the
Lines 479-485 Link Here
479
428
480
	/* list = range {"," range}
429
	/* list = range {"," range}
481
	 */
430
	 */
482
431
	
483
	/* clear the bit string, since the default is 'off'.
432
	/* clear the bit string, since the default is 'off'.
484
	 */
433
	 */
485
	bit_nclear(bits, 0, (high-low+1));
434
	bit_nclear(bits, 0, (high-low+1));
Lines 488-494 Link Here
488
	 */
437
	 */
489
	done = FALSE;
438
	done = FALSE;
490
	while (!done) {
439
	while (!done) {
491
		ch = get_range(bits, low, high, names, ch, file);
440
		if (EOF == (ch = get_range(bits, low, high, names, ch, file)))
441
			return (EOF);
492
		if (ch == ',')
442
		if (ch == ',')
493
			ch = get_char(file);
443
			ch = get_char(file);
494
		else
444
		else
Lines 502-524 Link Here
502
452
503
	Debug(DPARS|DEXT, ("get_list()...exiting w/ %02x\n", ch))
453
	Debug(DPARS|DEXT, ("get_list()...exiting w/ %02x\n", ch))
504
454
505
	return ch;
455
	return (ch);
506
}
456
}
507
457
508
458
509
static char
459
static int
510
get_range(bits, low, high, names, ch, file)
460
get_range(bitstr_t *bits, int low, int high, const char *names[],
511
	bitstr_t	*bits;		/* one bit per flag, default=FALSE */
461
	  int ch, FILE *file)
512
	int		low, high;	/* bounds, impl. offset for bitstr */
513
	char		*names[];	/* NULL or names of elements */
514
	int		ch;		/* current character being processed */
515
	FILE		*file;		/* file being read */
516
{
462
{
517
	/* range = number | number "-" number [ "/" number ]
463
	/* range = number | number "-" number [ "/" number ]
518
	 */
464
	 */
519
465
520
	register int	i;
466
	int i, num1, num2, num3;
521
	auto int	num1, num2, num3;
522
467
523
	Debug(DPARS|DEXT, ("get_range()...entering, exit won't show\n"))
468
	Debug(DPARS|DEXT, ("get_range()...entering, exit won't show\n"))
524
469
Lines 529-559 Link Here
529
		num2 = high;
474
		num2 = high;
530
		ch = get_char(file);
475
		ch = get_char(file);
531
		if (ch == EOF)
476
		if (ch == EOF)
532
			return EOF;
477
			return (EOF);
533
	} else {
478
	} else {
534
		if (EOF == (ch = get_number(&num1, low, names, ch, file)))
479
		ch = get_number(&num1, low, names, ch, file, ",- \t\n");
535
			return EOF;
480
		if (ch == EOF)
481
			return (EOF);
536
482
537
		if (ch == '/')
483
		if (ch != '-') {
538
			num2 = high;
539
		else if (ch != '-') {
540
			/* not a range, it's a single number.
484
			/* not a range, it's a single number.
541
			 */
485
			 */
542
			if (EOF == set_element(bits, low, high, num1))
486
			if (EOF == set_element(bits, low, high, num1)) {
543
				return EOF;
487
				unget_char(ch, file);
544
			return ch;
488
				return (EOF);
489
			}
490
			return (ch);
545
		} else {
491
		} else {
546
			/* eat the dash
492
			/* eat the dash
547
			 */
493
			 */
548
			ch = get_char(file);
494
			ch = get_char(file);
549
			if (ch == EOF)
495
			if (ch == EOF)
550
				return EOF;
496
				return (EOF);
551
497
552
			/* get the number following the dash
498
			/* get the number following the dash
553
			 */
499
			 */
554
			ch = get_number(&num2, low, names, ch, file);
500
			ch = get_number(&num2, low, names, ch, file, "/, \t\n");
555
			if (ch == EOF)
501
			if (ch == EOF || num1 > num2)
556
				return EOF;
502
				return (EOF);
557
		}
503
		}
558
	}
504
	}
559
505
Lines 564-579 Link Here
564
		 */
510
		 */
565
		ch = get_char(file);
511
		ch = get_char(file);
566
		if (ch == EOF)
512
		if (ch == EOF)
567
			return EOF;
513
			return (EOF);
568
514
569
		/* get the step size -- note: we don't pass the
515
		/* get the step size -- note: we don't pass the
570
		 * names here, because the number is not an
516
		 * names here, because the number is not an
571
		 * element id, it's a step size.  'low' is
517
		 * element id, it's a step size.  'low' is
572
		 * sent as a 0 since there is no offset either.
518
		 * sent as a 0 since there is no offset either.
573
		 */
519
		 */
574
		ch = get_number(&num3, 0, PPC_NULL, ch, file);
520
		ch = get_number(&num3, 0, PPC_NULL, ch, file, ", \t\n");
575
		if (ch == EOF || num3 == 0)
521
		if (ch == EOF || num3 == 0)
576
			return EOF;
522
			return (EOF);
577
	} else {
523
	} else {
578
		/* no step.  default==1.
524
		/* no step.  default==1.
579
		 */
525
		 */
Lines 583-667 Link Here
583
	/* range. set all elements from num1 to num2, stepping
529
	/* range. set all elements from num1 to num2, stepping
584
	 * by num3.  (the step is a downward-compatible extension
530
	 * by num3.  (the step is a downward-compatible extension
585
	 * proposed conceptually by bob@acornrc, syntactically
531
	 * proposed conceptually by bob@acornrc, syntactically
586
	 * designed then implmented by paul vixie).
532
	 * designed then implemented by paul vixie).
587
	 */
533
	 */
588
	for (i = num1;  i <= num2;  i += num3)
534
	for (i = num1;  i <= num2;  i += num3)
589
		if (EOF == set_element(bits, low, high, i))
535
		if (EOF == set_element(bits, low, high, i)) {
590
			return EOF;
536
			unget_char(ch, file);
537
			return (EOF);
538
		}
591
539
592
	return ch;
540
	return (ch);
593
}
541
}
594
542
543
static int
544
get_number(int *numptr, int low, const char *names[], int ch, FILE *file,
545
    const char *terms) {
546
	char temp[MAX_TEMPSTR], *pc;
547
	int len, i;
595
548
596
static char
597
get_number(numptr, low, names, ch, file)
598
	int	*numptr;	/* where does the result go? */
599
	int	low;		/* offset applied to result if symbolic enum used */
600
	char	*names[];	/* symbolic names, if any, for enums */
601
	int	ch;		/* current character */
602
	FILE	*file;		/* source */
603
{
604
	char	temp[MAX_TEMPSTR], *pc;
605
	int	len, i, all_digits;
606
607
	/* collect alphanumerics into our fixed-size temp array
608
	 */
609
	pc = temp;
549
	pc = temp;
610
	len = 0;
550
	len = 0;
611
	all_digits = TRUE;
612
	while (isalnum(ch)) {
613
		if (++len >= MAX_TEMPSTR)
614
			return EOF;
615
551
552
	/* first look for a number */
553
	while (isdigit((unsigned char)ch)) {
554
		if (++len >= MAX_TEMPSTR)
555
			goto bad;
616
		*pc++ = ch;
556
		*pc++ = ch;
617
618
		if (!isdigit(ch))
619
			all_digits = FALSE;
620
621
		ch = get_char(file);
557
		ch = get_char(file);
622
	}
558
	}
623
	*pc = '\0';
559
	*pc = '\0';
624
	if (len == 0)
560
	if (len != 0) {
625
	    return (EOF);
561
		/* got a number, check for valid terminator */
562
		if (!strchr(terms, ch))
563
			goto bad;
564
		*numptr = atoi(temp);
565
		return (ch);
566
	}
626
567
627
	/* try to find the name in the name list
568
	/* no numbers, look for a string if we have any */
628
	 */
629
	if (names) {
569
	if (names) {
630
		for (i = 0;  names[i] != NULL;  i++) {
570
		while (isalpha((unsigned char)ch)) {
631
			Debug(DPARS|DEXT,
571
			if (++len >= MAX_TEMPSTR)
632
				("get_num, compare(%s,%s)\n", names[i], temp))
572
				goto bad;
633
			if (!strcasecmp(names[i], temp)) {
573
			*pc++ = ch;
634
				*numptr = i+low;
574
			ch = get_char(file);
635
				return ch;
575
		}
576
		*pc = '\0';
577
		if (len != 0 && strchr(terms, ch)) {
578
			for (i = 0;  names[i] != NULL;  i++) {
579
				Debug(DPARS|DEXT,
580
					("get_num, compare(%s,%s)\n", names[i],
581
					temp))
582
				if (!strcasecmp(names[i], temp)) {
583
					*numptr = i+low;
584
					return (ch);
585
				}
636
			}
586
			}
637
		}
587
		}
638
	}
588
	}
639
589
640
	/* no name list specified, or there is one and our string isn't
590
bad:
641
	 * in it.  either way: if it's all digits, use its magnitude.
591
	unget_char(ch, file);
642
	 * otherwise, it's an error.
592
	return (EOF);
643
	 */
644
	if (all_digits) {
645
		*numptr = atoi(temp);
646
		return ch;
647
	}
648
649
	return EOF;
650
}
593
}
651
594
652
653
static int
595
static int
654
set_element(bits, low, high, number)
596
set_element(bitstr_t *bits, int low, int high, int number) {
655
	bitstr_t	*bits; 		/* one bit per flag, default=FALSE */
656
	int		low;
657
	int		high;
658
	int		number;
659
{
660
	Debug(DPARS|DEXT, ("set_element(?,%d,%d,%d)\n", low, high, number))
597
	Debug(DPARS|DEXT, ("set_element(?,%d,%d,%d)\n", low, high, number))
661
598
662
	if (number < low || number > high)
599
	if (number < low || number > high)
663
		return EOF;
600
		return (EOF);
664
601
665
	bit_set(bits, (number-low));
602
	bit_set(bits, (number-low));
666
	return OK;
603
	return (OK);
667
}
604
}
(-)cron/lib/env.c (-116 / +97 lines)
Lines 1-95 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
20
 */
17
21
18
#if !defined(lint) && !defined(LINT)
22
//#if !defined(lint) && !defined(LINT)
19
static const char rcsid[] =
23
//static char rcsid[] = "$Id: env.c,v 1.10 2004/01/23 18:56:42 vixie Exp $";
20
  "$FreeBSD: head/usr.sbin/cron/lib/env.c 110638 2003-02-10 11:20:58Z thomas $";
24
//#endif
21
#endif
22
23
25
24
#include "cron.h"
26
#include "cron.h"
25
27
26
27
char **
28
char **
28
env_init()
29
env_init(void) {
29
{
30
	char **p = (char **) malloc(sizeof(char **));
30
	register char	**p = (char **) malloc(sizeof(char *));
31
31
32
	if (p)
32
	if (p != NULL)
33
		p[0] = NULL;
33
		p[0] = NULL;
34
	return (p);
34
	return (p);
35
}
35
}
36
36
37
38
void
37
void
39
env_free(envp)
38
env_free(char **envp) {
40
	char	**envp;
39
	char **p;
41
{
42
	char	**p;
43
40
44
	if ((p = envp))
41
	for (p = envp; *p != NULL; p++)
45
	    for (;  *p;  p++)
46
		free(*p);
42
		free(*p);
47
	free(envp);
43
	free(envp);
48
}
44
}
49
45
50
51
char **
46
char **
52
env_copy(envp)
47
env_copy(char **envp) {
53
	register char	**envp;
48
	int count, i, save_errno;
54
{
49
	char **p;
55
	register int	count, i;
50
56
	register char	**p;
51
	for (count = 0; envp[count] != NULL; count++)
57
52
		NULL;
58
	for (count = 0;  envp[count] != NULL;  count++)
53
	p = (char **) malloc((count+1) * sizeof(char *));  /* 1 for the NULL */
59
		;
54
	if (p != NULL) {
60
	p = (char **) malloc((count+1) * sizeof(char *)); /* 1 for the NULL */
55
		for (i = 0; i < count; i++)
61
	if (p == NULL) {
56
			if ((p[i] = strdup(envp[i])) == NULL) {
62
		errno = ENOMEM;
57
				save_errno = errno;
63
		return NULL;
58
				while (--i >= 0)
59
					free(p[i]);
60
				free(p);
61
				errno = save_errno;
62
				return (NULL);
63
			}
64
		p[count] = NULL;
64
	}
65
	}
65
	for (i = 0;  i < count;  i++)
66
		if ((p[i] = strdup(envp[i])) == NULL) {
67
			while (--i >= 0)
68
				(void) free(p[i]);
69
			free(p);
70
			errno = ENOMEM;
71
			return NULL;
72
		}
73
	p[count] = NULL;
74
	return (p);
66
	return (p);
75
}
67
}
76
68
77
78
char **
69
char **
79
env_set(envp, envstr)
70
env_set(char **envp, char *envstr) {
80
	char	**envp;
71
	int count, found;
81
	char	*envstr;
72
	char **p, *envtmp;
82
{
83
	register int	count, found;
84
	register char	**p;
85
	char		*q;
86
73
87
	/*
74
	/*
88
	 * count the number of elements, including the null pointer;
75
	 * count the number of elements, including the null pointer;
89
	 * also set 'found' to -1 or index of entry if already in here.
76
	 * also set 'found' to -1 or index of entry if already in here.
90
	 */
77
	 */
91
	found = -1;
78
	found = -1;
92
	for (count = 0;  envp[count] != NULL;  count++) {
79
	for (count = 0; envp[count] != NULL; count++) {
93
		if (!strcmp_until(envp[count], envstr, '='))
80
		if (!strcmp_until(envp[count], envstr, '='))
94
			found = count;
81
			found = count;
95
	}
82
	}
Lines 100-113 Link Here
100
		 * it exists already, so just free the existing setting,
87
		 * it exists already, so just free the existing setting,
101
		 * save our new one there, and return the existing array.
88
		 * save our new one there, and return the existing array.
102
		 */
89
		 */
103
		q = envp[found];
90
		if ((envtmp = strdup(envstr)) == NULL)
104
		if ((envp[found] = strdup(envstr)) == NULL) {
91
			return (NULL);
105
			envp[found] = q;
92
		free(envp[found]);
106
			/* XXX env_free(envp); */
93
		envp[found] = envtmp;
107
			errno = ENOMEM;
108
			return NULL;
109
		}
110
		free(q);
111
		return (envp);
94
		return (envp);
112
	}
95
	}
113
96
Lines 116-162 Link Here
116
	 * one, save our string over the old null pointer, and return resized
99
	 * one, save our string over the old null pointer, and return resized
117
	 * array.
100
	 * array.
118
	 */
101
	 */
102
	if ((envtmp = strdup(envstr)) == NULL)
103
		return (NULL);
119
	p = (char **) realloc((void *) envp,
104
	p = (char **) realloc((void *) envp,
120
			      (unsigned) ((count+1) * sizeof(char *)));
105
			      (size_t) ((count+1) * sizeof(char **)));
121
	if (p == NULL) 	{
106
	if (p == NULL) {
122
		/* XXX env_free(envp); */
107
		free(envtmp);
123
		errno = ENOMEM;
108
		return (NULL);
124
		return NULL;
125
	}
109
	}
126
	p[count] = p[count-1];
110
	p[count] = p[count-1];
127
	if ((p[count-1] = strdup(envstr)) == NULL) {
111
	p[count-1] = envtmp;
128
		env_free(p);
129
		errno = ENOMEM;
130
		return NULL;
131
	}
132
	return (p);
112
	return (p);
133
}
113
}
134
114
115
/* The following states are used by load_env(), traversed in order: */
116
enum env_state {
117
	NAMEI,		/* First char of NAME, may be quote */
118
	NAME,		/* Subsequent chars of NAME */
119
	EQ1,		/* After end of name, looking for '=' sign */
120
	EQ2,		/* After '=', skipping whitespace */
121
	VALUEI,		/* First char of VALUE, may be quote */
122
	VALUE,		/* Subsequent chars of VALUE */
123
	FINI,		/* All done, skipping trailing whitespace */
124
	ERROR,		/* Error */
125
};
135
126
136
/* return	ERR = end of file
127
/* return	ERR = end of file
137
 *		FALSE = not an env setting (file was repositioned)
128
 *		FALSE = not an env setting (file was repositioned)
138
 *		TRUE = was an env setting
129
 *		TRUE = was an env setting
139
 */
130
 */
140
int
131
int
141
load_env(envstr, f)
132
load_env(char *envstr, FILE *f) {
142
	char	*envstr;
133
	long filepos;
143
	FILE	*f;
134
	int fileline;
144
{
135
	enum env_state state;
145
	long	filepos;
136
	char name[MAX_ENVSTR], val[MAX_ENVSTR];
146
	int	fileline;
137
	char quotechar, *c, *str;
147
	char	name[MAX_ENVSTR], val[MAX_ENVSTR];
148
	char	quotechar, *c, *str;
149
	int	state;
150
151
	/* The following states are traversed in order: */
152
#define NAMEI	0	/* First char of NAME, may be quote */
153
#define NAME	1	/* Subsequent chars of NAME */
154
#define EQ1	2	/* After end of name, looking for '=' sign */
155
#define EQ2	3	/* After '=', skipping whitespace */
156
#define VALUEI	4	/* First char of VALUE, may be quote */
157
#define VALUE	5	/* Subsequent chars of VALUE */
158
#define FINI	6	/* All done, skipping trailing whitespace */
159
#define ERROR	7	/* Error */
160
138
161
	filepos = ftell(f);
139
	filepos = ftell(f);
162
	fileline = LineNumber;
140
	fileline = LineNumber;
Lines 164-173 Link Here
164
	if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
142
	if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
165
		return (ERR);
143
		return (ERR);
166
144
167
	Debug(DPARS, ("load_env, read <%s>\n", envstr));
145
	Debug(DPARS, ("load_env, read <%s>\n", envstr))
168
146
169
	bzero (name, sizeof name);
147
	bzero(name, sizeof name);
170
	bzero (val, sizeof val);
148
	bzero(val, sizeof val);
171
	str = name;
149
	str = name;
172
	state = NAMEI;
150
	state = NAMEI;
173
	quotechar = '\0';
151
	quotechar = '\0';
Lines 178-184 Link Here
178
		case VALUEI:
156
		case VALUEI:
179
			if (*c == '\'' || *c == '"')
157
			if (*c == '\'' || *c == '"')
180
				quotechar = *c++;
158
				quotechar = *c++;
181
			++state;
159
			state++;
182
			/* FALLTHROUGH */
160
			/* FALLTHROUGH */
183
		case NAME:
161
		case NAME:
184
		case VALUE:
162
		case VALUE:
Lines 194-200 Link Here
194
				}
172
				}
195
			} else {
173
			} else {
196
				if (state == NAME) {
174
				if (state == NAME) {
197
					if (isspace (*c)) {
175
					if (isspace((unsigned char)*c)) {
198
						c++;
176
						c++;
199
						state++;
177
						state++;
200
						break;
178
						break;
Lines 214-265 Link Here
214
				str = val;
192
				str = val;
215
				quotechar = '\0';
193
				quotechar = '\0';
216
			} else {
194
			} else {
217
				if (!isspace (*c))
195
				if (!isspace((unsigned char)*c))
218
					state = ERROR;
196
					state = ERROR;
219
			}
197
			}
220
			c++;
198
			c++;
221
			break;
199
			break;
200
222
		case EQ2:
201
		case EQ2:
223
		case FINI:
202
		case FINI:
224
			if (isspace (*c))
203
			if (isspace((unsigned char)*c))
225
				c++;
204
				c++;
226
			else
205
			else
227
				state++;
206
				state++;
228
			break;
207
			break;
208
209
		default:
210
			abort();
229
		}
211
		}
230
	}
212
	}
231
	if (state != FINI && !(state == VALUE && !quotechar)) {
213
	if (state != FINI && !(state == VALUE && !quotechar)) {
232
		Debug(DPARS, ("load_env, parse error, state = %d\n", state))
214
		Debug(DPARS, ("load_env, not an env var, state = %d\n", state))
233
		fseek(f, filepos, 0);
215
		fseek(f, filepos, 0);
234
		Set_LineNum(fileline);
216
		Set_LineNum(fileline);
235
		return (FALSE);
217
		return (FALSE);
236
	}
218
	}
237
	if (state == VALUE) {
219
	if (state == VALUE) {
238
		/* End of unquoted value: trim trailing whitespace */
220
		/* End of unquoted value: trim trailing whitespace */
239
		c = val + strlen (val);
221
		c = val + strlen(val);
240
		while (c > val && isspace (*(c - 1)))
222
		while (c > val && isspace((unsigned char)c[-1]))
241
			*(--c) = '\0';
223
			*(--c) = '\0';
242
	}
224
	}
243
225
244
	/* 2 fields from parser; looks like an env setting */
226
	/* 2 fields from parser; looks like an env setting */
245
227
246
	if (strlen(name) + 1 + strlen(val) >= MAX_ENVSTR-1)
228
	/*
229
	 * This can't overflow because get_string() limited the size of the
230
	 * name and val fields.  Still, it doesn't hurt to be careful...
231
	 */
232
	if (!glue_strings(envstr, MAX_ENVSTR, name, val, '='))
247
		return (FALSE);
233
		return (FALSE);
248
	(void) sprintf(envstr, "%s=%s", name, val);
249
	Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
234
	Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
250
	return (TRUE);
235
	return (TRUE);
251
}
236
}
252
237
253
254
char *
238
char *
255
env_get(name, envp)
239
env_get(char *name, char **envp) {
256
	register char	*name;
240
	int len = strlen(name);
257
	register char	**envp;
241
	char *p, *q;
258
{
259
	register int	len = strlen(name);
260
	register char	*p, *q;
261
242
262
	while ((p = *envp++)) {
243
	while ((p = *envp++) != NULL) {
263
		if (!(q = strchr(p, '=')))
244
		if (!(q = strchr(p, '=')))
264
			continue;
245
			continue;
265
		if ((q - p) == len && !strncmp(p, name, len))
246
		if ((q - p) == len && !strncmp(p, name, len))
(-)cron/lib/misc.c (-250 / +389 lines)
Lines 1-63 Link Here
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
1
/* Copyright 1988,1990,1993,1994 by Paul Vixie
2
 * All rights reserved
2
 * All rights reserved
3
 */
4
5
/*
6
 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1997,2000 by Internet Software Consortium, Inc.
3
 *
8
 *
4
 * Distribute freely, except: don't remove my name from the source or
9
 * Permission to use, copy, modify, and distribute this software for any
5
 * documentation (don't take credit for my work), mark your changes (don't
10
 * purpose with or without fee is hereby granted, provided that the above
6
 * get me blamed for your possible bugs), don't alter or remove this
11
 * copyright notice and this permission notice appear in all copies.
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
 *
12
 *
13
 * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14
 * I'll try to keep a version up to date.  I can be reached as follows:
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
15
 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19
 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16