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 */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
3419803d09SToomas Soome /* All Rights Reserved */
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */
377c478bd9Sstevel@tonic-gate /* All Rights Reserved */
387c478bd9Sstevel@tonic-gate
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>
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #include <security/pam_appl.h>
517c478bd9Sstevel@tonic-gate
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>
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate #include "cron.h"
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate * #define DEBUG
807c478bd9Sstevel@tonic-gate */
817c478bd9Sstevel@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 */
847c478bd9Sstevel@tonic-gate
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 */
897c478bd9Sstevel@tonic-gate
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 */
937c478bd9Sstevel@tonic-gate
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 */
977c478bd9Sstevel@tonic-gate
987c478bd9Sstevel@tonic-gate #define JOBF 'j'
997c478bd9Sstevel@tonic-gate #define NICEF 'n'
1007c478bd9Sstevel@tonic-gate #define USERF 'u'
1017c478bd9Sstevel@tonic-gate #define WAITF 'w'
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate #define BCHAR '>'
1047c478bd9Sstevel@tonic-gate #define ECHAR '<'
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate #define DEFAULT 0
1077c478bd9Sstevel@tonic-gate #define LOAD 1
1087c478bd9Sstevel@tonic-gate #define QBUFSIZ 80
1097c478bd9Sstevel@tonic-gate
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
1147c478bd9Sstevel@tonic-gate
1157c478bd9Sstevel@tonic-gate #define BADCD "can't change directory to the crontab directory."
1167c478bd9Sstevel@tonic-gate #define NOREADDIR "can't read the crontab directory."
1177c478bd9Sstevel@tonic-gate
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."
1217c478bd9Sstevel@tonic-gate
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."
1357c478bd9Sstevel@tonic-gate
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"
1417c478bd9Sstevel@tonic-gate
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."
1467c478bd9Sstevel@tonic-gate
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"
1517c478bd9Sstevel@tonic-gate
1527c478bd9Sstevel@tonic-gate #define DIDFORK didfork
1537c478bd9Sstevel@tonic-gate #define NOFORK !didfork
1547c478bd9Sstevel@tonic-gate
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)
1597c478bd9Sstevel@tonic-gate
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 */
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate #define PROJECT "project="
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate #define MAX_LOST_CONTRACTS 2048 /* reset if this many failed abandons */
1697c478bd9Sstevel@tonic-gate
1707c478bd9Sstevel@tonic-gate #define FORMAT "%a %b %e %H:%M:%S %Y"
1717c478bd9Sstevel@tonic-gate static char timebuf[80];
1727c478bd9Sstevel@tonic-gate
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 };
2067c478bd9Sstevel@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 */
2207c478bd9Sstevel@tonic-gate
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;
2317c478bd9Sstevel@tonic-gate
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;
2437c478bd9Sstevel@tonic-gate
2447c478bd9Sstevel@tonic-gate static struct miscpid {
2457c478bd9Sstevel@tonic-gate pid_t pid;
2467c478bd9Sstevel@tonic-gate struct miscpid *next;
2477c478bd9Sstevel@tonic-gate } *miscpid_head;
2487c478bd9Sstevel@tonic-gate
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 */
2577c478bd9Sstevel@tonic-gate
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 */
2667c478bd9Sstevel@tonic-gate
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:"
2707c478bd9Sstevel@tonic-gate
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 };
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate extern char **environ;
2887c478bd9Sstevel@tonic-gate
2897c478bd9Sstevel@tonic-gate #define DEFTZ "GMT"
2907c478bd9Sstevel@tonic-gate static int log = 0;
2917c478bd9Sstevel@tonic-gate static char hzname[10];
2927c478bd9Sstevel@tonic-gate
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);
2977c478bd9Sstevel@tonic-gate
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);
3367c478bd9Sstevel@tonic-gate
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 *);
3427c478bd9Sstevel@tonic-gate
3437c478bd9Sstevel@tonic-gate static int set_user_cred(const struct usr *, struct project *);
3447c478bd9Sstevel@tonic-gate
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 */
3567c478bd9Sstevel@tonic-gate
357d1419d5aSNobutomo Nakano static int refresh;
358d1419d5aSNobutomo Nakano static sigset_t defmask, sigmask;
3597c478bd9Sstevel@tonic-gate
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();
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate static int cron_conv(int, struct pam_message **,
3737c478bd9Sstevel@tonic-gate struct pam_response **, void *);
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate static struct pam_conv pam_conv = {cron_conv, NULL};
3767c478bd9Sstevel@tonic-gate static pam_handle_t *pamh; /* Authentication handle */
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate * Function to help check a user's credentials.
3807c478bd9Sstevel@tonic-gate */
3817c478bd9Sstevel@tonic-gate
3824c4c9110Sbasabi static int verify_user_cred(struct usr *u);
3837c478bd9Sstevel@tonic-gate
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate * Values returned by verify_user_cred and set_user_cred:
3867c478bd9Sstevel@tonic-gate */
3877c478bd9Sstevel@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
3937c478bd9Sstevel@tonic-gate
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
3997c478bd9Sstevel@tonic-gate
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);
4087c478bd9Sstevel@tonic-gate
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);
4187c478bd9Sstevel@tonic-gate
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);
4244c4c9110Sbasabi
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;
4367c478bd9Sstevel@tonic-gate
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;
4497c478bd9Sstevel@tonic-gate
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);
4557c478bd9Sstevel@tonic-gate
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 }
4707c478bd9Sstevel@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);
4767c478bd9Sstevel@tonic-gate
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);
4957c478bd9Sstevel@tonic-gate
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);
5017c478bd9Sstevel@tonic-gate
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;
5437c478bd9Sstevel@tonic-gate
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 }
5677c478bd9Sstevel@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 }
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate last_time = next_event->time; /* save execution time */
5767c478bd9Sstevel@tonic-gate
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 }
5857c478bd9Sstevel@tonic-gate
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 }
5937c478bd9Sstevel@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 */
6027c478bd9Sstevel@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;
6127c478bd9Sstevel@tonic-gate
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
6317c478bd9Sstevel@tonic-gate
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 }
6687c478bd9Sstevel@tonic-gate
6697c478bd9Sstevel@tonic-gate /*NOTREACHED*/
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@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 }
7107c478bd9Sstevel@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 }
7157c478bd9Sstevel@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;
7307c478bd9Sstevel@tonic-gate
7317c478bd9Sstevel@tonic-gate if (!firstpass)
7327c478bd9Sstevel@tonic-gate return;
7337c478bd9Sstevel@tonic-gate
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);
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate /* log should be root-only */
7397c478bd9Sstevel@tonic-gate (void) fchmod(1, S_IRUSR|S_IWUSR);
7407c478bd9Sstevel@tonic-gate
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);
7467c478bd9Sstevel@tonic-gate
7477c478bd9Sstevel@tonic-gate contract_set_template();
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@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;
7584c4c9110Sbasabi
7597c478bd9Sstevel@tonic-gate
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);
7714c4c9110Sbasabi
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 }
7997c478bd9Sstevel@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;
8047c478bd9Sstevel@tonic-gate
8054c4c9110Sbasabi if (strcmp(name, ".") == 0 ||
8064c4c9110Sbasabi strcmp(name, "..") == 0)
8074c4c9110Sbasabi return (0);
8084c4c9110Sbasabi
8094c4c9110Sbasabi /* skip over ancillary file names */
8104c4c9110Sbasabi if (audit_cron_is_anc_name(name))
8114c4c9110Sbasabi return (0);
8124c4c9110Sbasabi
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 }
8314c4c9110Sbasabi
8324c4c9110Sbasabi struct usr *
create_ulist(char * name,int type)8334c4c9110Sbasabi create_ulist(char *name, int type)
8344c4c9110Sbasabi {
8354c4c9110Sbasabi struct usr *u;
8364c4c9110Sbasabi
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 }
8524c4c9110Sbasabi
8534c4c9110Sbasabi void
init_cronevent(char * name,int first)8544c4c9110Sbasabi init_cronevent(char *name, int first)
8554c4c9110Sbasabi {
8564c4c9110Sbasabi struct usr *u;
8574c4c9110Sbasabi
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 }
8734c4c9110Sbasabi
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;
8784c4c9110Sbasabi
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 }
8917c478bd9Sstevel@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;
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate /* skip over ancillary file names */
9027c478bd9Sstevel@tonic-gate if (audit_cron_is_anc_name(name))
9037c478bd9Sstevel@tonic-gate return;
9047c478bd9Sstevel@tonic-gate
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 }
9867c478bd9Sstevel@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;
9987c478bd9Sstevel@tonic-gate
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';
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate /* check for audit ancillary file */
10087c478bd9Sstevel@tonic-gate if (audit_cron_is_anc_name(name))
10097c478bd9Sstevel@tonic-gate return;
10107c478bd9Sstevel@tonic-gate
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 }
10637c478bd9Sstevel@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;
10687c478bd9Sstevel@tonic-gate
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 }
10907c478bd9Sstevel@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;
10954c4c9110Sbasabi
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 }
11137c478bd9Sstevel@tonic-gate
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 */
11167c478bd9Sstevel@tonic-gate
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;
11387c478bd9Sstevel@tonic-gate
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",
11437c478bd9