xref: /illumos-gate/usr/src/cmd/cron/cron.c (revision bbf21555)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54c4c9110Sbasabi  * Common Development and Distribution License (the "License").
64c4c9110Sbasabi  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d1419d5aSNobutomo Nakano  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2442c141d3SJoshua M. Clulow  *
2542c141d3SJoshua M. Clulow  * Copyright 2013 Joshua M. Clulow <josh@sysmgr.org>
26ee169c7eSGary Mills  *
27ee169c7eSGary Mills  * Copyright (c) 2014 Gary Mills
2848bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
296b734416SAndy Fiddaman  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
30618372bcSSebastian Wiedenroth  * Copyright 2022 Sebastian Wiedenroth
317c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
3419803d09SToomas Soome /*	  All Rights Reserved	*/
367c478bd9Sstevel@tonic-gate /*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
377c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
397c478bd9Sstevel@tonic-gate #include <sys/contract/process.h>
407c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
417c478bd9Sstevel@tonic-gate #include <sys/param.h>
427c478bd9Sstevel@tonic-gate #include <sys/resource.h>
437c478bd9Sstevel@tonic-gate #include <sys/stat.h>
447c478bd9Sstevel@tonic-gate #include <sys/task.h>
457c478bd9Sstevel@tonic-gate #include <sys/time.h>
467c478bd9Sstevel@tonic-gate #include <sys/types.h>
477c478bd9Sstevel@tonic-gate #include <sys/utsname.h>
487c478bd9Sstevel@tonic-gate #include <sys/wait.h>
507c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
527c478bd9Sstevel@tonic-gate #include <alloca.h>
537c478bd9Sstevel@tonic-gate #include <ctype.h>
547c478bd9Sstevel@tonic-gate #include <deflt.h>
557c478bd9Sstevel@tonic-gate #include <dirent.h>
567c478bd9Sstevel@tonic-gate #include <errno.h>
577c478bd9Sstevel@tonic-gate #include <fcntl.h>
587c478bd9Sstevel@tonic-gate #include <grp.h>
597c478bd9Sstevel@tonic-gate #include <libcontract.h>
607c478bd9Sstevel@tonic-gate #include <libcontract_priv.h>
617c478bd9Sstevel@tonic-gate #include <limits.h>
627c478bd9Sstevel@tonic-gate #include <locale.h>
637c478bd9Sstevel@tonic-gate #include <poll.h>
647c478bd9Sstevel@tonic-gate #include <project.h>
657c478bd9Sstevel@tonic-gate #include <pwd.h>
667c478bd9Sstevel@tonic-gate #include <signal.h>
677c478bd9Sstevel@tonic-gate #include <stdarg.h>
687c478bd9Sstevel@tonic-gate #include <stdio.h>
697c478bd9Sstevel@tonic-gate #include <stdlib.h>
707c478bd9Sstevel@tonic-gate #include <string.h>
717c478bd9Sstevel@tonic-gate #include <stropts.h>
727c478bd9Sstevel@tonic-gate #include <time.h>
737c478bd9Sstevel@tonic-gate #include <unistd.h>
745b08e637SChris Gerhard #include <libzoneinfo.h>
767c478bd9Sstevel@tonic-gate #include "cron.h"
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * #define	DEBUG
807c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate #define	MAIL		"/usr/bin/mail"	/* mail program to use */
837c478bd9Sstevel@tonic-gate #define	CONSOLE		"/dev/console"	/* where messages go when cron dies */
857c478bd9Sstevel@tonic-gate #define	TMPINFILE	"/tmp/crinXXXXXX"  /* file to put stdin in for cmd  */
867c478bd9Sstevel@tonic-gate #define	TMPDIR		"/tmp"
877c478bd9Sstevel@tonic-gate #define	PFX		"crout"
887c478bd9Sstevel@tonic-gate #define	TMPOUTFILE	"/tmp/croutXXXXXX" /* file to place stdout, stderr */
907c478bd9Sstevel@tonic-gate #define	INMODE		00400		/* mode for stdin file	*/
917c478bd9Sstevel@tonic-gate #define	OUTMODE		00600		/* mode for stdout file */
927c478bd9Sstevel@tonic-gate #define	ISUID		S_ISUID		/* mode for verifing at jobs */
947c478bd9Sstevel@tonic-gate #define	INFINITY	2147483647L	/* upper bound on time	*/
957c478bd9Sstevel@tonic-gate #define	CUSHION		180L
967c478bd9Sstevel@tonic-gate #define	ZOMB		100		/* proc slot used for mailing output */
987c478bd9Sstevel@tonic-gate #define	JOBF		'j'
997c478bd9Sstevel@tonic-gate #define	NICEF		'n'
1007c478bd9Sstevel@tonic-gate #define	USERF		'u'
1017c478bd9Sstevel@tonic-gate #define	WAITF		'w'
1037c478bd9Sstevel@tonic-gate #define	BCHAR		'>'
1047c478bd9Sstevel@tonic-gate #define	ECHAR		'<'
1067c478bd9Sstevel@tonic-gate #define	DEFAULT		0
1077c478bd9Sstevel@tonic-gate #define	LOAD		1
1087c478bd9Sstevel@tonic-gate #define	QBUFSIZ		80
1107c478bd9Sstevel@tonic-gate /* Defined actions for crabort() routine */
1117c478bd9Sstevel@tonic-gate #define	NO_ACTION	000
1127c478bd9Sstevel@tonic-gate #define	REMOVE_FIFO	001
1137c478bd9Sstevel@tonic-gate #define	CONSOLE_MSG	002
1157c478bd9Sstevel@tonic-gate #define	BADCD		"can't change directory to the crontab directory."
1167c478bd9Sstevel@tonic-gate #define	NOREADDIR	"can't read the crontab directory."
1187c478bd9Sstevel@tonic-gate #define	BADJOBOPEN	"unable to read your at job."
1197c478bd9Sstevel@tonic-gate #define	BADSHELL	"because your login shell \
1207c478bd9Sstevel@tonic-gate isn't /usr/bin/sh, you can't use cron."
1224c4c9110Sbasabi #define	BADSTAT		"can't access your crontab or at-job file. Resubmit it."
1237c478bd9Sstevel@tonic-gate #define	BADPROJID	"can't set project id for your job."
1245b08e637SChris Gerhard #define	CANTCDHOME	"can't change directory to %s.\
1257c478bd9Sstevel@tonic-gate \nYour commands will not be executed."
1265b08e637SChris Gerhard #define	CANTEXECSH	"unable to exec the shell, %s, for one of your \
1275b08e637SChris Gerhard commands."
1285b08e637SChris Gerhard #define	CANT_STR_LEN (sizeof (CANTEXECSH) > sizeof (CANTCDHOME) ? \
1295b08e637SChris Gerhard 	sizeof (CANTEXECSH) : sizeof (CANTCDHOME))
1307c478bd9Sstevel@tonic-gate #define	NOREAD		"can't read your crontab file.  Resubmit it."
1314c4c9110Sbasabi #define	BADTYPE		"crontab or at-job file is not a regular file.\n"
1327c478bd9Sstevel@tonic-gate #define	NOSTDIN		"unable to create a standard input file for \
1337c478bd9Sstevel@tonic-gate one of your crontab commands. \
1347c478bd9Sstevel@tonic-gate \nThat command was not executed."
1367c478bd9Sstevel@tonic-gate #define	NOTALLOWED	"you are not authorized to use cron.  Sorry."
1377c478bd9Sstevel@tonic-gate #define	STDERRMSG	"\n\n********************************************\
1387c478bd9Sstevel@tonic-gate *****\nCron: The previous message is the \
1397c478bd9Sstevel@tonic-gate standard output and standard error \
1407c478bd9Sstevel@tonic-gate \nof one of your cron commands.\n"
1427c478bd9Sstevel@tonic-gate #define	STDOUTERR	"one of your commands generated output or errors, \
1437c478bd9Sstevel@tonic-gate but cron was unable to mail you this output.\
1447c478bd9Sstevel@tonic-gate \nRemember to redirect standard output and standard \
1457c478bd9Sstevel@tonic-gate error for each of your commands."
1477c478bd9Sstevel@tonic-gate #define	CLOCK_DRIFT	"clock time drifted backwards after event!\n"
1487c478bd9Sstevel@tonic-gate #define	PIDERR		"unexpected pid returned %d (ignored)"
1497c478bd9Sstevel@tonic-gate #define	CRONTABERR	"Subject: Your crontab file has an error in it\n\n"
1507c478bd9Sstevel@tonic-gate #define	MALLOCERR	"out of space, cannot create new string\n"
1527c478bd9Sstevel@tonic-gate #define	DIDFORK didfork
1537c478bd9Sstevel@tonic-gate #define	NOFORK !didfork
1557c478bd9Sstevel@tonic-gate #define	MAILBUFLEN	(8*1024)
1567c478bd9Sstevel@tonic-gate #define	LINELIMIT	80
1577c478bd9Sstevel@tonic-gate #define	MAILBINITFREE	(MAILBUFLEN - (sizeof (cte_intro) - 1) \
1587c478bd9Sstevel@tonic-gate 	    - (sizeof (cte_trail1) - 1) - (sizeof (cte_trail2) - 1) - 1)
1607c478bd9Sstevel@tonic-gate #define	ERR_CRONTABENT	0	/* error in crontab file entry */
1617c478bd9Sstevel@tonic-gate #define	ERR_UNIXERR	1	/* error in some system call */
1627c478bd9Sstevel@tonic-gate #define	ERR_CANTEXECCRON 2	/* error setting up "cron" job environment */
1637c478bd9Sstevel@tonic-gate #define	ERR_CANTEXECAT	3	/* error setting up "at" job environment */
1644c4c9110Sbasabi #define	ERR_NOTREG	4	/* error not a regular file */
1667c478bd9Sstevel@tonic-gate #define	PROJECT		"project="
1687c478bd9Sstevel@tonic-gate #define	MAX_LOST_CONTRACTS	2048	/* reset if this many failed abandons */
1707c478bd9Sstevel@tonic-gate #define	FORMAT	"%a %b %e %H:%M:%S %Y"
1717c478bd9Sstevel@tonic-gate static char	timebuf[80];
173d1419d5aSNobutomo Nakano static struct message msgbuf;
174d1419d5aSNobutomo Nakano 
1755b08e637SChris Gerhard struct shared {
1765b08e637SChris Gerhard 	int count;			/* usage count */
1775b08e637SChris Gerhard 	void (*free)(void *obj);	/* routine that will free obj */
1785b08e637SChris Gerhard 	void *obj;			/* object */
1795b08e637SChris Gerhard };
1805b08e637SChris Gerhard 
1817c478bd9Sstevel@tonic-gate struct event {
1827c478bd9Sstevel@tonic-gate 	time_t time;	/* time of the event	*/
1837c478bd9Sstevel@tonic-gate 	short etype;	/* what type of event; 0=cron, 1=at	*/
1847c478bd9Sstevel@tonic-gate 	char *cmd;	/* command for cron, job name for at	*/
1857c478bd9Sstevel@tonic-gate 	struct usr *u;	/* ptr to the owner (usr) of this event	*/
1867c478bd9Sstevel@tonic-gate 	struct event *link;	/* ptr to another event for this user */
1877c478bd9Sstevel@tonic-gate 	union {
1887c478bd9Sstevel@tonic-gate 		struct { /* for crontab events */
1897c478bd9Sstevel@tonic-gate 			char *minute;	/*  (these	*/
1907c478bd9Sstevel@tonic-gate 			char *hour;	/*   fields	*/
1917c478bd9Sstevel@tonic-gate 			char *daymon;	/*   are	*/
1927c478bd9Sstevel@tonic-gate 			char *month;	/*   from	*/
1937c478bd9Sstevel@tonic-gate 			char *dayweek;	/*   crontab)	*/
1947c478bd9Sstevel@tonic-gate 			char *input;	/* ptr to stdin	*/
1955b08e637SChris Gerhard 			struct shared *tz;	/* timezone of this event */
1965b08e637SChris Gerhard 			struct shared *home;	/* directory for this event */
1975b08e637SChris Gerhard 			struct shared *shell;	/* shell for this event */
198618372bcSSebastian Wiedenroth 			uint32_t max_random_delay;	/* max. random delay */
1997c478bd9Sstevel@tonic-gate 		} ct;
2007c478bd9Sstevel@tonic-gate 		struct { /* for at events */
2017c478bd9Sstevel@tonic-gate 			short exists;	/* for revising at events	*/
2027c478bd9Sstevel@tonic-gate 			int eventid;	/* for el_remove-ing at events	*/
2037c478bd9Sstevel@tonic-gate 		} at;
2047c478bd9Sstevel@tonic-gate 	} of;
2057c478bd9Sstevel@tonic-gate };
2077c478bd9Sstevel@tonic-gate struct usr {
2087c478bd9Sstevel@tonic-gate 	char *name;	/* name of user (e.g. "root")	*/
2097c478bd9Sstevel@tonic-gate 	char *home;	/* home directory for user	*/
2107c478bd9Sstevel@tonic-gate 	uid_t uid;	/* user id	*/
2117c478bd9Sstevel@tonic-gate 	gid_t gid;	/* group id	*/
2127c478bd9Sstevel@tonic-gate 	int aruncnt;	/* counter for running jobs per uid */
2137c478bd9Sstevel@tonic-gate 	int cruncnt;	/* counter for running cron jobs per uid */
2147c478bd9Sstevel@tonic-gate 	int ctid;	/* for el_remove-ing crontab events */
2157c478bd9Sstevel@tonic-gate 	short ctexists;	/* for revising crontab events	*/
2167c478bd9Sstevel@tonic-gate 	struct event *ctevents;	/* list of this usr's crontab events */
2177c478bd9Sstevel@tonic-gate 	struct event *atevents;	/* list of this usr's at events */
2187c478bd9Sstevel@tonic-gate 	struct usr *nextusr;
2197c478bd9Sstevel@tonic-gate };	/* ptr to next user	*/
2217c478bd9Sstevel@tonic-gate static struct	queue
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	int njob;	/* limit */
2247c478bd9Sstevel@tonic-gate 	int nice;	/* nice for execution */
2257c478bd9Sstevel@tonic-gate 	int nwait;	/* wait time to next execution attempt */
2267c478bd9Sstevel@tonic-gate 	int nrun;	/* number running */
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate 	qd = {100, 2, 60},		/* default values for queue defs */
2297c478bd9Sstevel@tonic-gate 	qt[NQUEUE];
2307c478bd9Sstevel@tonic-gate static struct	queue	qq;
2329f163834Sbasabi static struct runinfo
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	pid_t	pid;
2357c478bd9Sstevel@tonic-gate 	short	que;
2367c478bd9Sstevel@tonic-gate 	struct  usr *rusr;	/* pointer to usr struct */
2377c478bd9Sstevel@tonic-gate 	char	*outfile;	/* file where stdout & stderr are trapped */
2387c478bd9Sstevel@tonic-gate 	short	jobtype;	/* what type of event: 0=cron, 1=at */
2397c478bd9Sstevel@tonic-gate 	char	*jobname;	/* command for "cron", jobname for "at" */
2407c478bd9Sstevel@tonic-gate 	int	mailwhendone;	/* 1 = send mail even if no ouptut */
2419f163834Sbasabi 	struct runinfo *next;
2429f163834Sbasabi }	*rthead;
2447c478bd9Sstevel@tonic-gate static struct miscpid {
2457c478bd9Sstevel@tonic-gate 	pid_t		pid;
2467c478bd9Sstevel@tonic-gate 	struct miscpid	*next;
2477c478bd9Sstevel@tonic-gate }	*miscpid_head;
2497c478bd9Sstevel@tonic-gate static pid_t cron_pid;	/* own pid */
2507c478bd9Sstevel@tonic-gate static char didfork = 0; /* flag to see if I'm process group leader */
2517c478bd9Sstevel@tonic-gate static int msgfd;	/* file descriptor for fifo queue */
2527c478bd9Sstevel@tonic-gate static int ecid = 1;	/* event class id for el_remove(); MUST be set to 1 */
2537c478bd9Sstevel@tonic-gate static int delayed;	/* is job being rescheduled or did it run first time */
2547c478bd9Sstevel@tonic-gate static int cwd;		/* current working directory */
2557c478bd9Sstevel@tonic-gate static struct event *next_event;	/* the next event to execute	*/
2567c478bd9Sstevel@tonic-gate static struct usr *uhead;		/* ptr to the list of users	*/
2587c478bd9Sstevel@tonic-gate /* Variables for error handling at reading crontabs. */
2597c478bd9Sstevel@tonic-gate static char cte_intro[] = "Line(s) with errors:\n\n";
2607c478bd9Sstevel@tonic-gate static char cte_trail1[] = "\nMax number of errors encountered.";
2617c478bd9Sstevel@tonic-gate static char cte_trail2[] = " Evaluation of crontab aborted.\n";
2627c478bd9Sstevel@tonic-gate static int cte_free = MAILBINITFREE;	/* Free buffer space */
2637c478bd9Sstevel@tonic-gate static char *cte_text = NULL;		/* Text buffer pointer */
2647c478bd9Sstevel@tonic-gate static char *cte_lp;			/* Next free line in cte_text */
2657c478bd9Sstevel@tonic-gate static int cte_nvalid;			/* Valid lines found */
2677c478bd9Sstevel@tonic-gate /* user's default environment for the shell */
2687c478bd9Sstevel@tonic-gate #define	ROOTPATH	"PATH=/usr/sbin:/usr/bin"
2697c478bd9Sstevel@tonic-gate #define	NONROOTPATH	"PATH=/usr/bin:"
2717c478bd9Sstevel@tonic-gate static char *Def_supath	= NULL;
2727c478bd9Sstevel@tonic-gate static char *Def_path		= NULL;
2737c478bd9Sstevel@tonic-gate static char path[LINE_MAX]	= "PATH=";
2747c478bd9Sstevel@tonic-gate static char supath[LINE_MAX]	= "PATH=";
2755b08e637SChris Gerhard static char homedir[LINE_MAX]	= ENV_HOME;
2767c478bd9Sstevel@tonic-gate static char logname[LINE_MAX]	= "LOGNAME=";
2775b08e637SChris Gerhard static char tzone[LINE_MAX]	= ENV_TZ;
2787c478bd9Sstevel@tonic-gate static char *envinit[] = {
2797c478bd9Sstevel@tonic-gate 	homedir,
2807c478bd9Sstevel@tonic-gate 	logname,
2817c478bd9Sstevel@tonic-gate 	ROOTPATH,
2827c478bd9Sstevel@tonic-gate 	"SHELL=/usr/bin/sh",
2837c478bd9Sstevel@tonic-gate 	tzone,
2847c478bd9Sstevel@tonic-gate 	NULL
2857c478bd9Sstevel@tonic-gate };
2877c478bd9Sstevel@tonic-gate extern char **environ;
2897c478bd9Sstevel@tonic-gate #define	DEFTZ		"GMT"
2907c478bd9Sstevel@tonic-gate static	int	log = 0;
2917c478bd9Sstevel@tonic-gate static	char	hzname[10];
2937c478bd9Sstevel@tonic-gate static void cronend(int);
2947c478bd9Sstevel@tonic-gate static void thaw_handler(int);
2957c478bd9Sstevel@tonic-gate static void child_handler(int);
2967c478bd9Sstevel@tonic-gate static void child_sigreset(void);
2987c478bd9Sstevel@tonic-gate static void mod_ctab(char *, time_t);
2997c478bd9Sstevel@tonic-gate static void mod_atjob(char *, time_t);
3007c478bd9Sstevel@tonic-gate static void add_atevent(struct usr *, char *, time_t, int);
3017c478bd9Sstevel@tonic-gate static void rm_ctevents(struct usr *);
3027c478bd9Sstevel@tonic-gate static void cleanup(struct runinfo *rn, int r);
3037c478bd9Sstevel@tonic-gate static void crabort(char *, int);
3047c478bd9Sstevel@tonic-gate static void msg(char *fmt, ...);
305e2553d68SSerge Dussud static void ignore_msg(char *, char *, struct event *);
3067c478bd9Sstevel@tonic-gate static void logit(int, struct runinfo *, int);
3077c478bd9Sstevel@tonic-gate static void parsqdef(char *);
3087c478bd9Sstevel@tonic-gate static void defaults();
3097c478bd9Sstevel@tonic-gate static void initialize(int);
3107c478bd9Sstevel@tonic-gate static void quedefs(int);
3117c478bd9Sstevel@tonic-gate static int idle(long);
3127c478bd9Sstevel@tonic-gate static struct usr *find_usr(char *);
3137c478bd9Sstevel@tonic-gate static int ex(struct event *e);
3144c4c9110Sbasabi static void read_dirs(int);
3157c478bd9Sstevel@tonic-gate static void mail(char *, char *, int);
3167c478bd9Sstevel@tonic-gate static void readcron(struct usr *, time_t);
3177c478bd9Sstevel@tonic-gate static int next_ge(int, char *);
3187c478bd9Sstevel@tonic-gate static void free_if_unused(struct usr *);
3197c478bd9Sstevel@tonic-gate static void del_atjob(char *, char *);
3207c478bd9Sstevel@tonic-gate static void del_ctab(char *);
3217c478bd9Sstevel@tonic-gate static void resched(int);
3227c478bd9Sstevel@tonic-gate static int msg_wait(long);
3237c478bd9Sstevel@tonic-gate static struct runinfo *rinfo_get(pid_t);
3247c478bd9Sstevel@tonic-gate static void rinfo_free(struct runinfo *rp);
3257c478bd9Sstevel@tonic-gate static void mail_result(struct usr *p, struct runinfo *pr, size_t filesize);
3267c478bd9Sstevel@tonic-gate static time_t next_time(struct event *, time_t);
3277c478bd9Sstevel@tonic-gate static time_t get_switching_time(int, time_t);
3287c478bd9Sstevel@tonic-gate static time_t xmktime(struct tm *);
3297c478bd9Sstevel@tonic-gate static void process_msg(struct message *, time_t);
3307c478bd9Sstevel@tonic-gate static void reap_child(void);
3317c478bd9Sstevel@tonic-gate static void miscpid_insert(pid_t);
3327c478bd9Sstevel@tonic-gate static int miscpid_delete(pid_t);
333032624d5Sbasabi static void contract_set_template(void);
334032624d5Sbasabi static void contract_clear_template(void);
3357c478bd9Sstevel@tonic-gate static void contract_abandon_latest(pid_t);
3377c478bd9Sstevel@tonic-gate static void cte_init(void);
3387c478bd9Sstevel@tonic-gate static void cte_add(int, char *);
3397c478bd9Sstevel@tonic-gate static void cte_valid(void);
3407c478bd9Sstevel@tonic-gate static int cte_istoomany(void);
3417c478bd9Sstevel@tonic-gate static void cte_sendmail(char *);
3437c478bd9Sstevel@tonic-gate static int set_user_cred(const struct usr *, struct project *);
3455b08e637SChris Gerhard static struct shared *create_shared_str(char *str);
3465b08e637SChris Gerhard static struct shared *dup_shared(struct shared *obj);
3475b08e637SChris Gerhard static void rel_shared(struct shared *obj);
3485b08e637SChris Gerhard static void *get_obj(struct shared *obj);
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  * last_time is set immediately prior to exection of an event (via ex())
3517c478bd9Sstevel@tonic-gate  * to indicate the last time an event was executed.  This was (surely)
3527c478bd9Sstevel@tonic-gate  * it's original intended use.
3537c478bd9Sstevel@tonic-gate  */
3547c478bd9Sstevel@tonic-gate static time_t last_time, init_time, t_old;
355*bbf21555SRichard Lowe static int reset_needed; /* set to 1 when cron(8) needs to re-initialize */
357d1419d5aSNobutomo Nakano static int		refresh;
358d1419d5aSNobutomo Nakano static sigset_t		defmask, sigmask;
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate  * BSM hooks
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate extern int	audit_cron_session(char *, char *, uid_t, gid_t, char *);
3647c478bd9Sstevel@tonic-gate extern void	audit_cron_new_job(char *, int, void *);
3657c478bd9Sstevel@tonic-gate extern void	audit_cron_bad_user(char *);
3667c478bd9Sstevel@tonic-gate extern void	audit_cron_user_acct_expired(char *);
3677c478bd9Sstevel@tonic-gate extern int	audit_cron_create_anc_file(char *, char *, char *, uid_t);
3687c478bd9Sstevel@tonic-gate extern int	audit_cron_delete_anc_file(char *, char *);
3697c478bd9Sstevel@tonic-gate extern int	audit_cron_is_anc_name(char *);
3707c478bd9Sstevel@tonic-gate extern int	audit_cron_mode();
3727c478bd9Sstevel@tonic-gate static int cron_conv(int, struct pam_message **,
3737c478bd9Sstevel@tonic-gate 		struct pam_response **, void *);
3757c478bd9Sstevel@tonic-gate static struct pam_conv pam_conv = {cron_conv, NULL};
3767c478bd9Sstevel@tonic-gate static pam_handle_t *pamh;	/* Authentication handle */
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate  * Function to help check a user's credentials.
3807c478bd9Sstevel@tonic-gate  */
3824c4c9110Sbasabi static int verify_user_cred(struct usr *u);
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * Values returned by verify_user_cred and set_user_cred:
3867c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate #define	VUC_OK		0
3897c478bd9Sstevel@tonic-gate #define	VUC_BADUSER	1
3907c478bd9Sstevel@tonic-gate #define	VUC_NOTINGROUP	2
3917c478bd9Sstevel@tonic-gate #define	VUC_EXPIRED	3
3927c478bd9Sstevel@tonic-gate #define	VUC_NEW_AUTH	4
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate  * Modes of process_anc_files function
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate #define	CRON_ANC_DELETE	1
3987c478bd9Sstevel@tonic-gate #define	CRON_ANC_CREATE	0
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * Functions to remove a user or job completely from the running database.
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate static void clean_out_atjobs(struct usr *u);
4047c478bd9Sstevel@tonic-gate static void clean_out_ctab(struct usr *u);
4057c478bd9Sstevel@tonic-gate static void clean_out_user(struct usr *u);
4067c478bd9Sstevel@tonic-gate static void cron_unlink(char *name);
4077c478bd9Sstevel@tonic-gate static void process_anc_files(int);
4097c478bd9Sstevel@tonic-gate /*
4107c478bd9Sstevel@tonic-gate  * functions in elm.c
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate extern void el_init(int, time_t, time_t, int);
413e2553d68SSerge Dussud extern int el_add(void *, time_t, int);
4147c478bd9Sstevel@tonic-gate extern void el_remove(int, int);
4157c478bd9Sstevel@tonic-gate extern int el_empty(void);
4167c478bd9Sstevel@tonic-gate extern void *el_first(void);
4177c478bd9Sstevel@tonic-gate extern void el_delete(void);
4194c4c9110Sbasabi static int valid_entry(char *, int);
4204c4c9110Sbasabi static struct usr *create_ulist(char *, int);
4214c4c9110Sbasabi static void init_cronevent(char *, int);
4224c4c9110Sbasabi static void init_atevent(char *, time_t, int, int);
4234c4c9110Sbasabi static void update_atevent(struct usr *, char *, time_t, int);
4257c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])4267c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
4277c478bd9Sstevel@tonic-gate {
4287c478bd9Sstevel@tonic-gate 	time_t t;
4297c478bd9Sstevel@tonic-gate 	time_t ne_time;		/* amt of time until next event execution */
4307c478bd9Sstevel@tonic-gate 	time_t newtime, lastmtime = 0L;
4317c478bd9Sstevel@tonic-gate 	struct usr *u;
4327c478bd9Sstevel@tonic-gate 	struct event *e, *e2, *eprev;
4337c478bd9Sstevel@tonic-gate 	struct stat buf;
4347c478bd9Sstevel@tonic-gate 	pid_t rfork;
4357c478bd9Sstevel@tonic-gate 	struct sigaction act;
4377c478bd9Sstevel@tonic-gate 	/*
438e2553d68SSerge Dussud 	 * reset_needed is set to 1 whenever el_add() finds out that a cron
439*bbf21555SRichard Lowe 	 * job is scheduled to be run before the time when cron(8) daemon
440e2553d68SSerge Dussud 	 * initialized.
441e2553d68SSerge Dussud 	 * Other cases where a reset is needed is when ex() finds that the
442e2553d68SSerge Dussud 	 * event to be executed is being run at the wrong time, or when idle()
443e2553d68SSerge Dussud 	 * determines that time was reset.
4447c478bd9Sstevel@tonic-gate 	 * We immediately return to the top of the while (TRUE) loop in
445e2553d68SSerge Dussud 	 * main() where the event list is cleared and rebuilt, and reset_needed
4467c478bd9Sstevel@tonic-gate 	 * is set back to 0.
4477c478bd9Sstevel@tonic-gate 	 */
448e2553d68SSerge Dussud 	reset_needed = 0;
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * Only the privileged user can run this command.
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	if (getuid() != 0)
4547c478bd9Sstevel@tonic-gate 		crabort(NOTALLOWED, 0);
4567c478bd9Sstevel@tonic-gate begin:
4577c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
4587c478bd9Sstevel@tonic-gate 	/* fork unless 'nofork' is specified */
4597c478bd9Sstevel@tonic-gate 	if ((argc <= 1) || (strcmp(argv[1], "nofork"))) {
4606b734416SAndy Fiddaman 		if ((rfork = fork()) != 0) {
4617c478bd9Sstevel@tonic-gate 			if (rfork == (pid_t)-1) {
4627c478bd9Sstevel@tonic-gate 				(void) sleep(30);
4637c478bd9Sstevel@tonic-gate 				goto begin;
4647c478bd9Sstevel@tonic-gate 			}
4657c478bd9Sstevel@tonic-gate 			return (0);
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 		didfork++;
4687c478bd9Sstevel@tonic-gate 		(void) setpgrp();	/* detach cron from console */
4697c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 	(void) umask(022);
4727c478bd9Sstevel@tonic-gate 	(void) signal(SIGHUP, SIG_IGN);
4737c478bd9Sstevel@tonic-gate 	(void) signal(SIGINT, SIG_IGN);
4747c478bd9Sstevel@tonic-gate 	(void) signal(SIGQUIT, SIG_IGN);
4757c478bd9Sstevel@tonic-gate 	(void) signal(SIGTERM, cronend);
4777c478bd9Sstevel@tonic-gate 	defaults();
4787c478bd9Sstevel@tonic-gate 	initialize(1);
4797c478bd9Sstevel@tonic-gate 	quedefs(DEFAULT);	/* load default queue definitions */
4807c478bd9Sstevel@tonic-gate 	cron_pid = getpid();
4817c478bd9Sstevel@tonic-gate 	msg("*** cron started ***   pid = %d", cron_pid);
482d1419d5aSNobutomo Nakano 
483d1419d5aSNobutomo Nakano 	/* setup THAW handler */
484d1419d5aSNobutomo Nakano 	act.sa_handler = thaw_handler;
485d1419d5aSNobutomo Nakano 	act.sa_flags = 0;
486d1419d5aSNobutomo Nakano 	(void) sigemptyset(&act.sa_mask);
487d1419d5aSNobutomo Nakano 	(void) sigaction(SIGTHAW, &act, NULL);
488d1419d5aSNobutomo Nakano 
489d1419d5aSNobutomo Nakano 	/* setup CHLD handler */
4907c478bd9Sstevel@tonic-gate 	act.sa_handler = child_handler;
4917c478bd9Sstevel@tonic-gate 	act.sa_flags = 0;
4927c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
4937c478bd9Sstevel@tonic-gate 	(void) sigaddset(&act.sa_mask, SIGCLD);
4947c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGCLD, &act, NULL);
496d1419d5aSNobutomo Nakano 	(void) sigemptyset(&defmask);
497d1419d5aSNobutomo Nakano 	(void) sigemptyset(&sigmask);
498d1419d5aSNobutomo Nakano 	(void) sigaddset(&sigmask, SIGCLD);
499d1419d5aSNobutomo Nakano 	(void) sigaddset(&sigmask, SIGTHAW);
500d1419d5aSNobutomo Nakano 	(void) sigprocmask(SIG_BLOCK, &sigmask, NULL);
502e2553d68SSerge Dussud 	t_old = init_time;
5037c478bd9Sstevel@tonic-gate 	last_time = t_old;
5047c478bd9Sstevel@tonic-gate 	for (;;) {		/* MAIN LOOP */
5057c478bd9Sstevel@tonic-gate 		t = time(NULL);
506e2553d68SSerge Dussud 		if ((t_old > t) || (t-last_time > CUSHION) || reset_needed) {
507e2553d68SSerge Dussud 			reset_needed = 0;
508d1419d5aSNobutomo Nakano 			/*
509d1419d5aSNobutomo Nakano 			 * the time was set backwards or forward or
510d1419d5aSNobutomo Nakano 			 * refresh is requested.
511d1419d5aSNobutomo Nakano 			 */
512d1419d5aSNobutomo Nakano 			if (refresh)
513d1419d5aSNobutomo Nakano 				msg("re-scheduling jobs");
514d1419d5aSNobutomo Nakano 			else
515d1419d5aSNobutomo Nakano 				msg("time was reset, re-initializing");
5167c478bd9Sstevel@tonic-gate 			el_delete();
5177c478bd9Sstevel@tonic-gate 			u = uhead;
5187c478bd9Sstevel@tonic-gate 			while (u != NULL) {
5197c478bd9Sstevel@tonic-gate 				rm_ctevents(u);
5207c478bd9Sstevel@tonic-gate 				e = u->atevents;
5217c478bd9Sstevel@tonic-gate 				while (e != NULL) {
5227c478bd9Sstevel@tonic-gate 					free(e->cmd);
5237c478bd9Sstevel@tonic-gate 					e2 = e->link;
5247c478bd9Sstevel@tonic-gate 					free(e);
5257c478bd9Sstevel@tonic-gate 					e = e2;
5267c478bd9Sstevel@tonic-gate 				}
5277c478bd9Sstevel@tonic-gate 				u->atevents = NULL;
5287c478bd9Sstevel@tonic-gate 				u = u->nextusr;
5297c478bd9Sstevel@tonic-gate 			}
5307c478bd9Sstevel@tonic-gate 			(void) close(msgfd);
5317c478bd9Sstevel@tonic-gate 			initialize(0);
5327c478bd9Sstevel@tonic-gate 			t = time(NULL);
5337c478bd9Sstevel@tonic-gate 			last_time = t;
534e2553d68SSerge Dussud 			/*
535e2553d68SSerge Dussud 			 * reset_needed might have been set in the functions
536e2553d68SSerge Dussud 			 * call path from initialize()
537e2553d68SSerge Dussud 			 */
538e2553d68SSerge Dussud 			if (reset_needed) {
539e2553d68SSerge Dussud 				continue;
540e2553d68SSerge Dussud 			}
5417c478bd9Sstevel@tonic-gate 		}
5427c478bd9Sstevel@tonic-gate 		t_old = t;
5447c478bd9Sstevel@tonic-gate 		if (next_event == NULL && !el_empty()) {
5457c478bd9Sstevel@tonic-gate 			next_event = (struct event *)el_first();
5467c478bd9Sstevel@tonic-gate 		}
5477c478bd9Sstevel@tonic-gate 		if (next_event == NULL) {
5487c478bd9Sstevel@tonic-gate 			ne_time = INFINITY;
5497c478bd9Sstevel@tonic-gate 		} else {
5507c478bd9Sstevel@tonic-gate 			ne_time = next_event->time - t;
5517c478bd9Sstevel@tonic-gate #ifdef DEBUG
552ee169c7eSGary Mills 			cftime(timebuf, "%+", &next_event->time);
5537c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "next_time=%ld %s\n",
5544c4c9110Sbasabi 			    next_event->time, timebuf);
5557c478bd9Sstevel@tonic-gate #endif
5567c478bd9Sstevel@tonic-gate 		}
5577c478bd9Sstevel@tonic-gate 		if (ne_time > 0) {
558e2553d68SSerge Dussud 			/*
559e2553d68SSerge Dussud 			 * reset_needed may be set in the functions call path
560e2553d68SSerge Dussud 			 * from idle()
561e2553d68SSerge Dussud 			 */
562e2553d68SSerge Dussud 			if (idle(ne_time) || reset_needed) {
563e2553d68SSerge Dussud 				reset_needed = 1;
5647c478bd9Sstevel@tonic-gate 				continue;
565e2553d68SSerge Dussud 			}
5667c478bd9Sstevel@tonic-gate 		}
5687c478bd9Sstevel@tonic-gate 		if (stat(QUEDEFS, &buf)) {
5697c478bd9Sstevel@tonic-gate 			msg("cannot stat QUEDEFS file");
5707c478bd9Sstevel@tonic-gate 		} else if (lastmtime != buf.st_mtime) {
5717c478bd9Sstevel@tonic-gate 			quedefs(LOAD);
5727c478bd9Sstevel@tonic-gate 			lastmtime = buf.st_mtime;
5737c478bd9Sstevel@tonic-gate 		}
5757c478bd9Sstevel@tonic-gate 		last_time = next_event->time; /* save execution time */
577e2553d68SSerge Dussud 		/*
578e2553d68SSerge Dussud 		 * reset_needed may be set in the functions call path
579e2553d68SSerge Dussud 		 * from ex()
580e2553d68SSerge Dussud 		 */
581e2553d68SSerge Dussud 		if (ex(next_event) || reset_needed) {
582e2553d68SSerge Dussud 			reset_needed = 1;
5837c478bd9Sstevel@tonic-gate 			continue;
584e2553d68SSerge Dussud 		}
5867c478bd9Sstevel@tonic-gate 		switch (next_event->etype) {
5877c478bd9Sstevel@tonic-gate 		case CRONEVENT:
5887c478bd9Sstevel@tonic-gate 			/* add cronevent back into the main event list */
5897c478bd9Sstevel@tonic-gate 			if (delayed) {
5907c478bd9Sstevel@tonic-gate 				delayed = 0;
5917c478bd9Sstevel@tonic-gate 				break;
5927c478bd9Sstevel@tonic-gate 			}
5947c478bd9Sstevel@tonic-gate 			/*
5957c478bd9Sstevel@tonic-gate 			 * check if time(0)< last_time. if so, then the
5967c478bd9Sstevel@tonic-gate 			 * system clock has gone backwards. to prevent this
5977c478bd9Sstevel@tonic-gate 			 * job from being started twice, we reschedule this
5987c478bd9Sstevel@tonic-gate 			 * job for the >>next time after last_time<<, and
5997c478bd9Sstevel@tonic-gate 			 * then set next_event->time to this. note that
6007c478bd9Sstevel@tonic-gate 			 * crontab's resolution is 1 minute.
6017c478bd9Sstevel@tonic-gate 			 */
6037c478bd9Sstevel@tonic-gate 			if (last_time > time(NULL)) {
6047c478bd9Sstevel@tonic-gate 				msg(CLOCK_DRIFT);
6057c478bd9Sstevel@tonic-gate 				/*
6067c478bd9Sstevel@tonic-gate 				 * bump up to next 30 second
6077c478bd9Sstevel@tonic-gate 				 * increment
6087c478bd9Sstevel@tonic-gate 				 * 1 <= newtime <= 30
6097c478bd9Sstevel@tonic-gate 				 */
6107c478bd9Sstevel@tonic-gate 				newtime = 30 - (last_time % 30);
6117c478bd9Sstevel@tonic-gate 				newtime += last_time;
6137c478bd9Sstevel@tonic-gate 				/*
6147c478bd9Sstevel@tonic-gate 				 * get the next scheduled event,
6157c478bd9Sstevel@tonic-gate 				 * not the one that we just
6167c478bd9Sstevel@tonic-gate 				 * kicked off!
6177c478bd9Sstevel@tonic-gate 				 */
6187c478bd9Sstevel@tonic-gate 				next_event->time =
6194c4c9110Sbasabi 				    next_time(next_event, newtime);
6207c478bd9Sstevel@tonic-gate 				t_old = time(NULL);
6217c478bd9Sstevel@tonic-gate 			} else {
6227c478bd9Sstevel@tonic-gate 				next_event->time =
6234c4c9110Sbasabi 				    next_time(next_event, (time_t)0);
6247c478bd9Sstevel@tonic-gate 			}
6257c478bd9Sstevel@tonic-gate #ifdef DEBUG
626ee169c7eSGary Mills 			cftime(timebuf, "%+", &next_event->time);
6277c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr,
6284c4c9110Sbasabi 			    "pushing back cron event %s at %ld (%s)\n",
6294c4c9110Sbasabi 			    next_event->cmd, next_event->time, timebuf);
6307c478bd9Sstevel@tonic-gate #endif
632e2553d68SSerge Dussud 			switch (el_add(next_event, next_event->time,
633e2553d68SSerge Dussud 			    (next_event->u)->ctid)) {
634e2553d68SSerge Dussud 			case -1:
635e2553d68SSerge Dussud 				ignore_msg("main", "cron", next_event);
636e2553d68SSerge Dussud 				break;
637e2553d68SSerge Dussud 			case -2: /* event time lower than init time */
638e2553d68SSerge Dussud 				reset_needed = 1;
639e2553d68SSerge Dussud 				break;
640e2553d68SSerge Dussud 			}
6417c478bd9Sstevel@tonic-gate 			break;
6427c478bd9Sstevel@tonic-gate 		default:
6437c478bd9Sstevel@tonic-gate 			/* remove at or batch job from system */
6447c478bd9Sstevel@tonic-gate 			if (delayed) {
6457c478bd9Sstevel@tonic-gate 				delayed = 0;
6467c478bd9Sstevel@tonic-gate 				break;
6477c478bd9Sstevel@tonic-gate 			}
6487c478bd9Sstevel@tonic-gate 			eprev = NULL;
6497c478bd9Sstevel@tonic-gate 			e = (next_event->u)->atevents;
6507c478bd9Sstevel@tonic-gate 			while (e != NULL) {
6517c478bd9Sstevel@tonic-gate 				if (e == next_event) {
6527c478bd9Sstevel@tonic-gate 					if (eprev == NULL)
6537c478bd9Sstevel@tonic-gate 						(e->u)->atevents = e->link;
6547c478bd9Sstevel@tonic-gate 					else
6557c478bd9Sstevel@tonic-gate 						eprev->link = e->link;
6567c478bd9Sstevel@tonic-gate 					free(e->cmd);
6577c478bd9Sstevel@tonic-gate 					free(e);
6587c478bd9Sstevel@tonic-gate 					break;
6597c478bd9Sstevel@tonic-gate 				} else {
6607c478bd9Sstevel@tonic-gate 					eprev = e;
6617c478bd9Sstevel@tonic-gate 					e = e->link;
6627c478bd9Sstevel@tonic-gate 				}
6637c478bd9Sstevel@tonic-gate 			}
6647c478bd9Sstevel@tonic-gate 			break;
6657c478bd9Sstevel@tonic-gate 		}
6667c478bd9Sstevel@tonic-gate 		next_event = NULL;
6677c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
6707c478bd9Sstevel@tonic-gate }
6727c478bd9Sstevel@tonic-gate static void
initialize(int firstpass)6737c478bd9Sstevel@tonic-gate initialize(int firstpass)
6747c478bd9Sstevel@tonic-gate {
6757c478bd9Sstevel@tonic-gate #ifdef DEBUG
6767c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "in initialize\n");
6777c478bd9Sstevel@tonic-gate #endif
6787c478bd9Sstevel@tonic-gate 	if (firstpass) {
6797c478bd9Sstevel@tonic-gate 		/* for mail(1), make sure messages come from root */
6807c478bd9Sstevel@tonic-gate 		if (putenv("LOGNAME=root") != 0) {
6817c478bd9Sstevel@tonic-gate 			crabort("cannot expand env variable",
6824c4c9110Sbasabi 			    REMOVE_FIFO|CONSOLE_MSG);
6837c478bd9Sstevel@tonic-gate 		}
6847c478bd9Sstevel@tonic-gate 		if (access(FIFO, R_OK) == -1) {
6857c478bd9Sstevel@tonic-gate 			if (errno == ENOENT) {
6867c478bd9Sstevel@tonic-gate 				if (mknod(FIFO, S_IFIFO|0600, 0) != 0)
6877c478bd9Sstevel@tonic-gate 					crabort("cannot create fifo queue",
6884c4c9110Sbasabi 					    REMOVE_FIFO|CONSOLE_MSG);
6897c478bd9Sstevel@tonic-gate 			} else {
6907c478bd9Sstevel@tonic-gate 				if (NOFORK) {
691*bbf21555SRichard Lowe 					/* didn't fork... init(8) is waiting */
6927c478bd9Sstevel@tonic-gate 					(void) sleep(60);
6937c478bd9Sstevel@tonic-gate 				}
6947c478bd9Sstevel@tonic-gate 				perror("FIFO");
6957c478bd9Sstevel@tonic-gate 				crabort("cannot access fifo queue",
6964c4c9110Sbasabi 				    REMOVE_FIFO|CONSOLE_MSG);
6977c478bd9Sstevel@tonic-gate 			}
6987c478bd9Sstevel@tonic-gate 		} else {
6997c478bd9Sstevel@tonic-gate 			if (NOFORK) {
700*bbf21555SRichard Lowe 				/* didn't fork... init(8) is waiting */
7017c478bd9Sstevel@tonic-gate 				(void) sleep(60);
7027c478bd9Sstevel@tonic-gate 				/*
7037c478bd9Sstevel@tonic-gate 				 * the wait is painful, but we don't want
7047c478bd9Sstevel@tonic-gate 				 * init respawning this quickly
7057c478bd9Sstevel@tonic-gate 				 */
7067c478bd9Sstevel@tonic-gate 			}
7077c478bd9Sstevel@tonic-gate 			crabort("cannot start cron; FIFO exists", CONSOLE_MSG);
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 	if ((msgfd = open(FIFO, O_RDWR)) < 0) {
7127c478bd9Sstevel@tonic-gate 		perror("! open");
7137c478bd9Sstevel@tonic-gate 		crabort("cannot open fifo queue", REMOVE_FIFO|CONSOLE_MSG);
7147c478bd9Sstevel@tonic-gate 	}
716e2553d68SSerge Dussud 	init_time = time(NULL);
717e2553d68SSerge Dussud 	el_init(8, init_time, (time_t)(60*60*24), 10);
718e2553d68SSerge Dussud 
7195b08e637SChris Gerhard 	init_time = time(NULL);
7205b08e637SChris Gerhard 	el_init(8, init_time, (time_t)(60*60*24), 10);
7215b08e637SChris Gerhard 
7227c478bd9Sstevel@tonic-gate 	/*
7237c478bd9Sstevel@tonic-gate 	 * read directories, create users list, and add events to the
7247c478bd9Sstevel@tonic-gate 	 * main event list. Only zero user list on firstpass.
7257c478bd9Sstevel@tonic-gate 	 */
7267c478bd9Sstevel@tonic-gate 	if (firstpass)
7277c478bd9Sstevel@tonic-gate 		uhead = NULL;
7284c4c9110Sbasabi 	read_dirs(firstpass);
7297c478bd9Sstevel@tonic-gate 	next_event = NULL;
7317c478bd9Sstevel@tonic-gate 	if (!firstpass)
7327c478bd9Sstevel@tonic-gate 		return;
7347c478bd9Sstevel@tonic-gate 	/* stdout is log file */
7357c478bd9Sstevel@tonic-gate 	if (freopen(ACCTFILE, "a", stdout) == NULL)
7367c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "cannot open %s\n", ACCTFILE);
7387c478bd9Sstevel@tonic-gate 	/* log should be root-only */
7397c478bd9Sstevel@tonic-gate 	(void) fchmod(1, S_IRUSR|S_IWUSR);
7417c478bd9Sstevel@tonic-gate 	/* stderr also goes to ACCTFILE */
7427c478bd9Sstevel@tonic-gate 	(void) close(fileno(stderr));
7437c478bd9Sstevel@tonic-gate 	(void) dup(1);
7447c478bd9Sstevel@tonic-gate 	/* null for stdin */
7457c478bd9Sstevel@tonic-gate 	(void) freopen("/dev/null", "r", stdin);
7477c478bd9Sstevel@tonic-gate 	contract_set_template();
7487c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate static void
read_dirs(int first)7514c4c9110Sbasabi read_dirs(int first)
7527c478bd9Sstevel@tonic-gate {
7534c4c9110Sbasabi 	DIR		*dir;
7544c4c9110Sbasabi 	struct dirent	*dp;
7554c4c9110Sbasabi 	char		*ptr;
7564c4c9110Sbasabi 	int		jobtype;
7574c4c9110Sbasabi 	time_t		tim;
7607c478bd9Sstevel@tonic-gate 	if (chdir(CRONDIR) == -1)
7617c478bd9Sstevel@tonic-gate 		crabort(BADCD, REMOVE_FIFO|CONSOLE_MSG);
7627c478bd9Sstevel@tonic-gate 	cwd = CRON;
7637c478bd9Sstevel@tonic-gate 	if ((dir = opendir(".")) == NULL)
7647c478bd9Sstevel@tonic-gate 		crabort(NOREADDIR, REMOVE_FIFO|CONSOLE_MSG);
7654c4c9110Sbasabi 	while ((dp = readdir(dir)) != NULL) {
7664c4c9110Sbasabi 		if (!valid_entry(dp->d_name, CRONEVENT))
7674c4c9110Sbasabi 			continue;
7684c4c9110Sbasabi 		init_cronevent(dp->d_name, first);
7694c4c9110Sbasabi 	}
7707c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
7727c478bd9Sstevel@tonic-gate 	if (chdir(ATDIR) == -1) {
7737c478bd9Sstevel@tonic-gate 		msg("cannot chdir to at directory");
7747c478bd9Sstevel@tonic-gate 		return;
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 	if ((dir = opendir(".")) == NULL) {
7777c478bd9Sstevel@tonic-gate 		msg("cannot read at at directory");
7787c478bd9Sstevel@tonic-gate 		return;
7797c478bd9Sstevel@tonic-gate 	}
7804c4c9110Sbasabi 	cwd = AT;
7814c4c9110Sbasabi 	while ((dp = readdir(dir)) != NULL) {
7824c4c9110Sbasabi 		if (!valid_entry(dp->d_name, ATEVENT))
7834c4c9110Sbasabi 			continue;
7844c4c9110Sbasabi 		ptr = dp->d_name;
7854c4c9110Sbasabi 		if (((tim = num(&ptr)) == 0) || (*ptr != '.'))
7864c4c9110Sbasabi 			continue;
7874c4c9110Sbasabi 		ptr++;
7884c4c9110Sbasabi 		if (!isalpha(*ptr))
7894c4c9110Sbasabi 			continue;
7904c4c9110Sbasabi 		jobtype = *ptr - 'a';
7914c4c9110Sbasabi 		if (jobtype >= NQUEUE) {
7924c4c9110Sbasabi 			cron_unlink(dp->d_name);
7934c4c9110Sbasabi 			continue;
7944c4c9110Sbasabi 		}
7954c4c9110Sbasabi 		init_atevent(dp->d_name, tim, jobtype, first);
7964c4c9110Sbasabi 	}
7977c478bd9Sstevel@tonic-gate 	(void) closedir(dir);
7987c478bd9Sstevel@tonic-gate }
8004c4c9110Sbasabi static int
valid_entry(char * name,int type)8014c4c9110Sbasabi valid_entry(char *name, int type)
8027c478bd9Sstevel@tonic-gate {
8034c4c9110Sbasabi 	struct stat	buf;
8054c4c9110Sbasabi 	if (strcmp(name, ".") == 0 ||
8064c4c9110Sbasabi 	    strcmp(name, "..") == 0)
8074c4c9110Sbasabi 		return (0);
8094c4c9110Sbasabi 	/* skip over ancillary file names */
8104c4c9110Sbasabi 	if (audit_cron_is_anc_name(name))
8114c4c9110Sbasabi 		return (0);
8134c4c9110Sbasabi 	if (stat(name, &buf)) {
8144c4c9110Sbasabi 		mail(name, BADSTAT, ERR_UNIXERR);
8154c4c9110Sbasabi 		cron_unlink(name);
8164c4c9110Sbasabi 		return (0);
8174c4c9110Sbasabi 	}
8184c4c9110Sbasabi 	if (!S_ISREG(buf.st_mode)) {
8194c4c9110Sbasabi 		mail(name, BADTYPE, ERR_NOTREG);
8204c4c9110Sbasabi 		cron_unlink(name);
8214c4c9110Sbasabi 		return (0);
8224c4c9110Sbasabi 	}
8234c4c9110Sbasabi 	if (type == ATEVENT) {
8244c4c9110Sbasabi 		if (!(buf.st_mode & ISUID)) {
8254c4c9110Sbasabi 			cron_unlink(name);
8264c4c9110Sbasabi 			return (0);
8274c4c9110Sbasabi 		}
8284c4c9110Sbasabi 	}
8294c4c9110Sbasabi 	return (1);
8304c4c9110Sbasabi }
8324c4c9110Sbasabi struct usr *
create_ulist(char * name,int type)8334c4c9110Sbasabi create_ulist(char *name, int type)
8344c4c9110Sbasabi {
8354c4c9110Sbasabi 	struct usr	*u;
837d1419d5aSNobutomo Nakano 	u = xcalloc(1, sizeof (struct usr));
838d1419d5aSNobutomo Nakano 	u->name = xstrdup(name);
8394c4c9110Sbasabi 	if (type == CRONEVENT) {
8404c4c9110Sbasabi 		u->ctexists = TRUE;
8414c4c9110Sbasabi 		u->ctid = ecid++;
8424c4c9110Sbasabi 	} else {
8434c4c9110Sbasabi 		u->ctexists = FALSE;
8444c4c9110Sbasabi 		u->ctid = 0;
8454c4c9110Sbasabi 	}
846d1419d5aSNobutomo Nakano 	u->uid = (uid_t)-1;
847d1419d5aSNobutomo Nakano 	u->gid = (uid_t)-1;
8484c4c9110Sbasabi 	u->nextusr = uhead;
8494c4c9110Sbasabi 	uhead = u;
8504c4c9110Sbasabi 	return (u);
8514c4c9110Sbasabi }
8534c4c9110Sbasabi void
init_cronevent(char * name,int first)8544c4c9110Sbasabi init_cronevent(char *name, int first)
8554c4c9110Sbasabi {
8564c4c9110Sbasabi 	struct usr	*u;
8584c4c9110Sbasabi 	if (first) {
8594c4c9110Sbasabi 		u = create_ulist(name, CRONEVENT);
8604c4c9110Sbasabi 		readcron(u, 0);
8614c4c9110Sbasabi 	} else {
8624c4c9110Sbasabi 		if ((u = find_usr(name)) == NULL) {
8634c4c9110Sbasabi 			u = create_ulist(name, CRONEVENT);
8644c4c9110Sbasabi 			readcron(u, 0);
8654c4c9110Sbasabi 		} else {
8664c4c9110Sbasabi 			u->ctexists = TRUE;
8674c4c9110Sbasabi 			rm_ctevents(u);
8684c4c9110Sbasabi 			el_remove(u->ctid, 0);
8694c4c9110Sbasabi 			readcron(u, 0);
8704c4c9110Sbasabi 		}
8714c4c9110Sbasabi 	}
8724c4c9110Sbasabi }
8744c4c9110Sbasabi void
init_atevent(char * name,time_t tim,int jobtype,int first)8754c4c9110Sbasabi init_atevent(char *name, time_t tim, int jobtype, int first)
8764c4c9110Sbasabi {
8774c4c9110Sbasabi 	struct usr	*u;
8794c4c9110Sbasabi 	if (first) {
8804c4c9110Sbasabi 		u = create_ulist(name, ATEVENT);
8814c4c9110Sbasabi 		add_atevent(u, name, tim, jobtype);
8824c4c9110Sbasabi 	} else {
8834c4c9110Sbasabi 		if ((u = find_usr(name)) == NULL) {
8844c4c9110Sbasabi 			u = create_ulist(name, ATEVENT);
8854c4c9110Sbasabi 			add_atevent(u, name, tim, jobtype);
8864c4c9110Sbasabi 		} else {
8874c4c9110Sbasabi 			update_atevent(u, name, tim, jobtype);
8887c478bd9Sstevel@tonic-gate 		}
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate static void
mod_ctab(char * name,time_t reftime)8937c478bd9Sstevel@tonic-gate mod_ctab(char *name, time_t reftime)
8947c478bd9Sstevel@tonic-gate {
8957c478bd9Sstevel@tonic-gate 	struct	passwd	*pw;
8967c478bd9Sstevel@tonic-gate 	struct	stat	buf;
8977c478bd9Sstevel@tonic-gate 	struct	usr	*u;
8985b08e637SChris Gerhard 	char	namebuf[LINE_MAX];
8997c478bd9Sstevel@tonic-gate 	char	*pname;
9017c478bd9Sstevel@tonic-gate 	/* skip over ancillary file names */
9027c478bd9Sstevel@tonic-gate 	if (audit_cron_is_anc_name(name))
9037c478bd9Sstevel@tonic-gate 		return;
9057c478bd9Sstevel@tonic-gate 	if ((pw = getpwnam(name)) == NULL) {
9067c478bd9Sstevel@tonic-gate 		msg("No such user as %s - cron entries not created", name);
9077c478bd9Sstevel@tonic-gate 		return;
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 	if (cwd != CRON) {
9107c478bd9Sstevel@tonic-gate 		if (snprintf(namebuf, sizeof (namebuf), "%s/%s",
9114c4c9110Sbasabi 		    CRONDIR, name) >= sizeof (namebuf)) {
9127c478bd9Sstevel@tonic-gate 			msg("Too long path name %s - cron entries not created",
9134c4c9110Sbasabi 			    namebuf);
9147c478bd9Sstevel@tonic-gate 			return;
9157c478bd9Sstevel@tonic-gate 		}
9167c478bd9Sstevel@tonic-gate 		pname = namebuf;
9177c478bd9Sstevel@tonic-gate 	} else {
9187c478bd9Sstevel@tonic-gate 		pname = name;
9197c478bd9Sstevel@tonic-gate 	}
9207c478bd9Sstevel@tonic-gate 	/*
9217c478bd9Sstevel@tonic-gate 	 * a warning message is given by the crontab command so there is
9227c478bd9Sstevel@tonic-gate 	 * no need to give one here......  use this code if you only want
9237c478bd9Sstevel@tonic-gate 	 * users with a login shell of /usr/bin/sh to use cron
9247c478bd9Sstevel@tonic-gate 	 */
9257c478bd9Sstevel@tonic-gate #ifdef BOURNESHELLONLY
9267c478bd9Sstevel@tonic-gate 	if ((strcmp(pw->pw_shell, "") != 0) &&
9277c478bd9Sstevel@tonic-gate 	    (strcmp(pw->pw_shell, SHELL) != 0)) {
9287c478bd9Sstevel@tonic-gate 		mail(name, BADSHELL, ERR_CANTEXECCRON);
9297c478bd9Sstevel@tonic-gate 		cron_unlink(pname);
9307c478bd9Sstevel@tonic-gate 		return;
9317c478bd9Sstevel@tonic-gate 	}
9327c478bd9Sstevel@tonic-gate #endif
9337c478bd9Sstevel@tonic-gate 	if (stat(pname, &buf)) {
9347c478bd9Sstevel@tonic-gate 		mail(name, BADSTAT, ERR_UNIXERR);
9357c478bd9Sstevel@tonic-gate 		cron_unlink(pname);
9367c478bd9Sstevel@tonic-gate 		return;
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 	if (!S_ISREG(buf.st_mode)) {
9397c478bd9Sstevel@tonic-gate 		mail(name, BADTYPE, ERR_CRONTABENT);
9407c478bd9Sstevel@tonic-gate 		return;
9417c478bd9Sstevel@tonic-gate 	}
9427c478bd9Sstevel@tonic-gate 	if ((u = find_usr(name)) == NULL) {
9437c478bd9Sstevel@tonic-gate #ifdef DEBUG
9447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "new user (%s) with a crontab\n", name);
9457c478bd9Sstevel@tonic-gate #endif
9464c4c9110Sbasabi 		u = create_ulist(name, CRONEVENT);
9474c4c9110Sbasabi 		u->home = xmalloc(strlen(pw->pw_dir) + 1);
9487c478bd9Sstevel@tonic-gate 		(void) strcpy(u->home, pw->pw_dir);
9497c478bd9Sstevel@tonic-gate 		u->uid = pw->pw_uid;
9507c478bd9Sstevel@tonic-gate 		u->gid = pw->pw_gid;
9517c478bd9Sstevel@tonic-gate 		readcron(u, reftime);
9527c478bd9Sstevel@tonic-gate 	} else {
9537c478bd9Sstevel@tonic-gate 		u->uid = pw->pw_uid;
9547c478bd9Sstevel@tonic-gate 		u->gid = pw->pw_gid;
955d9f27107Sbasabi 		if (u->home != NULL) {
956d9f27107Sbasabi 			if (strcmp(u->home, pw->pw_dir) != 0) {
957d9f27107Sbasabi 				free(u->home);
958d9f27107Sbasabi 				u->home = xmalloc(strlen(pw->pw_dir) + 1);
959d9f27107Sbasabi 				(void) strcpy(u->home, pw->pw_dir);
960d9f27107Sbasabi 			}
961d9f27107Sbasabi 		} else {
9624c4c9110Sbasabi 			u->home = xmalloc(strlen(pw->pw_dir) + 1);
9637c478bd9Sstevel@tonic-gate 			(void) strcpy(u->home, pw->pw_dir);
9647c478bd9Sstevel@tonic-gate 		}
9657c478bd9Sstevel@tonic-gate 		u->ctexists = TRUE;
9667c478bd9Sstevel@tonic-gate 		if (u->ctid == 0) {
9677c478bd9Sstevel@tonic-gate #ifdef DEBUG
9687c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "%s now has a crontab\n",
9697c478bd9Sstevel@tonic-gate 			    u->name);
9707c478bd9Sstevel@tonic-gate #endif
9717c478bd9Sstevel@tonic-gate 			/* user didnt have a crontab last time */
9727c478bd9Sstevel@tonic-gate 			u->ctid = ecid++;
9737c478bd9Sstevel@tonic-gate 			u->ctevents = NULL;
9747c478bd9Sstevel@tonic-gate 			readcron(u, reftime);
9757c478bd9Sstevel@tonic-gate 			return;
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate #ifdef DEBUG
9786b734416SAndy Fiddaman 		(void) fprintf(stderr, "%s has revised their crontab\n",
9796b734416SAndy Fiddaman 		    u->name);
9807c478bd9Sstevel@tonic-gate #endif
9817c478bd9Sstevel@tonic-gate 		rm_ctevents(u);
9827c478bd9Sstevel@tonic-gate 		el_remove(u->ctid, 0);
9837c478bd9Sstevel@tonic-gate 		readcron(u, reftime);
9847c478bd9Sstevel@tonic-gate 	}
9857c478bd9Sstevel@tonic-gate }
9877c478bd9Sstevel@tonic-gate static void
mod_atjob(char * name,time_t reftime __unused)9886b734416SAndy Fiddaman mod_atjob(char *name, time_t reftime __unused)
9897c478bd9Sstevel@tonic-gate {
9907c478bd9Sstevel@tonic-gate 	char	*ptr;
9917c478bd9Sstevel@tonic-gate 	time_t	tim;
9927c478bd9Sstevel@tonic-gate 	struct	passwd	*pw;
9937c478bd9Sstevel@tonic-gate 	struct	stat	buf;
9947c478bd9Sstevel@tonic-gate 	struct	usr	*u;
9957c478bd9Sstevel@tonic-gate 	char	namebuf[PATH_MAX];
9967c478bd9Sstevel@tonic-gate 	char	*pname;
9977c478bd9Sstevel@tonic-gate 	int	jobtype;
9997c478bd9Sstevel@tonic-gate 	ptr = name;
10007c478bd9Sstevel@tonic-gate 	if (((tim = num(&ptr)) == 0) || (*ptr != '.'))
10017c478bd9Sstevel@tonic-gate 		return;
10027c478bd9Sstevel@tonic-gate 	ptr++;
10037c478bd9Sstevel@tonic-gate 	if (!isalpha(*ptr))
10047c478bd9Sstevel@tonic-gate 		return;
10057c478bd9Sstevel@tonic-gate 	jobtype = *ptr - 'a';
10077c478bd9Sstevel@tonic-gate 	/* check for audit ancillary file */
10087c478bd9Sstevel@tonic-gate 	if (audit_cron_is_anc_name(name))
10097c478bd9Sstevel@tonic-gate 		return;
10117c478bd9Sstevel@tonic-gate 	if (cwd != AT) {
10127c478bd9Sstevel@tonic-gate 		if (snprintf(namebuf, sizeof (namebuf), "%s/%s", ATDIR, name)
10137c478bd9Sstevel@tonic-gate 		    >= sizeof (namebuf)) {
10147c478bd9Sstevel@tonic-gate 			return;
10157c478bd9Sstevel@tonic-gate 		}
10167c478bd9Sstevel@tonic-gate 		pname = namebuf;
10177c478bd9Sstevel@tonic-gate 	} else {
10187c478bd9Sstevel@tonic-gate 		pname = name;
10197c478bd9Sstevel@tonic-gate 	}
10207c478bd9Sstevel@tonic-gate 	if (stat(pname, &buf) || jobtype >= NQUEUE) {
10217c478bd9Sstevel@tonic-gate 		cron_unlink(pname);
10227c478bd9Sstevel@tonic-gate 		return;
10237c478bd9Sstevel@tonic-gate 	}
10247c478bd9Sstevel@tonic-gate 	if (!(buf.st_mode & ISUID) || !S_ISREG(buf.st_mode)) {
10257c478bd9Sstevel@tonic-gate 		cron_unlink(pname);
10267c478bd9Sstevel@tonic-gate 		return;
10277c478bd9Sstevel@tonic-gate 	}
10287c478bd9Sstevel@tonic-gate 	if ((pw = getpwuid(buf.st_uid)) == NULL) {
10297c478bd9Sstevel@tonic-gate 		cron_unlink(pname);
10307c478bd9Sstevel@tonic-gate 		return;
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 	/*
10337c478bd9Sstevel@tonic-gate 	 * a warning message is given by the at command so there is no
10347c478bd9Sstevel@tonic-gate 	 * need to give one here......use this code if you only want
10357c478bd9Sstevel@tonic-gate 	 * users with a login shell of /usr/bin/sh to use cron
10367c478bd9Sstevel@tonic-gate 	 */
10377c478bd9Sstevel@tonic-gate #ifdef BOURNESHELLONLY
10387c478bd9Sstevel@tonic-gate 	if ((strcmp(pw->pw_shell, "") != 0) &&
10397c478bd9Sstevel@tonic-gate 	    (strcmp(pw->pw_shell, SHELL) != 0)) {
10407c478bd9Sstevel@tonic-gate 		mail(pw->pw_name, BADSHELL, ERR_CANTEXECAT);
10417c478bd9Sstevel@tonic-gate 		cron_unlink(pname);
10427c478bd9Sstevel@tonic-gate 		return;
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate #endif
10457c478bd9Sstevel@tonic-gate 	if ((u = find_usr(pw->pw_name)) == NULL) {
10467c478bd9Sstevel@tonic-gate #ifdef DEBUG
10477c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "new user (%s) with an at job = %s\n",
10484c4c9110Sbasabi 		    pw->pw_name, name);
10497c478bd9Sstevel@tonic-gate #endif
10504c4c9110Sbasabi 		u = create_ulist(pw->pw_name, ATEVENT);
1051d1419d5aSNobutomo Nakano 		u->home = xstrdup(pw->pw_dir);
10527c478bd9Sstevel@tonic-gate 		u->uid = pw->pw_uid;
10537c478bd9Sstevel@tonic-gate 		u->gid = pw->pw_gid;
10547c478bd9Sstevel@tonic-gate 		add_atevent(u, name, tim, jobtype);
10557c478bd9Sstevel@tonic-gate 	} else {
10567c478bd9Sstevel@tonic-gate 		u->uid = pw->pw_uid;
10577c478bd9Sstevel@tonic-gate 		u->gid = pw->pw_gid;
10584c4c9110Sbasabi 		free(u->home);
1059d1419d5aSNobutomo Nakano 		u->home = xstrdup(pw->pw_dir);
10604c4c9110Sbasabi 		update_atevent(u, name, tim, jobtype);
10617c478bd9Sstevel@tonic-gate 	}
10627c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate static void
add_atevent(struct usr * u,char * job,time_t tim,int jobtype)10657c478bd9Sstevel@tonic-gate add_atevent(struct usr *u, char *job, time_t tim, int jobtype)
10667c478bd9Sstevel@tonic-gate {
10677c478bd9Sstevel@tonic-gate 	struct event *e;
10697c478bd9Sstevel@tonic-gate 	e = xmalloc(sizeof (struct event));
10707c478bd9Sstevel@tonic-gate 	e->etype = jobtype;
10714c4c9110Sbasabi 	e->cmd = xmalloc(strlen(job) + 1);
10727c478bd9Sstevel@tonic-gate 	(void) strcpy(e->cmd, job);
10737c478bd9Sstevel@tonic-gate 	e->u = u;
10747c478bd9Sstevel@tonic-gate 	e->link = u->atevents;
10757c478bd9Sstevel@tonic-gate 	u->atevents = e;
10767c478bd9Sstevel@tonic-gate 	e->of.at.exists = TRUE;
10777c478bd9Sstevel@tonic-gate 	e->of.at.eventid = ecid++;
10787c478bd9Sstevel@tonic-gate 	if (tim < init_time)	/* old job */
10797c478bd9Sstevel@tonic-gate 		e->time = init_time;
10807c478bd9Sstevel@tonic-gate 	else
10817c478bd9Sstevel@tonic-gate 		e->time = tim;
10827c478bd9Sstevel@tonic-gate #ifdef DEBUG
10837c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "add_atevent: user=%s, job=%s, time=%ld\n",
10844c4c9110Sbasabi 	    u->name, e->cmd, e->time);
10857c478bd9Sstevel@tonic-gate #endif
1086e2553d68SSerge Dussud 	if (el_add(e, e->time, e->of.at.eventid) < 0) {
1087e2553d68SSerge Dussud 		ignore_msg("add_atevent", "at", e);
1088e2553d68SSerge Dussud 	}
10897c478bd9Sstevel@tonic-gate }
10914c4c9110Sbasabi void
update_atevent(struct usr * u,char * name,time_t tim,int jobtype)10924c4c9110Sbasabi update_atevent(struct usr *u, char *name, time_t tim, int jobtype)
10934c4c9110Sbasabi {
10944c4c9110Sbasabi 	struct event *e;
10964c4c9110Sbasabi 	e = u->atevents;
10974c4c9110Sbasabi 	while (e != NULL) {
10984c4c9110Sbasabi 		if (strcmp(e->cmd, name) == 0) {
10994c4c9110Sbasabi 			e->of.at.exists = TRUE;
11004c4c9110Sbasabi 			break;
11014c4c9110Sbasabi 		} else {
11024c4c9110Sbasabi 			e = e->link;
11034c4c9110Sbasabi 		}
11044c4c9110Sbasabi 	}
11054c4c9110Sbasabi 	if (e == NULL) {
11064c4c9110Sbasabi #ifdef DEBUG
11074c4c9110Sbasabi 		(void) fprintf(stderr, "%s has a new at job = %s\n",
11084c4c9110Sbasabi 		    u->name, name);
11094c4c9110Sbasabi #endif
11104c4c9110Sbasabi 			add_atevent(u, name, tim, jobtype);
11114c4c9110Sbasabi 	}
11124c4c9110Sbasabi }
11147c478bd9Sstevel@tonic-gate static char line[CTLINESIZE];	/* holds a line from a crontab file */
11157c478bd9Sstevel@tonic-gate static int cursor;		/* cursor for the above line */
11177c478bd9Sstevel@tonic-gate static void
readcron(struct usr * u,time_t reftime)11187c478bd9Sstevel@tonic-gate readcron(struct usr *u, time_t reftime)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate 	/*
11217c478bd9Sstevel@tonic-gate 	 * readcron reads in a crontab file for a user (u). The list of
11227c478bd9Sstevel@tonic-gate 	 * events for user u is built, and u->events is made to point to
11237c478bd9Sstevel@tonic-gate 	 * this list. Each event is also entered into the main event
11247c478bd9Sstevel@tonic-gate 	 * list.
11257c478bd9Sstevel@tonic-gate 	 */
11267c478bd9Sstevel@tonic-gate 	FILE *cf;	/* cf will be a user's crontab file */
11277c478bd9Sstevel@tonic-gate 	struct event *e;
11287c478bd9Sstevel@tonic-gate 	int start;
11297c478bd9Sstevel@tonic-gate 	unsigned int i;
11307c478bd9Sstevel@tonic-gate 	char namebuf[PATH_MAX];
11317c478bd9Sstevel@tonic-gate 	char *pname;
11325b08e637SChris Gerhard 	struct shared *tz = NULL;
11335b08e637SChris Gerhard 	struct shared *home = NULL;
11345b08e637SChris Gerhard 	struct shared *shell = NULL;
1135618372bcSSebastian Wiedenroth 	uint32_t max_random_delay = 0;
11367c478bd9Sstevel@tonic-gate 	int lineno = 0;
1137618372bcSSebastian Wiedenroth 	const char *errstr;
11397c478bd9Sstevel@tonic-gate 	/* read the crontab file */
11407c478bd9Sstevel@tonic-gate 	cte_init();		/* Init error handling */
11417c478bd9Sstevel@tonic-gate 	if (cwd != CRON) {
11427c478bd9Sstevel@tonic-gate 		if (snprintf(namebuf, sizeof (namebuf), "%s/%s",