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 */
347c478bd9Sstevel@tonic-gate /* 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
515e2553d68SSerge Dussud 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",
5547c478bd9Sstevel@tonic-gate 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;
5657c478bd9Sstevel@tonic-gate }
566e2553d68SSerge Dussud }
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 =
6197c478bd9Sstevel@tonic-gate next_time(next_event, newtime);
6207c478bd9Sstevel@tonic-gate t_old = time(NULL);
6217c478bd9Sstevel@tonic-gate } else {
6227c478bd9Sstevel@tonic-gate next_event->time =
6237c478bd9Sstevel@tonic-gate 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,
6287c478bd9Sstevel@tonic-gate "pushing back cron event %s at %ld (%s)\n",
6297c478bd9Sstevel@tonic-gate 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",
6827c478bd9Sstevel@tonic-gate 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",
6887c478bd9Sstevel@tonic-gate 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",
6967c478bd9Sstevel@tonic-gate 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 {
7537c478bd9Sstevel@tonic-gate 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);
8177c478bd9Sstevel@tonic-gate }
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);
8884c4c9110Sbasabi }
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",
9117c478bd9Sstevel@tonic-gate CRONDIR, name) >= sizeof (namebuf)) {
9127c478bd9Sstevel@tonic-gate msg("Too long path name %s - cron entries not created",
9137c478bd9Sstevel@tonic-gate 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);
9477c478bd9Sstevel@tonic-gate 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) {
9567c478bd9Sstevel@tonic-gate if (strcmp(u->home, pw->pw_dir) != 0) {
9577c478bd9Sstevel@tonic-gate free(u->home);
9587c478bd9Sstevel@tonic-gate u->home = xmalloc(strlen(pw->pw_dir) + 1);
9597c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir);
9607c478bd9Sstevel@tonic-gate }
961d9f27107Sbasabi } else {
962d9f27107Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1);
963d9f27107Sbasabi (void) strcpy(u->home, pw->pw_dir);
964d9f27107Sbasabi }
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",
10487c478bd9Sstevel@tonic-gate 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;
10587c478bd9Sstevel@tonic-gate 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;
10717c478bd9Sstevel@tonic-gate 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",
10847c478bd9Sstevel@tonic-gate 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",
11437c478bd9Sstevel@tonic-gate CRONDIR, u->name) >= sizeof (namebuf)) {
11447c478bd9Sstevel@tonic-gate return;
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate pname = namebuf;
11477c478bd9Sstevel@tonic-gate } else {
11487c478bd9Sstevel@tonic-gate pname = u->name;
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate if ((cf = fopen(pname, "r")) == NULL) {
11517c478bd9Sstevel@tonic-gate mail(u->name, NOREAD, ERR_UNIXERR);
11527c478bd9Sstevel@tonic-gate return;
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate while (fgets(line, CTLINESIZE, cf) != NULL) {
11555b08e637SChris Gerhard char *tmp;
11567c478bd9Sstevel@tonic-gate /* process a line of a crontab file */
11577c478bd9Sstevel@tonic-gate lineno++;
11587c478bd9Sstevel@tonic-gate if (cte_istoomany())
11597c478bd9Sstevel@tonic-gate break;
11607c478bd9Sstevel@tonic-gate cursor = 0;
11617c478bd9Sstevel@tonic-gate while (line[cursor] == ' ' || line[cursor] == '\t')
11627c478bd9Sstevel@tonic-gate cursor++;
11637c478bd9Sstevel@tonic-gate if (line[cursor] == '#' || line[cursor] == '\n')
11647c478bd9Sstevel@tonic-gate continue;
11655b08e637SChris Gerhard
11665b08e637SChris Gerhard if (strncmp(&line[cursor], ENV_TZ,
11675b08e637SChris Gerhard strlen(ENV_TZ)) == 0) {
11685b08e637SChris Gerhard if ((tmp = strchr(&line[cursor], '\n')) != NULL) {
116919803d09SToomas Soome *tmp = '\0';
11705b08e637SChris Gerhard }
11715b08e637SChris Gerhard
11725b08e637SChris Gerhard if (!isvalid_tz(&line[cursor + strlen(ENV_TZ)], NULL,
11735b08e637SChris Gerhard _VTZ_ALL)) {
11745b08e637SChris Gerhard cte_add(lineno, line);
11755b08e637SChris Gerhard break;
11765b08e637SChris Gerhard }
11775b08e637SChris Gerhard if (tz == NULL || strcmp(&line[cursor], get_obj(tz))) {
11785b08e637SChris Gerhard rel_shared(tz);
11795b08e637SChris Gerhard tz = create_shared_str(&line[cursor]);
11805b08e637SChris Gerhard }
11815b08e637SChris Gerhard continue;
11825b08e637SChris Gerhard }
11835b08e637SChris Gerhard
11845b08e637SChris Gerhard if (strncmp(&line[cursor], ENV_HOME,
11855b08e637SChris Gerhard strlen(ENV_HOME)) == 0) {
11865b08e637SChris Gerhard if ((tmp = strchr(&line[cursor], '\n')) != NULL) {
118719803d09SToomas Soome *tmp = '\0';
11885b08e637SChris Gerhard }
11895b08e637SChris Gerhard if (home == NULL ||
11905b08e637SChris Gerhard strcmp(&line[cursor], get_obj(home))) {
11915b08e637SChris Gerhard rel_shared(home);
11925b08e637SChris Gerhard home = create_shared_str(
11935b08e637SChris Gerhard &line[cursor + strlen(ENV_HOME)]);
11945b08e637SChris Gerhard }
11955b08e637SChris Gerhard continue;
11965b08e637SChris Gerhard }
11975b08e637SChris Gerhard
11985b08e637SChris Gerhard if (strncmp(&line[cursor], ENV_SHELL,
11995b08e637SChris Gerhard strlen(ENV_SHELL)) == 0) {
12005b08e637SChris Gerhard if ((tmp = strchr(&line[cursor], '\n')) != NULL) {
120119803d09SToomas Soome *tmp = '\0';
12025b08e637SChris Gerhard }
12035b08e637SChris Gerhard if (shell == NULL ||
12045b08e637SChris Gerhard strcmp(&line[cursor], get_obj(shell))) {
12055b08e637SChris Gerhard rel_shared(shell);
12065b08e637SChris Gerhard shell = create_shared_str(&line[cursor]);
12075b08e637SChris Gerhard }
12085b08e637SChris Gerhard continue;
12095b08e637SChris Gerhard }
12105b08e637SChris Gerhard
1211618372bcSSebastian Wiedenroth if (strncmp(&line[cursor], ENV_RANDOM_DELAY,
1212618372bcSSebastian Wiedenroth strlen(ENV_RANDOM_DELAY)) == 0) {
1213618372bcSSebastian Wiedenroth if ((tmp = strchr(&line[cursor], '\n')) != NULL) {
1214618372bcSSebastian Wiedenroth *tmp = '\0';
1215618372bcSSebastian Wiedenroth }
1216618372bcSSebastian Wiedenroth
1217618372bcSSebastian Wiedenroth max_random_delay = strtonum(
1218618372bcSSebastian Wiedenroth &line[cursor + strlen(ENV_RANDOM_DELAY)], 0,
1219618372bcSSebastian Wiedenroth UINT32_MAX / 60, &errstr);
1220618372bcSSebastian Wiedenroth if (errstr != NULL) {
1221618372bcSSebastian Wiedenroth cte_add(lineno, line);
1222618372bcSSebastian Wiedenroth break;
1223618372bcSSebastian Wiedenroth }
1224618372bcSSebastian Wiedenroth
1225618372bcSSebastian Wiedenroth continue;
1226618372bcSSebastian Wiedenroth }
1227618372bcSSebastian Wiedenroth
12287c478bd9Sstevel@tonic-gate e = xmalloc(sizeof (struct event));
12297c478bd9Sstevel@tonic-gate e->etype = CRONEVENT;
12306b734416SAndy Fiddaman
12316b734416SAndy Fiddaman if (next_field(0, 59, line, &cursor,
12326b734416SAndy Fiddaman &e->of.ct.minute) != CFOK ||
12336b734416SAndy Fiddaman next_field(0, 23, line, &cursor, &e->of.ct.hour) != CFOK ||
12346b734416SAndy Fiddaman next_field(1, 31, line, &cursor,
12356b734416SAndy Fiddaman &e->of.ct.daymon) != CFOK ||
12366b734416SAndy Fiddaman next_field(1, 12, line, &cursor, &e->of.ct.month) != CFOK ||
12376b734416SAndy Fiddaman next_field(0, 6, line, &cursor,
12386b734416SAndy Fiddaman &e->of.ct.dayweek) != CFOK) {
12396b734416SAndy Fiddaman #ifdef DEBUG
12406b734416SAndy Fiddaman (void) fprintf(stderr, "Error: %d %s", lineno, line);
12416b734416SAndy Fiddaman #endif
12427c478bd9Sstevel@tonic-gate free(e);
12437c478bd9Sstevel@tonic-gate cte_add(lineno, line);
12447c478bd9Sstevel@tonic-gate continue;
12457c478bd9Sstevel@tonic-gate }
12467c478bd9Sstevel@tonic-gate while (line[cursor] == ' ' || line[cursor] == '\t')
12477c478bd9Sstevel@tonic-gate cursor++;
12487c478bd9Sstevel@tonic-gate if (line[cursor] == '\n' || line[cursor] == '\0')
12497c478bd9Sstevel@tonic-gate continue;
12507c478bd9Sstevel@tonic-gate /* get the command to execute */
12517c478bd9Sstevel@tonic-gate start = cursor;
12527c478bd9Sstevel@tonic-gate again:
12537c478bd9Sstevel@tonic-gate while ((line[cursor] != '%') &&
12547c478bd9Sstevel@tonic-gate (line[cursor] != '\n') &&
12557c478bd9Sstevel@tonic-gate (line[cursor] != '\0') &&
12567c478bd9Sstevel@tonic-gate (line[cursor] != '\\'))
12577c478bd9Sstevel@tonic-gate cursor++;
12587c478bd9Sstevel@tonic-gate if (line[cursor] == '\\') {
12597c478bd9Sstevel@tonic-gate cursor += 2;
12607c478bd9Sstevel@tonic-gate goto again;
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate e->cmd = xmalloc(cursor-start + 1);
12637c478bd9Sstevel@tonic-gate (void) strncpy(e->cmd, line + start, cursor-start);
12647c478bd9Sstevel@tonic-gate e->cmd[cursor-start] = '\0';
12657c478bd9Sstevel@tonic-gate /* see if there is any standard input */
12667c478bd9Sstevel@tonic-gate if (line[cursor] == '%') {
12677c478bd9Sstevel@tonic-gate e->of.ct.input = xmalloc(strlen(line)-cursor + 1);
12687c478bd9Sstevel@tonic-gate (void) strcpy(e->of.ct.input, line + cursor + 1);
12697c478bd9Sstevel@tonic-gate for (i = 0; i < strlen(e->of.ct.input); i++) {
12707c478bd9Sstevel@tonic-gate if (e->of.ct.input[i] == '%')
12717c478bd9Sstevel@tonic-gate e->of.ct.input[i] = '\n';
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate } else {
12747c478bd9Sstevel@tonic-gate e->of.ct.input = NULL;
12757c478bd9Sstevel@tonic-gate }
12765b08e637SChris Gerhard /* set the timezone of this entry */
12775b08e637SChris Gerhard e->of.ct.tz = dup_shared(tz);
12785b08e637SChris Gerhard /* set the shell of this entry */
12795b08e637SChris Gerhard e->of.ct.shell = dup_shared(shell);
12805b08e637SChris Gerhard /* set the home of this entry */
12815b08e637SChris Gerhard e->of.ct.home = dup_shared(home);
1282618372bcSSebastian Wiedenroth /* set the maximum random delay */
1283618372bcSSebastian Wiedenroth e->of.ct.max_random_delay = max_random_delay;
12847c478bd9Sstevel@tonic-gate /* have the event point to it's owner */
12857c478bd9Sstevel@tonic-gate e->u = u;
12867c478bd9Sstevel@tonic-gate /* insert this event at the front of this user's event list */
12877c478bd9Sstevel@tonic-gate e->link = u->ctevents;
12887c478bd9Sstevel@tonic-gate u->ctevents = e;
12897c478bd9Sstevel@tonic-gate /* set the time for the first occurance of this event */
12907c478bd9Sstevel@tonic-gate e->time = next_time(e, reftime);
12917c478bd9Sstevel@tonic-gate /* finally, add this event to the main event list */
1292e2553d68SSerge Dussud switch (el_add(e, e->time, u->ctid)) {
1293e2553d68SSerge Dussud case -1:
1294e2553d68SSerge Dussud ignore_msg("readcron", "cron", e);
1295e2553d68SSerge Dussud break;
1296e2553d68SSerge Dussud case -2: /* event time lower than init time */
1297e2553d68SSerge Dussud reset_needed = 1;
1298e2553d68SSerge Dussud break;
1299e2553d68SSerge Dussud }
13007c478bd9Sstevel@tonic-gate cte_valid();
13017c478bd9Sstevel@tonic-gate #ifdef DEBUG
1302ee169c7eSGary Mills cftime(timebuf, "%+", &e->time);
13037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "inserting cron event %s at %ld (%s)\n",
13047c478bd9Sstevel@tonic-gate e->cmd, e->time, timebuf);
13057c478bd9Sstevel@tonic-gate #endif
13067c478bd9Sstevel@tonic-gate }
13077c478bd9Sstevel@tonic-gate cte_sendmail(u->name); /* mail errors if any to user */
13087c478bd9Sstevel@tonic-gate (void) fclose(cf);
13095b08e637SChris Gerhard rel_shared(tz);
13105b08e637SChris Gerhard rel_shared(shell);
13115b08e637SChris Gerhard rel_shared(home);
13127c478bd9Sstevel@tonic-gate }
13137c478bd9Sstevel@tonic-gate
13147c478bd9Sstevel@tonic-gate /*
13157c478bd9Sstevel@tonic-gate * Below are the functions for handling of errors in crontabs. Concept is to
13167c478bd9Sstevel@tonic-gate * collect faulty lines and send one email at the end of the crontab
13177c478bd9Sstevel@tonic-gate * evaluation. If there are erroneous lines only ((cte_nvalid == 0), evaluation
13187c478bd9Sstevel@tonic-gate * of crontab is aborted. Otherwise reading of crontab is continued to the end
13197c478bd9Sstevel@tonic-gate * of the file but no further error logging appears.
13207c478bd9Sstevel@tonic-gate */
13217c478bd9Sstevel@tonic-gate static void
cte_init()13227c478bd9Sstevel@tonic-gate cte_init()
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate if (cte_text == NULL)
13257c478bd9Sstevel@tonic-gate cte_text = xmalloc(MAILBUFLEN);
13267c478bd9Sstevel@tonic-gate (void) strlcpy(cte_text, cte_intro, MAILBUFLEN);
13277c478bd9Sstevel@tonic-gate cte_lp = cte_text + sizeof (cte_intro) - 1;
13287c478bd9Sstevel@tonic-gate cte_free = MAILBINITFREE;
13297c478bd9Sstevel@tonic-gate cte_nvalid = 0;
13307c478bd9Sstevel@tonic-gate }
13317c478bd9Sstevel@tonic-gate
13327c478bd9Sstevel@tonic-gate static void
cte_add(int lineno,char * ctline)13337c478bd9Sstevel@tonic-gate cte_add(int lineno, char *ctline)
13347c478bd9Sstevel@tonic-gate {
13357c478bd9Sstevel@tonic-gate int len;
13367c478bd9Sstevel@tonic-gate char *p;
13377c478bd9Sstevel@tonic-gate
13387c478bd9Sstevel@tonic-gate if (cte_free >= LINELIMIT) {
13397c478bd9Sstevel@tonic-gate (void) sprintf(cte_lp, "%4d: ", lineno);
13407c478bd9Sstevel@tonic-gate (void) strlcat(cte_lp, ctline, LINELIMIT - 1);
13417c478bd9Sstevel@tonic-gate len = strlen(cte_lp);
13427c478bd9Sstevel@tonic-gate if (cte_lp[len - 1] != '\n') {
13437c478bd9Sstevel@tonic-gate cte_lp[len++] = '\n';
13447c478bd9Sstevel@tonic-gate cte_lp[len] = '\0';
13457c478bd9Sstevel@tonic-gate }
13467c478bd9Sstevel@tonic-gate for (p = cte_lp; *p; p++) {
13477c478bd9Sstevel@tonic-gate if (isprint(*p) || *p == '\n' || *p == '\t')
13487c478bd9Sstevel@tonic-gate continue;
13497c478bd9Sstevel@tonic-gate *p = '.';
13507c478bd9Sstevel@tonic-gate }
13517c478bd9Sstevel@tonic-gate cte_lp += len;
13527c478bd9Sstevel@tonic-gate cte_free -= len;
13537c478bd9Sstevel@tonic-gate if (cte_free < LINELIMIT) {
13547c478bd9Sstevel@tonic-gate size_t buflen = MAILBUFLEN - (cte_lp - cte_text);
13557c478bd9Sstevel@tonic-gate (void) strlcpy(cte_lp, cte_trail1, buflen);
13567c478bd9Sstevel@tonic-gate if (cte_nvalid == 0)
13577c478bd9Sstevel@tonic-gate (void) strlcat(cte_lp, cte_trail2, buflen);
13587c478bd9Sstevel@tonic-gate }
13597c478bd9Sstevel@tonic-gate }
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate
13627c478bd9Sstevel@tonic-gate static void
cte_valid()13637c478bd9Sstevel@tonic-gate cte_valid()
13647c478bd9Sstevel@tonic-gate {
13657c478bd9Sstevel@tonic-gate cte_nvalid++;
13667c478bd9Sstevel@tonic-gate }
13677c478bd9Sstevel@tonic-gate
13687c478bd9Sstevel@tonic-gate static int
cte_istoomany()13697c478bd9Sstevel@tonic-gate cte_istoomany()
13707c478bd9Sstevel@tonic-gate {
13717c478bd9Sstevel@tonic-gate /*
13727c478bd9Sstevel@tonic-gate * Return TRUE only if all lines are faulty. So evaluation of
13737c478bd9Sstevel@tonic-gate * a crontab is not aborted if at least one valid line was found.
13747c478bd9Sstevel@tonic-gate */
13757c478bd9Sstevel@tonic-gate return (cte_nvalid == 0 && cte_free < LINELIMIT);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate
13787c478bd9Sstevel@tonic-gate static void
cte_sendmail(char * username)13797c478bd9Sstevel@tonic-gate cte_sendmail(char *username)
13807c478bd9Sstevel@tonic-gate {
13817c478bd9Sstevel@tonic-gate if (cte_free < MAILBINITFREE)
13827c478bd9Sstevel@tonic-gate mail(username, cte_text, ERR_CRONTABENT);
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate
13857c478bd9Sstevel@tonic-gate /*
13867c478bd9Sstevel@tonic-gate * Send mail with error message to a user
13877c478bd9Sstevel@tonic-gate */
13887c478bd9Sstevel@tonic-gate static void
mail(char * usrname,char * mesg,int format)13897c478bd9Sstevel@tonic-gate mail(char *usrname, char *mesg, int format)
13907c478bd9Sstevel@tonic-gate {
13917c478bd9Sstevel@tonic-gate /* mail mails a user a message. */
13927c478bd9Sstevel@tonic-gate FILE *pipe;
13937c478bd9Sstevel@tonic-gate char *temp;
13947c478bd9Sstevel@tonic-gate struct passwd *ruser_ids;
13957c478bd9Sstevel@tonic-gate pid_t fork_val;
13967c478bd9Sstevel@tonic-gate int saveerrno = errno;
13977c478bd9Sstevel@tonic-gate struct utsname name;
13987c478bd9Sstevel@tonic-gate
13997c478bd9Sstevel@tonic-gate #ifdef TESTING
14007c478bd9Sstevel@tonic-gate return;
14017c478bd9Sstevel@tonic-gate #endif
14027c478bd9Sstevel@tonic-gate (void) uname(&name);
14037c478bd9Sstevel@tonic-gate if ((fork_val = fork()) == (pid_t)-1) {
14047c478bd9Sstevel@tonic-gate msg("cron cannot fork\n");
14057c478bd9Sstevel@tonic-gate return;
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate if (fork_val == 0) {
14087c478bd9Sstevel@tonic-gate child_sigreset();
14097c478bd9Sstevel@tonic-gate contract_clear_template();
14107c478bd9Sstevel@tonic-gate if ((ruser_ids = getpwnam(usrname)) == NULL)
14117c478bd9Sstevel@tonic-gate exit(0);
14127c478bd9Sstevel@tonic-gate (void) setuid(ruser_ids->pw_uid);
14137c478bd9Sstevel@tonic-gate temp = xmalloc(strlen(MAIL) + strlen(usrname) + 2);
14147c478bd9Sstevel@tonic-gate (void) sprintf(temp, "%s %s", MAIL, usrname);
14157c478bd9Sstevel@tonic-gate pipe = popen(temp, "w");
14167c478bd9Sstevel@tonic-gate if (pipe != NULL) {
14177c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "To: %s\n", usrname);
14187c478bd9Sstevel@tonic-gate switch (format) {
14197c478bd9Sstevel@tonic-gate case ERR_CRONTABENT:
14207c478bd9Sstevel@tonic-gate (void) fprintf(pipe, CRONTABERR);
14217c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Your \"crontab\" on %s\n",
14227c478bd9Sstevel@tonic-gate name.nodename);
14237c478bd9Sstevel@tonic-gate (void) fprintf(pipe, mesg);
14247c478bd9Sstevel@tonic-gate (void) fprintf(pipe,
14257c478bd9Sstevel@tonic-gate "\nEntries or crontab have been ignored\n");
14267c478bd9Sstevel@tonic-gate break;
14277c478bd9Sstevel@tonic-gate case ERR_UNIXERR:
14287c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Subject: %s\n\n", mesg);
14297c478bd9Sstevel@tonic-gate (void) fprintf(pipe,
14307c478bd9Sstevel@tonic-gate "The error on %s was \"%s\"\n",
14317c478bd9Sstevel@tonic-gate name.nodename, errmsg(saveerrno));
14327c478bd9Sstevel@tonic-gate break;
14337c478bd9Sstevel@tonic-gate
14347c478bd9Sstevel@tonic-gate case ERR_CANTEXECCRON:
14357c478bd9Sstevel@tonic-gate (void) fprintf(pipe,
14367c478bd9Sstevel@tonic-gate "Subject: Couldn't run your \"cron\" job\n\n");
14377c478bd9Sstevel@tonic-gate (void) fprintf(pipe,
14387c478bd9Sstevel@tonic-gate "Your \"cron\" job on %s ", name.nodename);
14397c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "couldn't be run\n");
14407c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "%s\n", mesg);
14417c478bd9Sstevel@tonic-gate (void) fprintf(pipe,
14427c478bd9Sstevel@tonic-gate "The error was \"%s\"\n", errmsg(saveerrno));
14437c478bd9Sstevel@tonic-gate break;
14447c478bd9Sstevel@tonic-gate
14457c478bd9Sstevel@tonic-gate case ERR_CANTEXECAT:
14467c478bd9Sstevel@tonic-gate (void) fprintf(pipe,
14477c478bd9Sstevel@tonic-gate "Subject: Couldn't run your \"at\" job\n\n");
14487c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Your \"at\" job on %s ",
14497c478bd9Sstevel@tonic-gate name.nodename);
14507c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "couldn't be run\n");
14517c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "%s\n", mesg);
14527c478bd9Sstevel@tonic-gate (void) fprintf(pipe,
14537c478bd9Sstevel@tonic-gate "The error was \"%s\"\n", errmsg(saveerrno));
14547c478bd9Sstevel@tonic-gate break;
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate default:
14577c478bd9Sstevel@tonic-gate break;
14587c478bd9Sstevel@tonic-gate }
14597c478bd9Sstevel@tonic-gate (void) pclose(pipe);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate free(temp);
14627c478bd9Sstevel@tonic-gate exit(0);
14637c478bd9Sstevel@tonic-gate }
14647c478bd9Sstevel@tonic-gate
14657c478bd9Sstevel@tonic-gate contract_abandon_latest(fork_val);
14667c478bd9Sstevel@tonic-gate
14677c478bd9Sstevel@tonic-gate if (cron_pid == getpid()) {
14687c478bd9Sstevel@tonic-gate miscpid_insert(fork_val);
14697c478bd9Sstevel@tonic-gate }
14707c478bd9Sstevel@tonic-gate }
14717c478bd9Sstevel@tonic-gate
14727c478bd9Sstevel@tonic-gate #define tm_cmp(t1, t2) (\
14737c478bd9Sstevel@tonic-gate (t1)->tm_year == (t2)->tm_year && \
14747c478bd9Sstevel@tonic-gate (t1)->tm_mon == (t2)->tm_mon && \
14757c478bd9Sstevel@tonic-gate (t1)->tm_mday == (t2)->tm_mday && \
14767c478bd9Sstevel@tonic-gate (t1)->tm_hour == (t2)->tm_hour && \
14777c478bd9Sstevel@tonic-gate (t1)->tm_min == (t2)->tm_min)
14787c478bd9Sstevel@tonic-gate
14797c478bd9Sstevel@tonic-gate #define tm_setup(tp, yr, mon, dy, hr, min, dst) \
14807c478bd9Sstevel@tonic-gate (tp)->tm_year = yr; \
14817c478bd9Sstevel@tonic-gate (tp)->tm_mon = mon; \
14827c478bd9Sstevel@tonic-gate (tp)->tm_mday = dy; \
14837c478bd9Sstevel@tonic-gate (tp)->tm_hour = hr; \
14847c478bd9Sstevel@tonic-gate (tp)->tm_min = min; \
14857c478bd9Sstevel@tonic-gate (tp)->tm_isdst = dst; \
14867c478bd9Sstevel@tonic-gate (tp)->tm_sec = 0; \
14877c478bd9Sstevel@tonic-gate (tp)->tm_wday = 0; \
14887c478bd9Sstevel@tonic-gate (tp)->tm_yday = 0;
14897c478bd9Sstevel@tonic-gate
14907c478bd9Sstevel@tonic-gate /*
14917c478bd9Sstevel@tonic-gate * modification for bugid 1104537. the second argument to next_time is
14927c478bd9Sstevel@tonic-gate * now the value of time(2) to be used. if this is 0, then use the
14937c478bd9Sstevel@tonic-gate * current time. otherwise, the second argument is the time from which to
14947c478bd9Sstevel@tonic-gate * calculate things. this is useful to correct situations where you've
14957c478bd9Sstevel@tonic-gate * gone backwards in time (I.e. the system's internal clock is correcting
14967c478bd9Sstevel@tonic-gate * itself backwards).
14977c478bd9Sstevel@tonic-gate */
14987c478bd9Sstevel@tonic-gate
14995b08e637SChris Gerhard
15005b08e637SChris Gerhard
15017c478bd9Sstevel@tonic-gate static time_t
tz_next_time(struct event * e,time_t tflag)15025b08e637SChris Gerhard tz_next_time(struct event *e, time_t tflag)
15037c478bd9Sstevel@tonic-gate {
15047c478bd9Sstevel@tonic-gate /*
15057c478bd9Sstevel@tonic-gate * returns the integer time for the next occurance of event e.
15067c478bd9Sstevel@tonic-gate * the following fields have ranges as indicated:
15077c478bd9Sstevel@tonic-gate * PRGM | min hour day of month mon day of week
15087c478bd9Sstevel@tonic-gate * ------|-------------------------------------------------------
15097c478bd9Sstevel@tonic-gate * cron | 0-59 0-23 1-31 1-12 0-6 (0=sunday)
15107c478bd9Sstevel@tonic-gate * time | 0-59 0-23 1-31 0-11 0-6 (0=sunday)
15117c478bd9Sstevel@tonic-gate * NOTE: this routine is hard to understand.
15127c478bd9Sstevel@tonic-gate */
15137c478bd9Sstevel@tonic-gate
15147c478bd9Sstevel@tonic-gate struct tm *tm, ref_tm, tmp, tmp1, tmp2;
15155b08e637SChris Gerhard int tm_mon, tm_mday, tm_wday, wday, m, min, h, hr, carry, day, days;
15165b08e637SChris Gerhard int d1, day1, carry1, d2, day2, carry2, daysahead, mon, yr, db, wd;
15175b08e637SChris Gerhard int today;
15187c478bd9Sstevel@tonic-gate time_t t, ref_t, t1, t2, zone_start;
15197c478bd9Sstevel@tonic-gate int fallback;
15207c478bd9Sstevel@tonic-gate extern int days_btwn(int, int, int, int, int, int);
15217c478bd9Sstevel@tonic-gate
15227c478bd9Sstevel@tonic-gate if (tflag == 0) {
15237c478bd9Sstevel@tonic-gate t = time(NULL); /* original way of doing things */
15247c478bd9Sstevel@tonic-gate } else {
15257c478bd9Sstevel@tonic-gate t = tflag;
15267c478bd9Sstevel@tonic-gate }
15277c478bd9Sstevel@tonic-gate
15287c478bd9Sstevel@tonic-gate tm = &ref_tm; /* use a local variable and call localtime_r() */
15297c478bd9Sstevel@tonic-gate ref_t = t; /* keep a copy of the reference time */
15307c478bd9Sstevel@tonic-gate
15317c478bd9Sstevel@tonic-gate recalc:
15327c478bd9Sstevel@tonic-gate fallback = 0;
15337c478bd9Sstevel@tonic-gate
15347c478bd9Sstevel@tonic-gate (void) localtime_r(&t, tm);
15357c478bd9Sstevel@tonic-gate
15367c478bd9Sstevel@tonic-gate if (daylight) {
15377c478bd9Sstevel@tonic-gate tmp = *tm;
15387c478bd9Sstevel@tonic-gate tmp.tm_isdst = (tm->tm_isdst > 0 ? 0 : 1);
15397c478bd9Sstevel@tonic-gate t1 = xmktime(&tmp);
15407c478bd9Sstevel@tonic-gate /*
15417c478bd9Sstevel@tonic-gate * see if we will have timezone switch over, and clock will
15427c478bd9Sstevel@tonic-gate * fall back. zone_start will hold the time when it happens
15437c478bd9Sstevel@tonic-gate * (ie time of PST -> PDT switch over).
15447c478bd9Sstevel@tonic-gate */
15457c478bd9Sstevel@tonic-gate if (tm->tm_isdst != tmp.tm_isdst &&
15467c478bd9Sstevel@tonic-gate (t1 - t) == (timezone - altzone) &&
15477c478bd9Sstevel@tonic-gate tm_cmp(tm, &tmp)) {
15487c478bd9Sstevel@tonic-gate zone_start = get_switching_time(tmp.tm_isdst, t);
15497c478bd9Sstevel@tonic-gate fallback = 1;
15507c478bd9Sstevel@tonic-gate }
15517c478bd9Sstevel@tonic-gate }
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate tm_mon = next_ge(tm->tm_mon + 1, e->of.ct.month) - 1; /* 0-11 */
15547c478bd9Sstevel@tonic-gate tm_mday = next_ge(tm->tm_mday, e->of.ct.daymon); /* 1-31 */
15557c478bd9Sstevel@tonic-gate tm_wday = next_ge(tm->tm_wday, e->of.ct.dayweek); /* 0-6 */
15567c478bd9Sstevel@tonic-gate today = TRUE;
15577c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0 && tm->tm_wday != tm_wday) ||
15587c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0 && tm->tm_mday != tm_mday) ||
15597c478bd9Sstevel@tonic-gate (tm->tm_mday != tm_mday && tm->tm_wday != tm_wday) ||
15607c478bd9Sstevel@tonic-gate (tm->tm_mon != tm_mon)) {
15617c478bd9Sstevel@tonic-gate today = FALSE;
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate m = tm->tm_min + (t == ref_t ? 1 : 0);
15647c478bd9Sstevel@tonic-gate if ((tm->tm_hour + 1) <= next_ge(tm->tm_hour, e->of.ct.hour)) {
15657c478bd9Sstevel@tonic-gate m = 0;
15667c478bd9Sstevel@tonic-gate }
15677c478bd9Sstevel@tonic-gate min = next_ge(m%60, e->of.ct.minute);
15687c478bd9Sstevel@tonic-gate carry = (min < m) ? 1 : 0;
15697c478bd9Sstevel@tonic-gate h = tm->tm_hour + carry;
15707c478bd9Sstevel@tonic-gate hr = next_ge(h%24, e->of.ct.hour);
15717c478bd9Sstevel@tonic-gate carry = (hr < h) ? 1 : 0;
15727c478bd9Sstevel@tonic-gate
15737c478bd9Sstevel@tonic-gate if (carry == 0 && today) {
15747c478bd9Sstevel@tonic-gate /* this event must occur today */
15757c478bd9Sstevel@tonic-gate tm_setup(&tmp, tm->tm_year, tm->tm_mon, tm->tm_mday,
15767c478bd9Sstevel@tonic-gate hr, min, tm->tm_isdst);
15777c478bd9Sstevel@tonic-gate tmp1 = tmp;
15787c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp1)) == (time_t)-1) {
15797c478bd9Sstevel@tonic-gate return (0);
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate if (daylight && tmp.tm_isdst != tmp1.tm_isdst) {
15827c478bd9Sstevel@tonic-gate /* In case we are falling back */
15837c478bd9Sstevel@tonic-gate if (fallback) {
15847c478bd9Sstevel@tonic-gate /* we may need to run the job once more. */
15857c478bd9Sstevel@tonic-gate t = zone_start;
15867c478bd9Sstevel@tonic-gate goto recalc;
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate
15897c478bd9Sstevel@tonic-gate /*
15907c478bd9Sstevel@tonic-gate * In case we are not in falling back period,
15917c478bd9Sstevel@tonic-gate * calculate the time assuming the DST. If the
15927c478bd9Sstevel@tonic-gate * date/time is not altered by mktime, it is the
15937c478bd9Sstevel@tonic-gate * time to execute the job.
15947c478bd9Sstevel@tonic-gate */
15957c478bd9Sstevel@tonic-gate tmp2 = tmp;
15967c478bd9Sstevel@tonic-gate tmp2.tm_isdst = tmp1.tm_isdst;
15977c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp2)) == (time_t)-1) {
15987c478bd9Sstevel@tonic-gate return (0);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst == tmp2.tm_isdst &&
16017c478bd9Sstevel@tonic-gate tm_cmp(&tmp, &tmp2)) {
16027c478bd9Sstevel@tonic-gate /*
16037c478bd9Sstevel@tonic-gate * We got a valid time.
16047c478bd9Sstevel@tonic-gate */
16057c478bd9Sstevel@tonic-gate return (t1);
16067c478bd9Sstevel@tonic-gate } else {
16077c478bd9Sstevel@tonic-gate /*
16087c478bd9Sstevel@tonic-gate * If the date does not match even if
16097c478bd9Sstevel@tonic-gate * we assume the alternate timezone, then
16107c478bd9Sstevel@tonic-gate * it must be the invalid time. eg
16117c478bd9Sstevel@tonic-gate * 2am while switching 1:59am to 3am.
16127c478bd9Sstevel@tonic-gate * t1 should point the time before the
16137c478bd9Sstevel@tonic-gate * switching over as we've calculate the
16147c478bd9Sstevel@tonic-gate * time with assuming alternate zone.
16157c478bd9Sstevel@tonic-gate */
16167c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst != tmp2.tm_isdst) {
16177c478bd9Sstevel@tonic-gate t = get_switching_time(tmp1.tm_isdst,
16187c478bd9Sstevel@tonic-gate t1);
16197c478bd9Sstevel@tonic-gate } else {
16207c478bd9Sstevel@tonic-gate /* does this really happen? */
16217c478bd9Sstevel@tonic-gate t = get_switching_time(tmp1.tm_isdst,
16227c478bd9Sstevel@tonic-gate t1 - abs(timezone - altzone));
16237c478bd9Sstevel@tonic-gate }
16245b08e637SChris Gerhard if (t == (time_t)-1) {
16257c478bd9Sstevel@tonic-gate return (0);
16267c478bd9Sstevel@tonic-gate }
16275b08e637SChris Gerhard }
16287c478bd9Sstevel@tonic-gate goto recalc;
16297c478bd9Sstevel@tonic-gate }
16307c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp1)) {
16317c478bd9Sstevel@tonic-gate /* got valid time */
16327c478bd9Sstevel@tonic-gate return (t1);
16337c478bd9Sstevel@tonic-gate } else {
16347c478bd9Sstevel@tonic-gate /*
16357c478bd9Sstevel@tonic-gate * This should never happen, but just in
16367c478bd9Sstevel@tonic-gate * case, we fall back to the old code.
16377c478bd9Sstevel@tonic-gate */
16387c478bd9Sstevel@tonic-gate if (tm->tm_min > min) {
16397c478bd9Sstevel@tonic-gate t += (time_t)(hr-tm->tm_hour-1) * HOUR +
16407c478bd9Sstevel@tonic-gate (time_t)(60-tm->tm_min + min) * MINUTE;
16417c478bd9Sstevel@tonic-gate } else {
16427c478bd9Sstevel@tonic-gate t += (time_t)(hr-tm->tm_hour) * HOUR +
16437c478bd9Sstevel@tonic-gate (time_t)(min-tm->tm_min) * MINUTE;
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate t1 = t;
16467c478bd9Sstevel@tonic-gate t -= (time_t)tm->tm_sec;
16477c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp);
16487c478bd9Sstevel@tonic-gate if ((tm->tm_isdst == 0) && (tmp.tm_isdst > 0))
16497c478bd9Sstevel@tonic-gate t -= (timezone - altzone);
16507c478bd9Sstevel@tonic-gate return ((t <= ref_t) ? t1 : t);
16517c478bd9Sstevel@tonic-gate }
16527c478bd9Sstevel@tonic-gate }
16537c478bd9Sstevel@tonic-gate
16547c478bd9Sstevel@tonic-gate /*
16557c478bd9Sstevel@tonic-gate * Job won't run today, however if we have a switch over within
16567c478bd9Sstevel@tonic-gate * one hour and we will have one hour time drifting back in this
16577c478bd9Sstevel@tonic-gate * period, we may need to run the job one more time if the job was
16587c478bd9Sstevel@tonic-gate * set to run on this hour of clock.
16597c478bd9Sstevel@tonic-gate */
16607c478bd9Sstevel@tonic-gate if (fallback) {
16617c478bd9Sstevel@tonic-gate t = zone_start;
16627c478bd9Sstevel@tonic-gate goto recalc;
16637c478bd9Sstevel@tonic-gate }
16647c478bd9Sstevel@tonic-gate
16657c478bd9Sstevel@tonic-gate min = next_ge(0, e->of.ct.minute);
16667c478bd9Sstevel@tonic-gate hr = next_ge(0, e->of.ct.hour);
16677c478bd9Sstevel@tonic-gate
16687c478bd9Sstevel@tonic-gate /*
16697c478bd9Sstevel@tonic-gate * calculate the date of the next occurance of this event, which
16707c478bd9Sstevel@tonic-gate * will be on a different day than the current
16717c478bd9Sstevel@tonic-gate */
16727c478bd9Sstevel@tonic-gate
16737c478bd9Sstevel@tonic-gate /* check monthly day specification */
16747c478bd9Sstevel@tonic-gate d1 = tm->tm_mday + 1;
16757c478bd9Sstevel@tonic-gate day1 = next_ge((d1-1)%days_in_mon(tm->tm_mon, tm->tm_year) + 1,
16767c478bd9Sstevel@tonic-gate e->of.ct.daymon);
16777c478bd9Sstevel@tonic-gate carry1 = (day1 < d1) ? 1 : 0;
16787c478bd9Sstevel@tonic-gate
16797c478bd9Sstevel@tonic-gate /* check weekly day specification */
16807c478bd9Sstevel@tonic-gate d2 = tm->tm_wday + 1;
16817c478bd9Sstevel@tonic-gate wday = next_ge(d2%7, e->of.ct.dayweek);
16827c478bd9Sstevel@tonic-gate if (wday < d2)
16837c478bd9Sstevel@tonic-gate daysahead = 7 - d2 + wday;
16847c478bd9Sstevel@tonic-gate else
16857c478bd9Sstevel@tonic-gate daysahead = wday - d2;
16867c478bd9Sstevel@tonic-gate day2 = (d1 + daysahead-1)%days_in_mon(tm->tm_mon, tm->tm_year) + 1;
16877c478bd9Sstevel@tonic-gate carry2 = (day2 < d1) ? 1 : 0;
16887c478bd9Sstevel@tonic-gate
16897c478bd9Sstevel@tonic-gate /*
16907c478bd9Sstevel@tonic-gate * based on their respective specifications, day1, and day2 give
16917c478bd9Sstevel@tonic-gate * the day of the month for the next occurance of this event.
16927c478bd9Sstevel@tonic-gate */
16937c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0) &&
16947c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") != 0)) {
16957c478bd9Sstevel@tonic-gate day1 = day2;
16967c478bd9Sstevel@tonic-gate carry1 = carry2;
16977c478bd9Sstevel@tonic-gate }
16987c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") != 0) &&
16997c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0)) {
17007c478bd9Sstevel@tonic-gate day2 = day1;
17017c478bd9Sstevel@tonic-gate carry2 = carry1;
17027c478bd9Sstevel@tonic-gate }
17037c478bd9Sstevel@tonic-gate
17047c478bd9Sstevel@tonic-gate yr = tm->tm_year;
17057c478bd9Sstevel@tonic-gate if ((carry1 && carry2) || (tm->tm_mon != tm_mon)) {
17067c478bd9Sstevel@tonic-gate /* event does not occur in this month */
17077c478bd9Sstevel@tonic-gate m = tm->tm_mon + 1;
17087c478bd9Sstevel@tonic-gate mon = next_ge(m%12 + 1, e->of.ct.month) - 1; /* 0..11 */
17097c478bd9Sstevel@tonic-gate carry = (mon < m) ? 1 : 0;
17107c478bd9Sstevel@tonic-gate yr += carry;
17117c478bd9Sstevel@tonic-gate /* recompute day1 and day2 */
17127c478bd9Sstevel@tonic-gate day1 = next_ge(1, e->of.ct.daymon);
17137c478bd9Sstevel@tonic-gate db = days_btwn(tm->tm_mon, tm->tm_mday, tm->tm_year, mon,
17147c478bd9Sstevel@tonic-gate 1, yr) + 1;
17157c478bd9Sstevel@tonic-gate wd = (tm->tm_wday + db)%7;
17167c478bd9Sstevel@tonic-gate /* wd is the day of the week of the first of month mon */
17177c478bd9Sstevel@tonic-gate wday = next_ge(wd, e->of.ct.dayweek);
17187c478bd9Sstevel@tonic-gate if (wday < wd)
17197c478bd9Sstevel@tonic-gate day2 = 1 + 7 - wd + wday;
17207c478bd9Sstevel@tonic-gate else
17217c478bd9Sstevel@tonic-gate day2 = 1 + wday - wd;
17227c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") != 0) &&
17237c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0))
17247c478bd9Sstevel@tonic-gate day2 = day1;
17257c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0) &&
17267c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") != 0))
17277c478bd9Sstevel@tonic-gate day1 = day2;
17287c478bd9Sstevel@tonic-gate day = (day1 < day2) ? day1 : day2;
17297c478bd9Sstevel@tonic-gate } else { /* event occurs in this month */
17307c478bd9Sstevel@tonic-gate mon = tm->tm_mon;
17317c478bd9Sstevel@tonic-gate if (!carry1 && !carry2)
17327c478bd9Sstevel@tonic-gate day = (day1 < day2) ? day1 : day2;
17337c478bd9Sstevel@tonic-gate else if (!carry1)
17347c478bd9Sstevel@tonic-gate day = day1;
17357c478bd9Sstevel@tonic-gate else
17367c478bd9Sstevel@tonic-gate day = day2;
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate
17397c478bd9Sstevel@tonic-gate /*
17407c478bd9Sstevel@tonic-gate * now that we have the min, hr, day, mon, yr of the next event,
17417c478bd9Sstevel@tonic-gate * figure out what time that turns out to be.
17427c478bd9Sstevel@tonic-gate */
17437c478bd9Sstevel@tonic-gate tm_setup(&tmp, yr, mon, day, hr, min, -1);
17447c478bd9Sstevel@tonic-gate tmp2 = tmp;
17457c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp2)) == (time_t)-1) {
17467c478bd9Sstevel@tonic-gate return (0);
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp2)) {
17497c478bd9Sstevel@tonic-gate /*
17507c478bd9Sstevel@tonic-gate * mktime returns clock for the current time zone. If the
17517c478bd9Sstevel@tonic-gate * target date was in fallback period, it needs to be adjusted
17527c478bd9Sstevel@tonic-gate * to the time comes first.
17537c478bd9Sstevel@tonic-gate * Suppose, we are at Jan and scheduling job at 1:30am10/26/03.
17547c478bd9Sstevel@tonic-gate * mktime returns the time in PST, but 1:30am in PDT comes
17557c478bd9Sstevel@tonic-gate * first. So reverse the tm_isdst, and see if we have such
17567c478bd9Sstevel@tonic-gate * time/date.
17577c478bd9Sstevel@tonic-gate */
17587c478bd9Sstevel@tonic-gate if (daylight) {
17597c478bd9Sstevel@tonic-gate int dst = tmp2.tm_isdst;
17607c478bd9Sstevel@tonic-gate
17617c478bd9Sstevel@tonic-gate tmp2 = tmp;
17627c478bd9Sstevel@tonic-gate tmp2.tm_isdst = (dst > 0 ? 0 : 1);
17637c478bd9Sstevel@tonic-gate if ((t2 = xmktime(&tmp2)) == (time_t)-1) {
17647c478bd9Sstevel@tonic-gate return (0);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp2)) {
17677c478bd9Sstevel@tonic-gate /*
17687c478bd9Sstevel@tonic-gate * same time/date found in the opposite zone.
17697c478bd9Sstevel@tonic-gate * check the clock to see which comes early.
17707c478bd9Sstevel@tonic-gate */
17717c478bd9Sstevel@tonic-gate if (t2 > ref_t && t2 < t1) {
17727c478bd9Sstevel@tonic-gate t1 = t2;
17737c478bd9Sstevel@tonic-gate }
17747c478bd9Sstevel@tonic-gate }
17757c478bd9Sstevel@tonic-gate }
17767c478bd9Sstevel@tonic-gate return (t1);
17777c478bd9Sstevel@tonic-gate } else {
17787c478bd9Sstevel@tonic-gate /*
17797c478bd9Sstevel@tonic-gate * mktime has set different time/date for the given date.
17807c478bd9Sstevel@tonic-gate * This means that the next job is scheduled to be run on the
17817c478bd9Sstevel@tonic-gate * invalid time. There are three possible invalid date/time.
17827c478bd9Sstevel@tonic-gate * 1. Non existing day of the month. such as April 31th.
17837c478bd9Sstevel@tonic-gate * 2. Feb 29th in the non-leap year.
17847c478bd9Sstevel@tonic-gate * 3. Time gap during the DST switch over.
17857c478bd9Sstevel@tonic-gate */
17867c478bd9Sstevel@tonic-gate d1 = days_in_mon(mon, yr);
17877c478bd9Sstevel@tonic-gate if ((mon != 1 && day > d1) || (mon == 1 && day > 29)) {
17887c478bd9Sstevel@tonic-gate /*
17897c478bd9Sstevel@tonic-gate * see if we have got a specific date which
17907c478bd9Sstevel@tonic-gate * is invalid.
17917c478bd9Sstevel@tonic-gate */
17927c478bd9Sstevel@tonic-gate if (strcmp(e->of.ct.dayweek, "*") == 0 &&
17934c4c9110Sbasabi mon == (next_ge((mon + 1)%12 + 1,
17944c4c9110Sbasabi e->of.ct.month) - 1) &&
17957c478bd9Sstevel@tonic-gate day <= next_ge(1, e->of.ct.daymon)) {
17967c478bd9Sstevel@tonic-gate /* job never run */
17977c478bd9Sstevel@tonic-gate return (0);
17987c478bd9Sstevel@tonic-gate }
17997c478bd9Sstevel@tonic-gate /*
18007c478bd9Sstevel@tonic-gate * Since the day has gone invalid, we need to go to
18017c478bd9Sstevel@tonic-gate * next month, and recalcuate the first occurrence.
18027c478bd9Sstevel@tonic-gate * eg the cron tab such as:
18037c478bd9Sstevel@tonic-gate * 0 0 1,15,31 1,2,3,4,5 * /usr/bin....
18047c478bd9Sstevel@tonic-gate * 2/31 is invalid, so the next job is 3/1.
18057c478bd9Sstevel@tonic-gate */
18067c478bd9Sstevel@tonic-gate tmp2 = tmp;
18077c478bd9Sstevel@tonic-gate tmp2.tm_min = 0;
18087c478bd9Sstevel@tonic-gate tmp2.tm_hour = 0;
18097c478bd9Sstevel@tonic-gate tmp2.tm_mday = 1; /* 1st day of the month */
18107c478bd9Sstevel@tonic-gate if (mon == 11) {
18117c478bd9Sstevel@tonic-gate tmp2.tm_mon = 0;
18127c478bd9Sstevel@tonic-gate tmp2.tm_year = yr + 1;
18137c478bd9Sstevel@tonic-gate } else {
18147c478bd9Sstevel@tonic-gate tmp2.tm_mon = mon + 1;
18157c478bd9Sstevel@tonic-gate }
18167c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp2)) == (time_t)-1) {
18177c478bd9Sstevel@tonic-gate return (0);
18187c478bd9Sstevel@tonic-gate }
18197c478bd9Sstevel@tonic-gate } else if (mon == 1 && day > d1) {
18207c478bd9Sstevel@tonic-gate /*
18217c478bd9Sstevel@tonic-gate * ie 29th in the non-leap year. Forwarding the
18227c478bd9Sstevel@tonic-gate * clock to Feb 29th 00:00 (March 1st), and recalculate
18237c478bd9Sstevel@tonic-gate * the next time.
18247c478bd9Sstevel@tonic-gate */
18257c478bd9Sstevel@tonic-gate tmp2 = tmp;
18267c478bd9Sstevel@tonic-gate tmp2.tm_min = 0;
18277c478bd9Sstevel@tonic-gate tmp2.tm_hour = 0;
18287c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp2)) == (time_t)-1) {
18297c478bd9Sstevel@tonic-gate return (0);
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate } else if (daylight) {
18327c478bd9Sstevel@tonic-gate /*
18337c478bd9Sstevel@tonic-gate * Non existing time, eg 2am PST during summer time
18347c478bd9Sstevel@tonic-gate * switch.
18357c478bd9Sstevel@tonic-gate * We need to get the correct isdst which we are
18367c478bd9Sstevel@tonic-gate * swithing to, by adding time difference to make sure
18377c478bd9Sstevel@tonic-gate * that t2 is in the zone being switched.
18387c478bd9Sstevel@tonic-gate */
18397c478bd9Sstevel@tonic-gate t2 = t1;
18407c478bd9Sstevel@tonic-gate t2 += abs(timezone - altzone);
18417c478bd9Sstevel@tonic-gate (void) localtime_r(&t2, &tmp2);
18427c478bd9Sstevel@tonic-gate zone_start = get_switching_time(tmp2.tm_isdst,
18437c478bd9Sstevel@tonic-gate t1 - abs(timezone - altzone));
18447c478bd9Sstevel@tonic-gate if (zone_start == (time_t)-1) {
18457c478bd9Sstevel@tonic-gate return (0);
18467c478bd9Sstevel@tonic-gate }
18477c478bd9Sstevel@tonic-gate t = zone_start;
18487c478bd9Sstevel@tonic-gate } else {
18497c478bd9Sstevel@tonic-gate /*
18507c478bd9Sstevel@tonic-gate * This should never happen, but fall back to the
18517c478bd9Sstevel@tonic-gate * old code.
18527c478bd9Sstevel@tonic-gate */
18537c478bd9Sstevel@tonic-gate days = days_btwn(tm->tm_mon,
18547c478bd9Sstevel@tonic-gate tm->tm_mday, tm->tm_year, mon, day, yr);
18557c478bd9Sstevel@tonic-gate t += (time_t)(23-tm->tm_hour)*HOUR
18567c478bd9Sstevel@tonic-gate + (time_t)(60-tm->tm_min)*MINUTE
18577c478bd9Sstevel@tonic-gate + (time_t)hr*HOUR + (time_t)min*MINUTE
18587c478bd9Sstevel@tonic-gate + (time_t)days*DAY;
18597c478bd9Sstevel@tonic-gate t1 = t;
18607c478bd9Sstevel@tonic-gate t -= (time_t)tm->tm_sec;
18617c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp);
18627c478bd9Sstevel@tonic-gate if ((tm->tm_isdst == 0) && (tmp.tm_isdst > 0))
18637c478bd9Sstevel@tonic-gate t -= (timezone - altzone);
18647c478bd9Sstevel@tonic-gate return (t <= ref_t ? t1 : t);
18657c478bd9Sstevel@tonic-gate }
18667c478bd9Sstevel@tonic-gate goto recalc;
18677c478bd9Sstevel@tonic-gate }
18687c478bd9Sstevel@tonic-gate /*NOTREACHED*/
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate
18715b08e637SChris Gerhard static time_t
next_time(struct event * e,time_t tflag)18725b08e637SChris Gerhard next_time(struct event *e, time_t tflag)
18735b08e637SChris Gerhard {
18745b08e637SChris Gerhard time_t ret;
18755b08e637SChris Gerhard
1876618372bcSSebastian Wiedenroth if (e->of.ct.tz != NULL) {
18775b08e637SChris Gerhard (void) putenv((char *)get_obj(e->of.ct.tz));
18785b08e637SChris Gerhard tzset();
18795b08e637SChris Gerhard ret = tz_next_time(e, tflag);
18805b08e637SChris Gerhard (void) putenv(tzone);
18815b08e637SChris Gerhard tzset();
18825b08e637SChris Gerhard } else {
1883618372bcSSebastian Wiedenroth ret = tz_next_time(e, tflag);
18845b08e637SChris Gerhard }
1885618372bcSSebastian Wiedenroth
1886618372bcSSebastian Wiedenroth if (e->of.ct.max_random_delay > 0) {
1887618372bcSSebastian Wiedenroth ret += arc4random_uniform(e->of.ct.max_random_delay * 60 - 1);
1888618372bcSSebastian Wiedenroth }
1889618372bcSSebastian Wiedenroth return (ret);
18905b08e637SChris Gerhard }
18915b08e637SChris Gerhard
18927c478bd9Sstevel@tonic-gate /*
18937c478bd9Sstevel@tonic-gate * This returns TOD in time_t that zone switch will happen, and this
18947c478bd9Sstevel@tonic-gate * will be called when clock fallback is about to happen.
18957c478bd9Sstevel@tonic-gate * (ie 30minutes before the time of PST -> PDT switch. 2:00 AM PST
18967c478bd9Sstevel@tonic-gate * will fall back to 1:00 PDT. So this function will be called only
18977c478bd9Sstevel@tonic-gate * for the time between 1:00 AM PST and 2:00 PST(1:00 PST)).
18987c478bd9Sstevel@tonic-gate * First goes through the common time differences to see if zone
18997c478bd9Sstevel@tonic-gate * switch happens at those minutes later. If not, check every minutes
19007c478bd9Sstevel@tonic-gate * until 6 hours ahead see if it happens(We might have 45minutes
19017c478bd9Sstevel@tonic-gate * fallback).
19027c478bd9Sstevel@tonic-gate */
19037c478bd9Sstevel@tonic-gate static time_t
get_switching_time(int to_dst,time_t t_ref)19047c478bd9Sstevel@tonic-gate get_switching_time(int to_dst, time_t t_ref)
19057c478bd9Sstevel@tonic-gate {
19067c478bd9Sstevel@tonic-gate time_t t, t1;
19077c478bd9Sstevel@tonic-gate struct tm tmp, tmp1;
19087c478bd9Sstevel@tonic-gate int hints[] = { 60, 120, 30, 90, 0}; /* minutes */
19097c478bd9Sstevel@tonic-gate int i;
19107c478bd9Sstevel@tonic-gate
19117c478bd9Sstevel@tonic-gate (void) localtime_r(&t_ref, &tmp);
19127c478bd9Sstevel@tonic-gate tmp1 = tmp;
19137c478bd9Sstevel@tonic-gate tmp1.tm_sec = 0;
19147c478bd9Sstevel@tonic-gate tmp1.tm_min = 0;
19157c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp1)) == (time_t)-1)
19167c478bd9Sstevel@tonic-gate return ((time_t)-1);
19177c478bd9Sstevel@tonic-gate
19187c478bd9Sstevel@tonic-gate /* fast path */
19197c478bd9Sstevel@tonic-gate for (i = 0; hints[i] != 0; i++) {
19207c478bd9Sstevel@tonic-gate t1 = t + hints[i] * 60;
19217c478bd9Sstevel@tonic-gate (void) localtime_r(&t1, &tmp1);
19227c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst == to_dst) {
19237c478bd9Sstevel@tonic-gate t1--;
19247c478bd9Sstevel@tonic-gate (void) localtime_r(&t1, &tmp1);
19257c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst != to_dst) {
19267c478bd9Sstevel@tonic-gate return (t1 + 1);
19277c478bd9Sstevel@tonic-gate }
19287c478bd9Sstevel@tonic-gate }
19297c478bd9Sstevel@tonic-gate }
19307c478bd9Sstevel@tonic-gate
19317c478bd9Sstevel@tonic-gate /* ugly, but don't know other than this. */
19327c478bd9Sstevel@tonic-gate tmp1 = tmp;
19337c478bd9Sstevel@tonic-gate tmp1.tm_sec = 0;
19347c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp1)) == (time_t)-1)
19357c478bd9Sstevel@tonic-gate return ((time_t)-1);
19367c478bd9Sstevel@tonic-gate while (t < (t_ref + 6*60*60)) { /* 6 hours should be enough */
19377c478bd9Sstevel@tonic-gate t += 60; /* at least one minute, I assume */
19387c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp);
19397c478bd9Sstevel@tonic-gate if (tmp.tm_isdst == to_dst)
19407c478bd9Sstevel@tonic-gate return (t);
19417c478bd9Sstevel@tonic-gate }
19427c478bd9Sstevel@tonic-gate return ((time_t)-1);
19437c478bd9Sstevel@tonic-gate }
19447c478bd9Sstevel@tonic-gate
19457c478bd9Sstevel@tonic-gate static time_t
xmktime(struct tm * tmp)19467c478bd9Sstevel@tonic-gate xmktime(struct tm *tmp)
19477c478bd9Sstevel@tonic-gate {
19487c478bd9Sstevel@tonic-gate time_t ret;
19497c478bd9Sstevel@tonic-gate
19507c478bd9Sstevel@tonic-gate if ((ret = mktime(tmp)) == (time_t)-1) {
19517c478bd9Sstevel@tonic-gate if (errno == EOVERFLOW) {
19527c478bd9Sstevel@tonic-gate return ((time_t)-1);
19537c478bd9Sstevel@tonic-gate }
19547c478bd9Sstevel@tonic-gate crabort("internal error: mktime failed",
19557c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG);
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate return (ret);
19587c478bd9Sstevel@tonic-gate }
19597c478bd9Sstevel@tonic-gate
19607c478bd9Sstevel@tonic-gate #define DUMMY 100
19617c478bd9Sstevel@tonic-gate
19627c478bd9Sstevel@tonic-gate static int
next_ge(int current,char * list)19637c478bd9Sstevel@tonic-gate next_ge(int current, char *list)
19647c478bd9Sstevel@tonic-gate {
19657c478bd9Sstevel@tonic-gate /*
19667c478bd9Sstevel@tonic-gate * list is a character field as in a crontab file;
19677c478bd9Sstevel@tonic-gate * for example: "40, 20, 50-10"
19687c478bd9Sstevel@tonic-gate * next_ge returns the next number in the list that is
19697c478bd9Sstevel@tonic-gate * greater than or equal to current. if no numbers of list
19707c478bd9Sstevel@tonic-gate * are >= current, the smallest element of list is returned.
19717c478bd9Sstevel@tonic-gate * NOTE: current must be in the appropriate range.
19727c478bd9Sstevel@tonic-gate */
19737c478bd9Sstevel@tonic-gate
19747c478bd9Sstevel@tonic-gate char *ptr;
19757c478bd9Sstevel@tonic-gate int n, n2, min, min_gt;
19767c478bd9Sstevel@tonic-gate
19777c478bd9Sstevel@tonic-gate if (strcmp(list, "*") == 0)
19787c478bd9Sstevel@tonic-gate return (current);
19797c478bd9Sstevel@tonic-gate ptr = list;
19807c478bd9Sstevel@tonic-gate min = DUMMY;
19817c478bd9Sstevel@tonic-gate min_gt = DUMMY;
19827c478bd9Sstevel@tonic-gate for (;;) {
19837c478bd9Sstevel@tonic-gate if ((n = (int)num(&ptr)) == current)
19847c478bd9Sstevel@tonic-gate return (current);
19857c478bd9Sstevel@tonic-gate if (n < min)
19867c478bd9Sstevel@tonic-gate min = n;
19877c478bd9Sstevel@tonic-gate if ((n > current) && (n < min_gt))
19887c478bd9Sstevel@tonic-gate min_gt = n;
19897c478bd9Sstevel@tonic-gate if (*ptr == '-') {
19907c478bd9Sstevel@tonic-gate ptr++;
19917c478bd9Sstevel@tonic-gate if ((n2 = (int)num(&ptr)) > n) {
19927c478bd9Sstevel@tonic-gate if ((current > n) && (current <= n2))
19937c478bd9Sstevel@tonic-gate return (current);
19947c478bd9Sstevel@tonic-gate } else { /* range that wraps around */
19957c478bd9Sstevel@tonic-gate if (current > n)
19967c478bd9Sstevel@tonic-gate return (current);
19977c478bd9Sstevel@tonic-gate if (current <= n2)
19987c478bd9Sstevel@tonic-gate return (current);
19997c478bd9Sstevel@tonic-gate }
20007c478bd9Sstevel@tonic-gate }
20017c478bd9Sstevel@tonic-gate if (*ptr == '\0')
20027c478bd9Sstevel@tonic-gate break;
20037c478bd9Sstevel@tonic-gate ptr += 1;
20047c478bd9Sstevel@tonic-gate }
20057c478bd9Sstevel@tonic-gate if (min_gt != DUMMY)
20067c478bd9Sstevel@tonic-gate return (min_gt);
20077c478bd9Sstevel@tonic-gate else
20087c478bd9Sstevel@tonic-gate return (min);
20097c478bd9Sstevel@tonic-gate }
20107c478bd9Sstevel@tonic-gate
20117c478bd9Sstevel@tonic-gate static void
free_if_unused(struct usr * u)20127c478bd9Sstevel@tonic-gate free_if_unused(struct usr *u)
20137c478bd9Sstevel@tonic-gate {
20147c478bd9Sstevel@tonic-gate struct usr *cur, *prev;
20157c478bd9Sstevel@tonic-gate /*
20167c478bd9Sstevel@tonic-gate * To make sure a usr structure is idle we must check that
20177c478bd9Sstevel@tonic-gate * there are no at jobs queued for the user; the user does
20187c478bd9Sstevel@tonic-gate * not have a crontab, and also that there are no running at
20197c478bd9Sstevel@tonic-gate * or cron jobs (since the runinfo structure also has a
20207c478bd9Sstevel@tonic-gate * pointer to the usr structure).
20217c478bd9Sstevel@tonic-gate */
20227c478bd9Sstevel@tonic-gate if (!u->ctexists && u->atevents == NULL &&
20237c478bd9Sstevel@tonic-gate u->cruncnt == 0 && u->aruncnt == 0) {
20247c478bd9Sstevel@tonic-gate #ifdef DEBUG
20257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s removed from usr list\n", u->name);
20267c478bd9Sstevel@tonic-gate #endif
20277c478bd9Sstevel@tonic-gate for (cur = uhead, prev = NULL;
20287c478bd9Sstevel@tonic-gate cur != u;
20297c478bd9Sstevel@tonic-gate prev = cur, cur = cur->nextusr) {
20307c478bd9Sstevel@tonic-gate if (cur == NULL) {
20317c478bd9Sstevel@tonic-gate return;
20327c478bd9Sstevel@tonic-gate }
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate
20357c478bd9Sstevel@tonic-gate if (prev == NULL)
20367c478bd9Sstevel@tonic-gate uhead = u->nextusr;
20377c478bd9Sstevel@tonic-gate else
20387c478bd9Sstevel@tonic-gate prev->nextusr = u->nextusr;
20397c478bd9Sstevel@tonic-gate free(u->name);
20407c478bd9Sstevel@tonic-gate free(u->home);
20417c478bd9Sstevel@tonic-gate free(u);
20427c478bd9Sstevel@tonic-gate }
20437c478bd9Sstevel@tonic-gate }
20447c478bd9Sstevel@tonic-gate
20457c478bd9Sstevel@tonic-gate static void
del_atjob(char * name,char * usrname)20467c478bd9Sstevel@tonic-gate del_atjob(char *name, char *usrname)
20477c478bd9Sstevel@tonic-gate {
20487c478bd9Sstevel@tonic-gate
20497c478bd9Sstevel@tonic-gate struct event *e, *eprev;
20507c478bd9Sstevel@tonic-gate struct usr *u;
20517c478bd9Sstevel@tonic-gate
20527c478bd9Sstevel@tonic-gate if ((u = find_usr(usrname)) == NULL)
20537c478bd9Sstevel@tonic-gate return;
20547c478bd9Sstevel@tonic-gate e = u->atevents;
20557c478bd9Sstevel@tonic-gate eprev = NULL;
20567c478bd9Sstevel@tonic-gate while (e != NULL) {
20577c478bd9Sstevel@tonic-gate if (strcmp(name, e->cmd) == 0) {
20587c478bd9Sstevel@tonic-gate if (next_event == e)
20597c478bd9Sstevel@tonic-gate next_event = NULL;
20607c478bd9Sstevel@tonic-gate if (eprev == NULL)
20617c478bd9Sstevel@tonic-gate u->atevents = e->link;
20627c478bd9Sstevel@tonic-gate else
20637c478bd9Sstevel@tonic-gate eprev->link = e->link;
20647c478bd9Sstevel@tonic-gate el_remove(e->of.at.eventid, 1);
20657c478bd9Sstevel@tonic-gate free(e->cmd);
20667c478bd9Sstevel@tonic-gate free(e);
20677c478bd9Sstevel@tonic-gate break;
20687c478bd9Sstevel@tonic-gate } else {
20697c478bd9Sstevel@tonic-gate eprev = e;
20707c478bd9Sstevel@tonic-gate e = e->link;
20717c478bd9Sstevel@tonic-gate }
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate
20747c478bd9Sstevel@tonic-gate free_if_unused(u);
20757c478bd9Sstevel@tonic-gate }
20767c478bd9Sstevel@tonic-gate
20777c478bd9Sstevel@tonic-gate static void
del_ctab(char * name)20787c478bd9Sstevel@tonic-gate del_ctab(char *name)
20797c478bd9Sstevel@tonic-gate {
20807c478bd9Sstevel@tonic-gate
20817c478bd9Sstevel@tonic-gate struct usr *u;
20827c478bd9Sstevel@tonic-gate
20837c478bd9Sstevel@tonic-gate if ((u = find_usr(name)) == NULL)
20847c478bd9Sstevel@tonic-gate return;
20857c478bd9Sstevel@tonic-gate rm_ctevents(u);
20867c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0);
20877c478bd9Sstevel@tonic-gate u->ctid = 0;
20887c478bd9Sstevel@tonic-gate u->ctexists = 0;
20897c478bd9Sstevel@tonic-gate
20907c478bd9Sstevel@tonic-gate free_if_unused(u);
20917c478bd9Sstevel@tonic-gate }
20927c478bd9Sstevel@tonic-gate
20937c478bd9Sstevel@tonic-gate static void
rm_ctevents(struct usr * u)20947c478bd9Sstevel@tonic-gate rm_ctevents(struct usr *u)
20957c478bd9Sstevel@tonic-gate {
20967c478bd9Sstevel@tonic-gate struct event *e2, *e3;
20977c478bd9Sstevel@tonic-gate
20987c478bd9Sstevel@tonic-gate /*
20997c478bd9Sstevel@tonic-gate * see if the next event (to be run by cron) is a cronevent
21007c478bd9Sstevel@tonic-gate * owned by this user.
21017c478bd9Sstevel@tonic-gate */
21027c478bd9Sstevel@tonic-gate
21037c478bd9Sstevel@tonic-gate if ((next_event != NULL) &&
21047c478bd9Sstevel@tonic-gate (next_event->etype == CRONEVENT) &&
21057c478bd9Sstevel@tonic-gate (next_event->u == u)) {
21067c478bd9Sstevel@tonic-gate next_event = NULL;
21077c478bd9Sstevel@tonic-gate }
21087c478bd9Sstevel@tonic-gate e2 = u->ctevents;
21097c478bd9Sstevel@tonic-gate while (e2 != NULL) {
21107c478bd9Sstevel@tonic-gate free(e2->cmd);
21115b08e637SChris Gerhard rel_shared(e2->of.ct.tz);
21125b08e637SChris Gerhard rel_shared(e2->of.ct.shell);
21135b08e637SChris Gerhard rel_shared(e2->of.ct.home);
21147c478bd9Sstevel@tonic-gate free(e2->of.ct.minute);
21157c478bd9Sstevel@tonic-gate free(e2->of.ct.hour);
21167c478bd9Sstevel@tonic-gate free(e2->of.ct.daymon);
21177c478bd9Sstevel@tonic-gate free(e2->of.ct.month);
21187c478bd9Sstevel@tonic-gate free(e2->of.ct.dayweek);
21197c478bd9Sstevel@tonic-gate if (e2->of.ct.input != NULL)
21207c478bd9Sstevel@tonic-gate free(e2->of.ct.input);
21217c478bd9Sstevel@tonic-gate e3 = e2->link;
21227c478bd9Sstevel@tonic-gate free(e2);
21237c478bd9Sstevel@tonic-gate e2 = e3;
21247c478bd9Sstevel@tonic-gate }
21257c478bd9Sstevel@tonic-gate u->ctevents = NULL;
21267c478bd9Sstevel@tonic-gate }
21277c478bd9Sstevel@tonic-gate
21287c478bd9Sstevel@tonic-gate
21297c478bd9Sstevel@tonic-gate static struct usr *
find_usr(char * uname)21307c478bd9Sstevel@tonic-gate find_usr(char *uname)
21317c478bd9Sstevel@tonic-gate {
21327c478bd9Sstevel@tonic-gate struct usr *u;
21337c478bd9Sstevel@tonic-gate
21347c478bd9Sstevel@tonic-gate u = uhead;
21357c478bd9Sstevel@tonic-gate while (u != NULL) {
21367c478bd9Sstevel@tonic-gate if (strcmp(u->name, uname) == 0)
21377c478bd9Sstevel@tonic-gate return (u);
21387c478bd9Sstevel@tonic-gate u = u->nextusr;
21397c478bd9Sstevel@tonic-gate }
21407c478bd9Sstevel@tonic-gate return (NULL);
21417c478bd9Sstevel@tonic-gate }
21427c478bd9Sstevel@tonic-gate
21437c478bd9Sstevel@tonic-gate /*
21447c478bd9Sstevel@tonic-gate * Execute cron command or at/batch job.
21457c478bd9Sstevel@tonic-gate * If ever a premature return is added to this function pay attention to
21467c478bd9Sstevel@tonic-gate * free at_cmdfile and outfile plus jobname buffers of the runinfo structure.
21477c478bd9Sstevel@tonic-gate */
21487c478bd9Sstevel@tonic-gate static int
ex(struct event * e)21497c478bd9Sstevel@tonic-gate ex(struct event *e)
21507c478bd9Sstevel@tonic-gate {
21517c478bd9Sstevel@tonic-gate int r;
21527c478bd9Sstevel@tonic-gate int fd;
21537c478bd9Sstevel@tonic-gate pid_t rfork;
21547c478bd9Sstevel@tonic-gate FILE *atcmdfp;
21557c478bd9Sstevel@tonic-gate char mailvar[4];
21567c478bd9Sstevel@tonic-gate char *at_cmdfile = NULL;
21577c478bd9Sstevel@tonic-gate struct stat buf;
21587c478bd9Sstevel@tonic-gate struct queue *qp;
21597c478bd9Sstevel@tonic-gate struct runinfo *rp;
21607c478bd9Sstevel@tonic-gate struct project proj, *pproj = NULL;
21615b08e637SChris Gerhard union {
21625b08e637SChris Gerhard struct {
21635b08e637SChris Gerhard char buf[PROJECT_BUFSZ];
21645b08e637SChris Gerhard char buf2[PROJECT_BUFSZ];
21655b08e637SChris Gerhard } p;
21665b08e637SChris Gerhard char error[CANT_STR_LEN + PATH_MAX];
21675b08e637SChris Gerhard } bufs;
21687c478bd9Sstevel@tonic-gate char *tmpfile;
21697c478bd9Sstevel@tonic-gate FILE *fptr;
21707c478bd9Sstevel@tonic-gate time_t dhltime;
21717c478bd9Sstevel@tonic-gate projid_t projid;
21727c478bd9Sstevel@tonic-gate int projflag = 0;
21735b08e637SChris Gerhard char *home;
21745b08e637SChris Gerhard char *sh;
21757c478bd9Sstevel@tonic-gate
21767c478bd9Sstevel@tonic-gate qp = &qt[e->etype]; /* set pointer to queue defs */
21777c478bd9Sstevel@tonic-gate if (qp->nrun >= qp->njob) {
21787c478bd9Sstevel@tonic-gate msg("%c queue max run limit reached", e->etype + 'a');
21797c478bd9Sstevel@tonic-gate resched(qp->nwait);
21807c478bd9Sstevel@tonic-gate return (0);
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate
2183d1419d5aSNobutomo Nakano rp = rinfo_get(0); /* allocating a new runinfo struct */
21847c478bd9Sstevel@tonic-gate
21857c478bd9Sstevel@tonic-gate /*
21867c478bd9Sstevel@tonic-gate * the tempnam() function uses malloc(3C) to allocate space for the
21877c478bd9Sstevel@tonic-gate * constructed file name, and returns a pointer to this area, which
21887c478bd9Sstevel@tonic-gate * is assigned to rp->outfile. Here rp->outfile is not overwritten.
21897c478bd9Sstevel@tonic-gate */
21907c478bd9Sstevel@tonic-gate
21917c478bd9Sstevel@tonic-gate rp->outfile = tempnam(TMPDIR, PFX);
21927c478bd9Sstevel@tonic-gate rp->jobtype = e->etype;
21937c478bd9Sstevel@tonic-gate if (e->etype == CRONEVENT) {
21947c478bd9Sstevel@tonic-gate rp->jobname = xmalloc(strlen(e->cmd) + 1);
21957c478bd9Sstevel@tonic-gate (void) strcpy(rp->jobname, e->cmd);
21967c478bd9Sstevel@tonic-gate /* "cron" jobs only produce mail if there's output */
21977c478bd9Sstevel@tonic-gate rp->mailwhendone = 0;
21987c478bd9Sstevel@tonic-gate } else {
21997c478bd9Sstevel@tonic-gate at_cmdfile = xmalloc(strlen(ATDIR) + strlen(e->cmd) + 2);
22007c478bd9Sstevel@tonic-gate (void) sprintf(at_cmdfile, "%s/%s", ATDIR, e->cmd);
22017c478bd9Sstevel@tonic-gate if ((atcmdfp = fopen(at_cmdfile, "r")) == NULL) {
22027c478bd9Sstevel@tonic-gate if (errno == ENAMETOOLONG) {
22037c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == 0)
22047c478bd9Sstevel@tonic-gate cron_unlink(e->cmd);
22057c478bd9Sstevel@tonic-gate } else {
22067c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile);
22077c478bd9Sstevel@tonic-gate }
22087c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECAT);
22097c478bd9Sstevel@tonic-gate free(at_cmdfile);
22107c478bd9Sstevel@tonic-gate rinfo_free(rp);
22117c478bd9Sstevel@tonic-gate return (0);
22127c478bd9Sstevel@tonic-gate }
22137c478bd9Sstevel@tonic-gate rp->jobname = xmalloc(strlen(at_cmdfile) + 1);
22147c478bd9Sstevel@tonic-gate (void) strcpy(rp->jobname, at_cmdfile);
22157c478bd9Sstevel@tonic-gate
22167c478bd9Sstevel@tonic-gate /*
22177c478bd9Sstevel@tonic-gate * Skip over the first two lines.
22187c478bd9Sstevel@tonic-gate */
22197c478bd9Sstevel@tonic-gate (void) fscanf(atcmdfp, "%*[^\n]\n");
22207c478bd9Sstevel@tonic-gate (void) fscanf(atcmdfp, "%*[^\n]\n");
22217c478bd9Sstevel@tonic-gate if (fscanf(atcmdfp, ": notify by mail: %3s%*[^\n]\n",
22227c478bd9Sstevel@tonic-gate mailvar) == 1) {
22237c478bd9Sstevel@tonic-gate /*
22247c478bd9Sstevel@tonic-gate * Check to see if we should always send mail
22257c478bd9Sstevel@tonic-gate * to the owner.
22267c478bd9Sstevel@tonic-gate */
22277c478bd9Sstevel@tonic-gate rp->mailwhendone = (strcmp(mailvar, "yes") == 0);
22287c478bd9Sstevel@tonic-gate } else {
22297c478bd9Sstevel@tonic-gate rp->mailwhendone = 0;
22307c478bd9Sstevel@tonic-gate }
22317c478bd9Sstevel@tonic-gate
22327c478bd9Sstevel@tonic-gate if (fscanf(atcmdfp, "\n: project: %d\n", &projid) == 1) {
22337c478bd9Sstevel@tonic-gate projflag = 1;
22347c478bd9Sstevel@tonic-gate }
22357c478bd9Sstevel@tonic-gate (void) fclose(atcmdfp);
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate
22387c478bd9Sstevel@tonic-gate /*
22397c478bd9Sstevel@tonic-gate * we make sure that the system time
22407c478bd9Sstevel@tonic-gate * hasn't drifted backwards. if it has, el_add() is now
22417c478bd9Sstevel@tonic-gate * called, to make sure that the event queue is back in order,
22427c478bd9Sstevel@tonic-gate * and we set the delayed flag. cron will pick up the request
22437c478bd9Sstevel@tonic-gate * later on at the proper time.
22447c478bd9Sstevel@tonic-gate */
22457c478bd9Sstevel@tonic-gate dhltime = time(NULL);
22467c478bd9Sstevel@tonic-gate if ((dhltime - e->time) < 0) {
22477c478bd9Sstevel@tonic-gate msg("clock time drifted backwards!\n");
22487c478bd9Sstevel@tonic-gate if (next_event->etype == CRONEVENT) {
22497c478bd9Sstevel@tonic-gate msg("correcting cron event\n");
22507c478bd9Sstevel@tonic-gate next_event->time = next_time(next_event, dhltime);
2251e2553d68SSerge Dussud switch (el_add(next_event, next_event->time,
2252e2553d68SSerge Dussud (next_event->u)->ctid)) {
2253e2553d68SSerge Dussud case -1:
2254e2553d68SSerge Dussud ignore_msg("ex", "cron", next_event);
2255e2553d68SSerge Dussud break;
2256e2553d68SSerge Dussud case -2: /* event time lower than init time */
2257e2553d68SSerge Dussud reset_needed = 1;
2258e2553d68SSerge Dussud break;
2259e2553d68SSerge Dussud }
22607c478bd9Sstevel@tonic-gate } else { /* etype == ATEVENT */
22617c478bd9Sstevel@tonic-gate msg("correcting batch event\n");
2262e2553d68SSerge Dussud if (el_add(next_event, next_event->time,
2263e2553d68SSerge Dussud next_event->of.at.eventid) < 0) {
2264e2553d68SSerge Dussud ignore_msg("ex", "at", next_event);
2265e2553d68SSerge Dussud }
22667c478bd9Sstevel@tonic-gate }
22677c478bd9Sstevel@tonic-gate delayed++;
22687c478bd9Sstevel@tonic-gate t_old = time(NULL);
22697c478bd9Sstevel@tonic-gate free(at_cmdfile);
22707c478bd9Sstevel@tonic-gate rinfo_free(rp);
22717c478bd9Sstevel@tonic-gate return (0);
22727c478bd9Sstevel@tonic-gate }
22737c478bd9Sstevel@tonic-gate
22747c478bd9Sstevel@tonic-gate if ((rfork = fork()) == (pid_t)-1) {
22757c478bd9Sstevel@tonic-gate reap_child();
22767c478bd9Sstevel@tonic-gate if ((rfork = fork()) == (pid_t)-1) {
22777c478bd9Sstevel@tonic-gate msg("cannot fork");
22787c478bd9Sstevel@tonic-gate free(at_cmdfile);
22797c478bd9Sstevel@tonic-gate rinfo_free(rp);
22807c478bd9Sstevel@tonic-gate resched(60);
22817c478bd9Sstevel@tonic-gate (void) sleep(30);
22827c478bd9Sstevel@tonic-gate return (0);
22837c478bd9Sstevel@tonic-gate }
22847c478bd9Sstevel@tonic-gate }
22857c478bd9Sstevel@tonic-gate if (rfork) { /* parent process */
22867c478bd9Sstevel@tonic-gate contract_abandon_latest(rfork);
22877c478bd9Sstevel@tonic-gate
22887c478bd9Sstevel@tonic-gate ++qp->nrun;
22897c478bd9Sstevel@tonic-gate rp->pid = rfork;
22907c478bd9Sstevel@tonic-gate rp->que = e->etype;
22917c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT)
22927c478bd9Sstevel@tonic-gate (e->u)->aruncnt++;
22937c478bd9Sstevel@tonic-gate else
22947c478bd9Sstevel@tonic-gate (e->u)->cruncnt++;
22957c478bd9Sstevel@tonic-gate rp->rusr = (e->u);
22967c478bd9Sstevel@tonic-gate logit(BCHAR, rp, 0);
22977c478bd9Sstevel@tonic-gate free(at_cmdfile);
22987c478bd9Sstevel@tonic-gate
22997c478bd9Sstevel@tonic-gate return (0);
23007c478bd9Sstevel@tonic-gate }
23017c478bd9Sstevel@tonic-gate
23027c478bd9Sstevel@tonic-gate child_sigreset();
23037c478bd9Sstevel@tonic-gate contract_clear_template();
23047c478bd9Sstevel@tonic-gate
23057c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) {
23067c478bd9Sstevel@tonic-gate /* open jobfile as stdin to shell */
23077c478bd9Sstevel@tonic-gate if (stat(at_cmdfile, &buf)) {
23087c478bd9Sstevel@tonic-gate if (errno == ENAMETOOLONG) {
23097c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == 0)
23107c478bd9Sstevel@tonic-gate cron_unlink(e->cmd);
23117c478bd9Sstevel@tonic-gate } else
23127c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile);
23137c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECCRON);
23147c478bd9Sstevel@tonic-gate exit(1);
23157c478bd9Sstevel@tonic-gate }
23167c478bd9Sstevel@tonic-gate if (!(buf.st_mode&ISUID)) {
23177c478bd9Sstevel@tonic-gate /*
23187c478bd9Sstevel@tonic-gate * if setuid bit off, original owner has
23197c478bd9Sstevel@tonic-gate * given this file to someone else
23207c478bd9Sstevel@tonic-gate */
23217c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile);
23227c478bd9Sstevel@tonic-gate exit(1);
23237c478bd9Sstevel@tonic-gate }
23247c478bd9Sstevel@tonic-gate if ((fd = open(at_cmdfile, O_RDONLY)) == -1) {
23257c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECCRON);
23267c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile);
23277c478bd9Sstevel@tonic-gate exit(1);
23287c478bd9Sstevel@tonic-gate }
23297c478bd9Sstevel@tonic-gate if (fd != 0) {
23307c478bd9Sstevel@tonic-gate (void) dup2(fd, 0);
23317c478bd9Sstevel@tonic-gate (void) close(fd);
23327c478bd9Sstevel@tonic-gate }
23337c478bd9Sstevel@tonic-gate /*
23347c478bd9Sstevel@tonic-gate * retrieve the project id of the at job and convert it
23357c478bd9Sstevel@tonic-gate * to a project name. fail if it's not a valid project
23367c478bd9Sstevel@tonic-gate * or if the user isn't a member of the project.
23377c478bd9Sstevel@tonic-gate */
23387c478bd9Sstevel@tonic-gate if (projflag == 1) {
23397c478bd9Sstevel@tonic-gate if ((pproj = getprojbyid(projid, &proj,
23405b08e637SChris Gerhard (void *)&bufs.p.buf,
23415b08e637SChris Gerhard sizeof (bufs.p.buf))) == NULL ||
23427c478bd9Sstevel@tonic-gate !inproj(e->u->name, pproj->pj_name,
23435b08e637SChris Gerhard bufs.p.buf2, sizeof (bufs.p.buf2))) {
23447c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile);
23457c478bd9Sstevel@tonic-gate mail((e->u)->name, BADPROJID, ERR_CANTEXECAT);
23467c478bd9Sstevel@tonic-gate exit(1);
23477c478bd9Sstevel@tonic-gate }
23487c478bd9Sstevel@tonic-gate }
23497c478bd9Sstevel@tonic-gate }
23507c478bd9Sstevel@tonic-gate
23517c478bd9Sstevel@tonic-gate /*
23527c478bd9Sstevel@tonic-gate * Put process in a new session, and create a new task.
23537c478bd9Sstevel@tonic-gate */
23547c478bd9Sstevel@tonic-gate if (setsid() < 0) {
23557c478bd9Sstevel@tonic-gate msg("setsid failed with errno = %d. job failed (%s)"
23567c478bd9Sstevel@tonic-gate " for user %s", errno, e->cmd, e->u->name);
23577c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT)
23587c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile);
23597c478bd9Sstevel@tonic-gate exit(1);
23607c478bd9Sstevel@tonic-gate }
23617c478bd9Sstevel@tonic-gate
23627c478bd9Sstevel@tonic-gate /*
236348bbca81SDaniel Hoffman * set correct user identification and check their account
23647c478bd9Sstevel@tonic-gate */
23657c478bd9Sstevel@tonic-gate r = set_user_cred(e->u, pproj);
23667c478bd9Sstevel@tonic-gate if (r == VUC_EXPIRED) {
23677c478bd9Sstevel@tonic-gate msg("user (%s) account is expired", e->u->name);
23687c478bd9Sstevel@tonic-gate audit_cron_user_acct_expired(e->u->name);
23697c478bd9Sstevel@tonic-gate clean_out_user(e->u);
23707c478bd9Sstevel@tonic-gate exit(1);
23717c478bd9Sstevel@tonic-gate }
23727c478bd9Sstevel@tonic-gate if (r == VUC_NEW_AUTH) {
23737c478bd9Sstevel@tonic-gate msg("user (%s) password has expired", e->u->name);
23747c478bd9Sstevel@tonic-gate audit_cron_user_acct_expired(e->u->name);
23757c478bd9Sstevel@tonic-gate clean_out_user(e->u);
23767c478bd9Sstevel@tonic-gate exit(1);
23777c478bd9Sstevel@tonic-gate }
23787c478bd9Sstevel@tonic-gate if (r != VUC_OK) {
23797c478bd9Sstevel@tonic-gate msg("bad user (%s)", e->u->name);
23807c478bd9Sstevel@tonic-gate audit_cron_bad_user(e->u->name);
23817c478bd9Sstevel@tonic-gate clean_out_user(e->u);
23827c478bd9Sstevel@tonic-gate exit(1);
23837c478bd9Sstevel@tonic-gate }
23847c478bd9Sstevel@tonic-gate /*
23857c478bd9Sstevel@tonic-gate * check user and initialize the supplementary group access list.
23867c478bd9Sstevel@tonic-gate * bugid 1230784: deleted from parent to avoid cron hang. Now
23877c478bd9Sstevel@tonic-gate * only child handles the call.
23887c478bd9Sstevel@tonic-gate */
23897c478bd9Sstevel@tonic-gate
23907c478bd9Sstevel@tonic-gate if (verify_user_cred(e->u) != VUC_OK ||
23917c478bd9Sstevel@tonic-gate setgid(e->u->gid) == -1 ||
23927c478bd9Sstevel@tonic-gate initgroups(e->u->name, e->u->gid) == -1) {
23937c478bd9Sstevel@tonic-gate msg("bad user (%s) or setgid failed (%s)",
23947c478bd9Sstevel@tonic-gate e->u->name, e->u->name);
23957c478bd9Sstevel@tonic-gate audit_cron_bad_user(e->u->name);
23967c478bd9Sstevel@tonic-gate clean_out_user(e->u);
23977c478bd9Sstevel@tonic-gate exit(1);
23987c478bd9Sstevel@tonic-gate }
23997c478bd9Sstevel@tonic-gate
240063d5d94cSjc144527 if ((e->u)->uid == 0) { /* set default path */
240163d5d94cSjc144527 /* path settable in defaults file */
240263d5d94cSjc144527 envinit[2] = supath;
240363d5d94cSjc144527 } else {
240463d5d94cSjc144527 envinit[2] = path;
240563d5d94cSjc144527 }
240663d5d94cSjc144527
24077c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) {
24087c478bd9Sstevel@tonic-gate r = audit_cron_session(e->u->name, NULL,
24094c4c9110Sbasabi e->u->uid, e->u->gid, at_cmdfile);
24107c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile);
24117c478bd9Sstevel@tonic-gate } else {
24127c478bd9Sstevel@tonic-gate r = audit_cron_session(e->u->name, CRONDIR,
24134c4c9110Sbasabi e->u->uid, e->u->gid, NULL);
24147c478bd9Sstevel@tonic-gate }
24157c478bd9Sstevel@tonic-gate if (r != 0) {
24167c478bd9Sstevel@tonic-gate msg("cron audit problem. job failed (%s) for user %s",
24177c478bd9Sstevel@tonic-gate e->cmd, e->u->name);
24187c478bd9Sstevel@tonic-gate exit(1);
24197c478bd9Sstevel@tonic-gate }
24207c478bd9Sstevel@tonic-gate
24217c478bd9Sstevel@tonic-gate audit_cron_new_job(e->cmd, e->etype, (void *)e);
24227c478bd9Sstevel@tonic-gate
24237c478bd9Sstevel@tonic-gate if (setuid(e->u->uid) == -1) {
24247c478bd9Sstevel@tonic-gate msg("setuid failed (%s)", e->u->name);
24257c478bd9Sstevel@tonic-gate clean_out_user(e->u);
24267c478bd9Sstevel@tonic-gate exit(1);
24277c478bd9Sstevel@tonic-gate }
24287c478bd9Sstevel@tonic-gate
24297c478bd9Sstevel@tonic-gate if (e->etype == CRONEVENT) {
24307c478bd9Sstevel@tonic-gate /* check for standard input to command */
24317c478bd9Sstevel@tonic-gate if (e->of.ct.input != NULL) {
24327c478bd9Sstevel@tonic-gate if ((tmpfile = strdup(TMPINFILE)) == NULL) {
24337c478bd9Sstevel@tonic-gate mail((e->u)->name, MALLOCERR,
24347c478bd9Sstevel@tonic-gate ERR_CANTEXECCRON);
24357c478bd9Sstevel@tonic-gate exit(1);
24367c478bd9Sstevel@tonic-gate }
24377c478bd9Sstevel@tonic-gate if ((fd = mkstemp(tmpfile)) == -1 ||
24387c478bd9Sstevel@tonic-gate (fptr = fdopen(fd, "w")) == NULL) {
24397c478bd9Sstevel@tonic-gate mail((e->u)->name, NOSTDIN,
24407c478bd9Sstevel@tonic-gate ERR_CANTEXECCRON);
24417c478bd9Sstevel@tonic-gate cron_unlink(tmpfile);
24427c478bd9Sstevel@tonic-gate free(tmpfile);
24437c478bd9Sstevel@tonic-gate exit(1);
24447c478bd9Sstevel@tonic-gate }
24457c478bd9Sstevel@tonic-gate if ((fwrite(e->of.ct.input, sizeof (char),
24467c478bd9Sstevel@tonic-gate strlen(e->of.ct.input), fptr)) !=
24477c478bd9Sstevel@tonic-gate strlen(e->of.ct.input)) {
24487c478bd9Sstevel@tonic-gate mail((e->u)->name, NOSTDIN, ERR_CANTEXECCRON);
24497c478bd9Sstevel@tonic-gate cron_unlink(tmpfile);
24507c478bd9Sstevel@tonic-gate free(tmpfile);
24517c478bd9Sstevel@tonic-gate (void) close(fd);
24527c478bd9Sstevel@tonic-gate (void) fclose(fptr);
24537c478bd9Sstevel@tonic-gate exit(1);
24547c478bd9Sstevel@tonic-gate }
24557c478bd9Sstevel@tonic-gate if (fseek(fptr, (off_t)0, SEEK_SET) != -1) {
24567c478bd9Sstevel@tonic-gate if (fd != 0) {
24577c478bd9Sstevel@tonic-gate (void) dup2(fd, 0);
24587c478bd9Sstevel@tonic-gate (void) close(fd);
24597c478bd9Sstevel@tonic-gate }
24607c478bd9Sstevel@tonic-gate }
24617c478bd9Sstevel@tonic-gate cron_unlink(tmpfile);
24627c478bd9Sstevel@tonic-gate free(tmpfile);
24637c478bd9Sstevel@tonic-gate (void) fclose(fptr);
24647c478bd9Sstevel@tonic-gate } else if ((fd = open("/dev/null", O_RDONLY)) > 0) {
24657c478bd9Sstevel@tonic-gate (void) dup2(fd, 0);
24667c478bd9Sstevel@tonic-gate (void) close(fd);
24677c478bd9Sstevel@tonic-gate }
24687c478bd9Sstevel@tonic-gate }
24697c478bd9Sstevel@tonic-gate
24707c478bd9Sstevel@tonic-gate /* redirect stdout and stderr for the shell */
24717c478bd9Sstevel@tonic-gate if ((fd = open(rp->outfile, O_WRONLY|O_CREAT|O_EXCL, OUTMODE)) == 1)
24727c478bd9Sstevel@tonic-gate fd = open("/dev/null", O_WRONLY);
24737c478bd9Sstevel@tonic-gate
24747c478bd9Sstevel@tonic-gate if (fd >= 0 && fd != 1)
24757c478bd9Sstevel@tonic-gate (void) dup2(fd, 1);
24767c478bd9Sstevel@tonic-gate
24777c478bd9Sstevel@tonic-gate if (fd >= 0 && fd != 2) {
24787c478bd9Sstevel@tonic-gate (void) dup2(fd, 2);
24797c478bd9Sstevel@tonic-gate if (fd != 1)
24807c478bd9Sstevel@tonic-gate (void) close(fd);
24817c478bd9Sstevel@tonic-gate }
24827c478bd9Sstevel@tonic-gate
24835b08e637SChris Gerhard if (e->etype == CRONEVENT && e->of.ct.home != NULL) {
24845b08e637SChris Gerhard home = (char *)get_obj(e->of.ct.home);
24855b08e637SChris Gerhard } else {
24865b08e637SChris Gerhard home = (e->u)->home;
24875b08e637SChris Gerhard }
24885b08e637SChris Gerhard (void) strlcat(homedir, home, sizeof (homedir));
24897c478bd9Sstevel@tonic-gate (void) strlcat(logname, (e->u)->name, sizeof (logname));
24907c478bd9Sstevel@tonic-gate environ = envinit;
24915b08e637SChris Gerhard if (chdir(home) == -1) {
24925b08e637SChris Gerhard snprintf(bufs.error, sizeof (bufs.error), CANTCDHOME, home);
24935b08e637SChris Gerhard mail((e->u)->name, bufs.error,
24947c478bd9Sstevel@tonic-gate e->etype == CRONEVENT ? ERR_CANTEXECCRON :
24957c478bd9Sstevel@tonic-gate ERR_CANTEXECAT);
24967c478bd9Sstevel@tonic-gate exit(1);
24977c478bd9Sstevel@tonic-gate }
24987c478bd9Sstevel@tonic-gate #ifdef TESTING
24997c478bd9Sstevel@tonic-gate exit(1);
25007c478bd9Sstevel@tonic-gate #endif
25017c478bd9Sstevel@tonic-gate /*
25027c478bd9Sstevel@tonic-gate * make sure that all file descriptors EXCEPT 0, 1 and 2
25037c478bd9Sstevel@tonic-gate * will be closed.
25047c478bd9Sstevel@tonic-gate */
25057c478bd9Sstevel@tonic-gate closefrom(3);
25067c478bd9Sstevel@tonic-gate
25077c478bd9Sstevel@tonic-gate if ((e->u)->uid != 0)
25087c478bd9Sstevel@tonic-gate (void) nice(qp->nice);
25095b08e637SChris Gerhard if (e->etype == CRONEVENT) {
25105b08e637SChris Gerhard if (e->of.ct.tz) {
25115b08e637SChris Gerhard (void) putenv((char *)get_obj(e->of.ct.tz));
25125b08e637SChris Gerhard }
25135b08e637SChris Gerhard if (e->of.ct.shell) {
25145b08e637SChris Gerhard char *name;
25155b08e637SChris Gerhard
25165b08e637SChris Gerhard sh = (char *)get_obj(e->of.ct.shell);
25175b08e637SChris Gerhard name = strrchr(sh, '/');
25185b08e637SChris Gerhard if (name == NULL)
25195b08e637SChris Gerhard name = sh;
25205b08e637SChris Gerhard else
25215b08e637SChris Gerhard name++;
25225b08e637SChris Gerhard
25235b08e637SChris Gerhard (void) putenv(sh);
25245b08e637SChris Gerhard sh += strlen(ENV_SHELL);
25255b08e637SChris Gerhard (void) execl(sh, name, "-c", e->cmd, 0);
25265b08e637SChris Gerhard } else {
25277c478bd9Sstevel@tonic-gate (void) execl(SHELL, "sh", "-c", e->cmd, 0);
25285b08e637SChris Gerhard sh = SHELL;
25295b08e637SChris Gerhard }
25305b08e637SChris Gerhard } else { /* type == ATEVENT */
25317c478bd9Sstevel@tonic-gate (void) execl(SHELL, "sh", 0);
25325b08e637SChris Gerhard sh = SHELL;
25335b08e637SChris Gerhard }
25345b08e637SChris Gerhard snprintf(bufs.error, sizeof (bufs.error), CANTEXECSH, sh);
25355b08e637SChris Gerhard mail((e->u)->name, bufs.error,
25367c478bd9Sstevel@tonic-gate e->etype == CRONEVENT ? ERR_CANTEXECCRON : ERR_CANTEXECAT);
25377c478bd9Sstevel@tonic-gate exit(1);
25387c478bd9Sstevel@tonic-gate /*NOTREACHED*/
25397c478bd9Sstevel@tonic-gate }
25407c478bd9Sstevel@tonic-gate
2541d1419d5aSNobutomo Nakano /*
2542d1419d5aSNobutomo Nakano * Main idle loop.
2543d1419d5aSNobutomo Nakano * When timed out to run the job, return 0.
2544d1419d5aSNobutomo Nakano * If for some reasons we need to reschedule jobs, return 1.
2545d1419d5aSNobutomo Nakano */
25467c478bd9Sstevel@tonic-gate static int
idle(long t)25477c478bd9Sstevel@tonic-gate idle(long t)
25487c478bd9Sstevel@tonic-gate {
25497c478bd9Sstevel@tonic-gate time_t now;
25507c478bd9Sstevel@tonic-gate
2551d1419d5aSNobutomo Nakano refresh = 0;
25527c478bd9Sstevel@tonic-gate
2553d1419d5aSNobutomo Nakano while (t > 0L) {
25547c478bd9Sstevel@tonic-gate if (msg_wait(t) != 0) {
25557c478bd9Sstevel@tonic-gate /* we need to run next job immediately */
25567c478bd9Sstevel@tonic-gate return (0);
25577c478bd9Sstevel@tonic-gate }
25587c478bd9Sstevel@tonic-gate
25597c478bd9Sstevel@tonic-gate reap_child();
25607c478bd9Sstevel@tonic-gate
2561d1419d5aSNobutomo Nakano if (refresh) {
2562d1419d5aSNobutomo Nakano /* We got THAW or REFRESH message */
2563d1419d5aSNobutomo Nakano return (1);
2564d1419d5aSNobutomo Nakano }
2565d1419d5aSNobutomo Nakano
25667c478bd9Sstevel@tonic-gate now = time(NULL);
25677c478bd9Sstevel@tonic-gate if (last_time > now) {
2568d1419d5aSNobutomo Nakano /* clock has been reset to backward */
25697c478bd9Sstevel@tonic-gate return (1);
25707c478bd9Sstevel@tonic-gate }
25717c478bd9Sstevel@tonic-gate
25727c478bd9Sstevel@tonic-gate if (next_event == NULL && !el_empty()) {
25737c478bd9Sstevel@tonic-gate next_event = (struct event *)el_first();
25747c478bd9Sstevel@tonic-gate }
2575d1419d5aSNobutomo Nakano
25767c478bd9Sstevel@tonic-gate if (next_event == NULL)
25777c478bd9Sstevel@tonic-gate t = INFINITY;
25787c478bd9Sstevel@tonic-gate else
25797c478bd9Sstevel@tonic-gate t = (long)next_event->time - now;
25807c478bd9Sstevel@tonic-gate }
25817c478bd9Sstevel@tonic-gate return (0);
25827c478bd9Sstevel@tonic-gate }
25837c478bd9Sstevel@tonic-gate
25847c478bd9Sstevel@tonic-gate /*
25857c478bd9Sstevel@tonic-gate * This used to be in the idle(), but moved to the separate function.
25867c478bd9Sstevel@tonic-gate * This called from various place when cron needs to reap the
25877c478bd9Sstevel@tonic-gate * child. It includes the situation that cron hit maxrun, and needs
25887c478bd9Sstevel@tonic-gate * to reschedule the job.
25897c478bd9Sstevel@tonic-gate */
25907c478bd9Sstevel@tonic-gate static void
reap_child()25917c478bd9Sstevel@tonic-gate reap_child()
25927c478bd9Sstevel@tonic-gate {
25937c478bd9Sstevel@tonic-gate pid_t pid;
25947c478bd9Sstevel@tonic-gate int prc;
25957c478bd9Sstevel@tonic-gate struct runinfo *rp;
25967c478bd9Sstevel@tonic-gate
25977c478bd9Sstevel@tonic-gate for (;;) {
25987c478bd9Sstevel@tonic-gate pid = waitpid((pid_t)-1, &prc, WNOHANG);
25997c478bd9Sstevel@tonic-gate if (pid <= 0)
26007c478bd9Sstevel@tonic-gate break;
26017c478bd9Sstevel@tonic-gate #ifdef DEBUG
26027c478bd9Sstevel@tonic-gate fprintf(stderr,
26037c478bd9Sstevel@tonic-gate "wait returned %x for process %d\n", prc, pid);
26047c478bd9Sstevel@tonic-gate #endif
26057c478bd9Sstevel@tonic-gate if ((rp = rinfo_get(pid)) == NULL) {
26067c478bd9Sstevel@tonic-gate if (miscpid_delete(pid) == 0) {
26077c478bd9Sstevel@tonic-gate /* not found in anywhere */
26087c478bd9Sstevel@tonic-gate msg(PIDERR, pid);
26097c478bd9Sstevel@tonic-gate }
26107c478bd9Sstevel@tonic-gate } else if (rp->que == ZOMB) {
26117c478bd9Sstevel@tonic-gate (void) unlink(rp->outfile);
26127c478bd9Sstevel@tonic-gate rinfo_free(rp);
26137c478bd9Sstevel@tonic-gate } else {
26147c478bd9Sstevel@tonic-gate cleanup(rp, prc);
26157c478bd9Sstevel@tonic-gate }
26167c478bd9Sstevel@tonic-gate }
26177c478bd9Sstevel@tonic-gate }
26187c478bd9Sstevel@tonic-gate
26197c478bd9Sstevel@tonic-gate static void
cleanup(struct runinfo * pr,int rc)26207c478bd9Sstevel@tonic-gate cleanup(struct runinfo *pr, int rc)
26217c478bd9Sstevel@tonic-gate {
26227c478bd9Sstevel@tonic-gate int nextfork = 1;
26237c478bd9Sstevel@tonic-gate struct usr *p;
26247c478bd9Sstevel@tonic-gate struct stat buf;
26257c478bd9Sstevel@tonic-gate
26267c478bd9Sstevel@tonic-gate logit(ECHAR, pr, rc);
26277c478bd9Sstevel@tonic-gate --qt[pr->que].nrun;
26287c478bd9Sstevel@tonic-gate p = pr->rusr;
26297c478bd9Sstevel@tonic-gate if (pr->que != CRONEVENT)
26307c478bd9Sstevel@tonic-gate --p->aruncnt;
26317c478bd9Sstevel@tonic-gate else
26327c478bd9Sstevel@tonic-gate --p->cruncnt;
26337c478bd9Sstevel@tonic-gate
26344bc0a2efScasper if (lstat(pr->outfile, &buf) == 0) {
26354bc0a2efScasper if (!S_ISLNK(buf.st_mode) &&
26367c478bd9Sstevel@tonic-gate (buf.st_size > 0 || pr->mailwhendone)) {
26377c478bd9Sstevel@tonic-gate /* mail user stdout and stderr */
26387c478bd9Sstevel@tonic-gate for (;;) {
26397c478bd9Sstevel@tonic-gate if ((pr->pid = fork()) < 0) {
26407c478bd9Sstevel@tonic-gate /*
26417c478bd9Sstevel@tonic-gate * if fork fails try forever in doubling
26427c478bd9Sstevel@tonic-gate * retry times, up to 16 seconds
26437c478bd9Sstevel@tonic-gate */
26447c478bd9Sstevel@tonic-gate (void) sleep(nextfork);
26457c478bd9Sstevel@tonic-gate if (nextfork < 16)
26467c478bd9Sstevel@tonic-gate nextfork += nextfork;
26477c478bd9Sstevel@tonic-gate continue;
26487c478bd9Sstevel@tonic-gate } else if (pr->pid == 0) {
26497c478bd9Sstevel@tonic-gate child_sigreset();
26507c478bd9Sstevel@tonic-gate contract_clear_template();
26517c478bd9Sstevel@tonic-gate
26527c478bd9Sstevel@tonic-gate mail_result(p, pr, buf.st_size);
26537c478bd9Sstevel@tonic-gate /* NOTREACHED */
26547c478bd9Sstevel@tonic-gate } else {
26557c478bd9Sstevel@tonic-gate contract_abandon_latest(pr->pid);
26567c478bd9Sstevel@tonic-gate pr->que = ZOMB;
26577c478bd9Sstevel@tonic-gate break;
26587c478bd9Sstevel@tonic-gate }
26597c478bd9Sstevel@tonic-gate }
26607c478bd9Sstevel@tonic-gate } else {
26617c478bd9Sstevel@tonic-gate (void) unlink(pr->outfile);
26627c478bd9Sstevel@tonic-gate rinfo_free(pr);
26637c478bd9Sstevel@tonic-gate }
26647c478bd9Sstevel@tonic-gate } else {
26657c478bd9Sstevel@tonic-gate rinfo_free(pr);
26667c478bd9Sstevel@tonic-gate }
26677c478bd9Sstevel@tonic-gate
26687c478bd9Sstevel@tonic-gate free_if_unused(p);
26697c478bd9Sstevel@tonic-gate }
26707c478bd9Sstevel@tonic-gate
26717c478bd9Sstevel@tonic-gate /*
26727c478bd9Sstevel@tonic-gate * Mail stdout and stderr of a job to user. Get uid for real user and become
26737c478bd9Sstevel@tonic-gate * that person. We do this so that mail won't come from root since this
26747c478bd9Sstevel@tonic-gate * could be a security hole. If failure, quit - don't send mail as root.
26757c478bd9Sstevel@tonic-gate */
26767c478bd9Sstevel@tonic-gate static void
mail_result(struct usr * p,struct runinfo * pr,size_t filesize)26777c478bd9Sstevel@tonic-gate mail_result(struct usr *p, struct runinfo *pr, size_t filesize)
26787c478bd9Sstevel@tonic-gate {
26797c478bd9Sstevel@tonic-gate struct passwd *ruser_ids;
26807c478bd9Sstevel@tonic-gate FILE *mailpipe;
26817c478bd9Sstevel@tonic-gate FILE *st;
26827c478bd9Sstevel@tonic-gate struct utsname name;
26837c478bd9Sstevel@tonic-gate int nbytes;
26847c478bd9Sstevel@tonic-gate char iobuf[BUFSIZ];
26857c478bd9Sstevel@tonic-gate char *cmd;
268642c141d3SJoshua M. Clulow char *lowname = (pr->jobtype == CRONEVENT ? "cron" : "at");
26877c478bd9Sstevel@tonic-gate
26887c478bd9Sstevel@tonic-gate (void) uname(&name);
26897c478bd9Sstevel@tonic-gate if ((ruser_ids = getpwnam(p->name)) == NULL)
26907c478bd9Sstevel@tonic-gate exit(0);
26917c478bd9Sstevel@tonic-gate (void) setuid(ruser_ids->pw_uid);
26927c478bd9Sstevel@tonic-gate
26937c478bd9Sstevel@tonic-gate cmd = xmalloc(strlen(MAIL) + strlen(p->name)+2);
26947c478bd9Sstevel@tonic-gate (void) sprintf(cmd, "%s %s", MAIL, p->name);
26957c478bd9Sstevel@tonic-gate mailpipe = popen(cmd, "w");
26967c478bd9Sstevel@tonic-gate free(cmd);
26977c478bd9Sstevel@tonic-gate if (mailpipe == NULL)
26987c478bd9Sstevel@tonic-gate exit(127);
26997c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "To: %s\n", p->name);
270042c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "Subject: %s <%s@%s> %s\n",
270142c141d3SJoshua M. Clulow (pr->jobtype == CRONEVENT ? "Cron" : "At"),
270242c141d3SJoshua M. Clulow p->name, name.nodename, pr->jobname);
270342c141d3SJoshua M. Clulow
270442c141d3SJoshua M. Clulow /*
270542c141d3SJoshua M. Clulow * RFC3834 (Section 5) defines the Auto-Submitted header to prevent
270642c141d3SJoshua M. Clulow * vacation replies, et al, from being sent in response to
270742c141d3SJoshua M. Clulow * machine-generated mail.
270842c141d3SJoshua M. Clulow */
270942c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "Auto-Submitted: auto-generated\n");
271042c141d3SJoshua M. Clulow
271142c141d3SJoshua M. Clulow /*
271242c141d3SJoshua M. Clulow * Additional headers for mail filtering and diagnostics:
271342c141d3SJoshua M. Clulow */
271442c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "X-Mailer: cron (%s %s)\n", name.sysname,
271542c141d3SJoshua M. Clulow name.release);
271642c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "X-Cron-User: %s\n", p->name);
271742c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "X-Cron-Host: %s\n", name.nodename);
271842c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "X-Cron-Job-Name: %s\n", pr->jobname);
271942c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "X-Cron-Job-Type: %s\n", lowname);
272042c141d3SJoshua M. Clulow
272142c141d3SJoshua M. Clulow /*
272242c141d3SJoshua M. Clulow * Message Body:
272342c141d3SJoshua M. Clulow *
272442c141d3SJoshua M. Clulow * (Temporary file is fopen'ed with "r", secure open.)
272542c141d3SJoshua M. Clulow */
272642c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "\n");
27277c478bd9Sstevel@tonic-gate if (filesize > 0 &&
27287c478bd9Sstevel@tonic-gate (st = fopen(pr->outfile, "r")) != NULL) {
27297c478bd9Sstevel@tonic-gate while ((nbytes = fread(iobuf, sizeof (char), BUFSIZ, st)) != 0)
27307c478bd9Sstevel@tonic-gate (void) fwrite(iobuf, sizeof (char), nbytes, mailpipe);
27317c478bd9Sstevel@tonic-gate (void) fclose(st);
27327c478bd9Sstevel@tonic-gate } else {
273342c141d3SJoshua M. Clulow (void) fprintf(mailpipe, "Job completed with no output.\n");
27347c478bd9Sstevel@tonic-gate }
27357c478bd9Sstevel@tonic-gate (void) pclose(mailpipe);
27367c478bd9Sstevel@tonic-gate exit(0);
27377c478bd9Sstevel@tonic-gate }
27387c478bd9Sstevel@tonic-gate
27397c478bd9Sstevel@tonic-gate static int
msg_wait(long tim)27407c478bd9Sstevel@tonic-gate msg_wait(long tim)
27417c478bd9Sstevel@tonic-gate {
27427c478bd9Sstevel@tonic-gate struct message msg;
27437c478bd9Sstevel@tonic-gate int cnt;
27447c478bd9Sstevel@tonic-gate time_t reftime;
2745d1419d5aSNobutomo Nakano fd_set fds;
2746d1419d5aSNobutomo Nakano struct timespec tout, *toutp;
27477c478bd9Sstevel@tonic-gate static int pending_msg;
27487c478bd9Sstevel@tonic-gate static time_t pending_reftime;
27497c478bd9Sstevel@tonic-gate
27507c478bd9Sstevel@tonic-gate if (pending_msg) {
27517c478bd9Sstevel@tonic-gate process_msg(&msgbuf, pending_reftime);
27527c478bd9Sstevel@tonic-gate pending_msg = 0;
27537c478bd9Sstevel@tonic-gate return (0);
27547c478bd9Sstevel@tonic-gate }
27557c478bd9Sstevel@tonic-gate
2756d1419d5aSNobutomo Nakano FD_ZERO(&fds);
2757d1419d5aSNobutomo Nakano FD_SET(msgfd, &fds);
27587c478bd9Sstevel@tonic-gate
2759d1419d5aSNobutomo Nakano toutp = NULL;
2760d1419d5aSNobutomo Nakano if (tim != INFINITY) {
27617c478bd9Sstevel@tonic-gate #ifdef CRON_MAXSLEEP
27627c478bd9Sstevel@tonic-gate /*
27637c478bd9Sstevel@tonic-gate * CRON_MAXSLEEP can be defined to have cron periodically wake
27647c478bd9Sstevel@tonic-gate * up, so that cron can detect a change of TOD and adjust the
2765d1419d5aSNobutomo Nakano * sleep time more frequently.
27667c478bd9Sstevel@tonic-gate */
27677c478bd9Sstevel@tonic-gate tim = (tim > CRON_MAXSLEEP) ? CRON_MAXSLEEP : tim;
27687c478bd9Sstevel@tonic-gate #endif
2769d1419d5aSNobutomo Nakano tout.tv_nsec = 0;
2770d1419d5aSNobutomo Nakano tout.tv_sec = tim;
2771d1419d5aSNobutomo Nakano toutp = &tout;
27727c478bd9Sstevel@tonic-gate }
27737c478bd9Sstevel@tonic-gate
2774d1419d5aSNobutomo Nakano cnt = pselect(msgfd + 1, &fds, NULL, NULL, toutp, &defmask);
2775d1419d5aSNobutomo Nakano if (cnt == -1 && errno != EINTR)
2776d1419d5aSNobutomo Nakano perror("! pselect");
2777d1419d5aSNobutomo Nakano
2778d1419d5aSNobutomo Nakano /* pselect timeout or interrupted */
27797c478bd9Sstevel@tonic-gate if (cnt <= 0)
27807c478bd9Sstevel@tonic-gate return (0);
27817c478bd9Sstevel@tonic-gate
27827c478bd9Sstevel@tonic-gate errno = 0;
27837c478bd9Sstevel@tonic-gate if ((cnt = read(msgfd, &msg, sizeof (msg))) != sizeof (msg)) {
27847c478bd9Sstevel@tonic-gate if (cnt != -1 || errno != EAGAIN)
27857c478bd9Sstevel@tonic-gate perror("! read");
27867c478bd9Sstevel@tonic-gate return (0);
27877c478bd9Sstevel@tonic-gate }
27887c478bd9Sstevel@tonic-gate reftime = time(NULL);
27897c478bd9Sstevel@tonic-gate if (next_event != NULL && reftime >= next_event->time) {
27907c478bd9Sstevel@tonic-gate /*
27917c478bd9Sstevel@tonic-gate * we need to run the job before reloading crontab.
27927c478bd9Sstevel@tonic-gate */
27937c478bd9Sstevel@tonic-gate (void) memcpy(&msgbuf, &msg, sizeof (msg));
27947c478bd9Sstevel@tonic-gate pending_msg = 1;
27957c478bd9Sstevel@tonic-gate pending_reftime = reftime;
27967c478bd9Sstevel@tonic-gate return (1);
27977c478bd9Sstevel@tonic-gate }
27987c478bd9Sstevel@tonic-gate process_msg(&msg, reftime);
27997c478bd9Sstevel@tonic-gate return (0);
28007c478bd9Sstevel@tonic-gate }
28017c478bd9Sstevel@tonic-gate
28027c478bd9Sstevel@tonic-gate /*
28037c478bd9Sstevel@tonic-gate * process the message supplied via pipe. This will be called either
28047c478bd9Sstevel@tonic-gate * immediately after cron read the message from pipe, or idle time
28057c478bd9Sstevel@tonic-gate * if the message was pending due to the job execution.
28067c478bd9Sstevel@tonic-gate */
28077c478bd9Sstevel@tonic-gate static void
process_msg(struct message * pmsg,time_t reftime)28087c478bd9Sstevel@tonic-gate process_msg(struct message *pmsg, time_t reftime)
28097c478bd9Sstevel@tonic-gate {
281019803d09SToomas Soome if (pmsg->etype == 0)
28117c478bd9Sstevel@tonic-gate return;
28127c478bd9Sstevel@tonic-gate
28137c478bd9Sstevel@tonic-gate switch (pmsg->etype) {
28147c478bd9Sstevel@tonic-gate case AT:
28157c478bd9Sstevel@tonic-gate if (pmsg->action == DELETE)
28167c478bd9Sstevel@tonic-gate del_atjob(pmsg->fname, pmsg->logname);
28177c478bd9Sstevel@tonic-gate else
28187c478bd9Sstevel@tonic-gate mod_atjob(pmsg->fname, (time_t)0);
28197c478bd9Sstevel@tonic-gate break;
28207c478bd9Sstevel@tonic-gate case CRON:
28217c478bd9Sstevel@tonic-gate if (pmsg->action == DELETE)
28227c478bd9Sstevel@tonic-gate del_ctab(pmsg->fname);
28237c478bd9Sstevel@tonic-gate else
28247c478bd9Sstevel@tonic-gate mod_ctab(pmsg->fname, reftime);
28257c478bd9Sstevel@tonic-gate break;
2826d1419d5aSNobutomo Nakano case REFRESH:
2827d1419d5aSNobutomo Nakano refresh = 1;
2828d1419d5aSNobutomo Nakano pmsg->etype = 0;
2829d1419d5aSNobutomo Nakano return;
28307c478bd9Sstevel@tonic-gate default:
28317c478bd9Sstevel@tonic-gate msg("message received - bad format");
28327c478bd9Sstevel@tonic-gate break;
28337c478bd9Sstevel@tonic-gate }
28347c478bd9Sstevel@tonic-gate if (next_event != NULL) {
2835e2553d68SSerge Dussud if (next_event->etype == CRONEVENT) {
2836e2553d68SSerge Dussud switch (el_add(next_event, next_event->time,
2837e2553d68SSerge Dussud (next_event->u)->ctid)) {
2838e2553d68SSerge Dussud case -1:
2839e2553d68SSerge Dussud ignore_msg("process_msg", "cron", next_event);
2840e2553d68SSerge Dussud break;
2841e2553d68SSerge Dussud case -2: /* event time lower than init time */
2842e2553d68SSerge Dussud reset_needed = 1;
2843e2553d68SSerge Dussud break;
2844e2553d68SSerge Dussud }
2845e2553d68SSerge Dussud } else { /* etype == ATEVENT */
2846e2553d68SSerge Dussud if (el_add(next_event, next_event->time,
2847e2553d68SSerge Dussud next_event->of.at.eventid) < 0) {
2848e2553d68SSerge Dussud ignore_msg("process_msg", "at", next_event);
2849e2553d68SSerge Dussud }
2850e2553d68SSerge Dussud }
28517c478bd9Sstevel@tonic-gate next_event = NULL;
28527c478bd9Sstevel@tonic-gate }
28537c478bd9Sstevel@tonic-gate (void) fflush(stdout);
2854d1419d5aSNobutomo Nakano pmsg->etype = 0;
28557c478bd9Sstevel@tonic-gate }
28567c478bd9Sstevel@tonic-gate
28579f163834Sbasabi /*
28589f163834Sbasabi * Allocate a new or find an existing runinfo structure
28599f163834Sbasabi */
28607c478bd9Sstevel@tonic-gate static struct runinfo *
rinfo_get(pid_t pid)28617c478bd9Sstevel@tonic-gate rinfo_get(pid_t pid)
28627c478bd9Sstevel@tonic-gate {
28637c478bd9Sstevel@tonic-gate struct runinfo *rp;
28647c478bd9Sstevel@tonic-gate
28659f163834Sbasabi if (pid == 0) { /* allocate a new entry */
28669f163834Sbasabi rp = xcalloc(1, sizeof (struct runinfo));
28679f163834Sbasabi rp->next = rthead; /* link the entry into the list */
28689f163834Sbasabi rthead = rp;
28699f163834Sbasabi return (rp);
28709f163834Sbasabi }
28719f163834Sbasabi /* search the list for an existing entry */
28729f163834Sbasabi for (rp = rthead; rp != NULL; rp = rp->next) {
28737c478bd9Sstevel@tonic-gate if (rp->pid == pid)
28747c478bd9Sstevel@tonic-gate break;
28757c478bd9Sstevel@tonic-gate }
28767c478bd9Sstevel@tonic-gate return (rp);
28777c478bd9Sstevel@tonic-gate }
28787c478bd9Sstevel@tonic-gate
28797c478bd9Sstevel@tonic-gate /*
28809f163834Sbasabi * Free a runinfo structure and its associated memory
28817c478bd9Sstevel@tonic-gate */
28827c478bd9Sstevel@tonic-gate static void
rinfo_free(struct runinfo * entry)28839f163834Sbasabi rinfo_free(struct runinfo *entry)
28847c478bd9Sstevel@tonic-gate {
28859f163834Sbasabi struct runinfo **rpp;
28869f163834Sbasabi struct runinfo *rp;
28879f163834Sbasabi
28889f163834Sbasabi #ifdef DEBUG
28899f163834Sbasabi (void) fprintf(stderr, "freeing job %s\n", entry->jobname);
28909f163834Sbasabi #endif
28919f163834Sbasabi for (rpp = &rthead; (rp = *rpp) != NULL; rpp = &rp->next) {
28929f163834Sbasabi if (rp == entry) {
28939f163834Sbasabi *rpp = rp->next; /* unlink the entry */
28947c478bd9Sstevel@tonic-gate free(rp->outfile);
28957c478bd9Sstevel@tonic-gate free(rp->jobname);
28969f163834Sbasabi free(rp);
28979f163834Sbasabi break;
28989f163834Sbasabi }
28999f163834Sbasabi }
29007c478bd9Sstevel@tonic-gate }
29017c478bd9Sstevel@tonic-gate
29027c478bd9Sstevel@tonic-gate static void
thaw_handler(int sig __unused)29036b734416SAndy Fiddaman thaw_handler(int sig __unused)
29047c478bd9Sstevel@tonic-gate {
2905d1419d5aSNobutomo Nakano refresh = 1;
29067c478bd9Sstevel@tonic-gate }
29077c478bd9Sstevel@tonic-gate
29087c478bd9Sstevel@tonic-gate
29097c478bd9Sstevel@tonic-gate static void
cronend(int sig __unused)29106b734416SAndy Fiddaman cronend(int sig __unused)
29117c478bd9Sstevel@tonic-gate {
29127c478bd9Sstevel@tonic-gate crabort("SIGTERM", REMOVE_FIFO);
29137c478bd9Sstevel@tonic-gate }
29147c478bd9Sstevel@tonic-gate
29157c478bd9Sstevel@tonic-gate static void
child_handler(int sig __unused)29166b734416SAndy Fiddaman child_handler(int sig __unused)
29177c478bd9Sstevel@tonic-gate {
2918d1419d5aSNobutomo Nakano ;
29197c478bd9Sstevel@tonic-gate }
29207c478bd9Sstevel@tonic-gate
29217c478bd9Sstevel@tonic-gate static void
child_sigreset(void)29227c478bd9Sstevel@tonic-gate child_sigreset(void)
29237c478bd9Sstevel@tonic-gate {
29247c478bd9Sstevel@tonic-gate (void) signal(SIGCLD, SIG_DFL);
29257c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &defmask, NULL);
29267c478bd9Sstevel@tonic-gate }
29277c478bd9Sstevel@tonic-gate
29287c478bd9Sstevel@tonic-gate /*
29297c478bd9Sstevel@tonic-gate * crabort() - handle exits out of cron
29307c478bd9Sstevel@tonic-gate */
29317c478bd9Sstevel@tonic-gate static void
crabort(char * mssg,int action)29327c478bd9Sstevel@tonic-gate crabort(char *mssg, int action)
29337c478bd9Sstevel@tonic-gate {
29347c478bd9Sstevel@tonic-gate int c;
29357c478bd9Sstevel@tonic-gate
29367c478bd9Sstevel@tonic-gate if (action & REMOVE_FIFO) {
29377c478bd9Sstevel@tonic-gate /* FIFO vanishes when cron finishes */
29387c478bd9Sstevel@tonic-gate if (unlink(FIFO) < 0)
29397c478bd9Sstevel@tonic-gate perror("cron could not unlink FIFO");
29407c478bd9Sstevel@tonic-gate }
29417c478bd9Sstevel@tonic-gate
29427c478bd9Sstevel@tonic-gate if (action & CONSOLE_MSG) {
29437c478bd9Sstevel@tonic-gate /* write error msg to console */
29447c478bd9Sstevel@tonic-gate if ((c = open(CONSOLE, O_WRONLY)) >= 0) {
29457c478bd9Sstevel@tonic-gate (void) write(c, "cron aborted: ", 14);
29467c478bd9Sstevel@tonic-gate (void) write(c, mssg, strlen(mssg));
29477c478bd9Sstevel@tonic-gate (void) write(c, "\n", 1);
29487c478bd9Sstevel@tonic-gate (void) close(c);
29497c478bd9Sstevel@tonic-gate }
29507c478bd9Sstevel@tonic-gate }
29517c478bd9Sstevel@tonic-gate
29527c478bd9Sstevel@tonic-gate /* always log the message */
29537c478bd9Sstevel@tonic-gate msg(mssg);
29547c478bd9Sstevel@tonic-gate msg("******* CRON ABORTED ********");
29557c478bd9Sstevel@tonic-gate exit(1);
29567c478bd9Sstevel@tonic-gate }
29577c478bd9Sstevel@tonic-gate
29587c478bd9Sstevel@tonic-gate /*
29597c478bd9Sstevel@tonic-gate * msg() - time-stamped error reporting function
29607c478bd9Sstevel@tonic-gate */
29617c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
29627c478bd9Sstevel@tonic-gate static void
msg(char * fmt,...)29637c478bd9Sstevel@tonic-gate msg(char *fmt, ...)
29647c478bd9Sstevel@tonic-gate {
29657c478bd9Sstevel@tonic-gate va_list args;
29667c478bd9Sstevel@tonic-gate time_t t;
29677c478bd9Sstevel@tonic-gate
29687c478bd9Sstevel@tonic-gate t = time(NULL);
29697c478bd9Sstevel@tonic-gate
29707c478bd9Sstevel@tonic-gate (void) fflush(stdout);
29717c478bd9Sstevel@tonic-gate
29727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "! ");
29737c478bd9Sstevel@tonic-gate
29747c478bd9Sstevel@tonic-gate va_start(args, fmt);
29757c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, args);
29767c478bd9Sstevel@tonic-gate va_end(args);
29777c478bd9Sstevel@tonic-gate
29787c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), FORMAT, localtime(&t));
29797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " %s\n", timebuf);
29807c478bd9Sstevel@tonic-gate
29817c478bd9Sstevel@tonic-gate (void) fflush(stderr);
29827c478bd9Sstevel@tonic-gate }
29837c478bd9Sstevel@tonic-gate
29847c478bd9Sstevel@tonic-gate static void
ignore_msg(char * func_name,char * job_type,struct event * event)2985e2553d68SSerge Dussud ignore_msg(char *func_name, char *job_type, struct event *event)
2986e2553d68SSerge Dussud {
2987e2553d68SSerge Dussud msg("%s: ignoring %s job (user: %s, cmd: %s, time: %ld)",
2988e2553d68SSerge Dussud func_name, job_type,
2989e2553d68SSerge Dussud event->u->name ? event->u->name : "unknown",
2990e2553d68SSerge Dussud event->cmd ? event->cmd : "unknown",
2991e2553d68SSerge Dussud event->time);
2992e2553d68SSerge Dussud }
2993e2553d68SSerge Dussud
2994e2553d68SSerge Dussud static void
logit(int cc,struct runinfo * rp,int rc)29957c478bd9Sstevel@tonic-gate logit(int cc, struct runinfo *rp, int rc)
29967c478bd9Sstevel@tonic-gate {
29977c478bd9Sstevel@tonic-gate time_t t;
29987c478bd9Sstevel@tonic-gate int ret;
29997c478bd9Sstevel@tonic-gate
30007c478bd9Sstevel@tonic-gate if (!log)
30017c478bd9Sstevel@tonic-gate return;
30027c478bd9Sstevel@tonic-gate
30037c478bd9Sstevel@tonic-gate t = time(NULL);
30047c478bd9Sstevel@tonic-gate if (cc == BCHAR)
30057c478bd9Sstevel@tonic-gate (void) printf("%c CMD: %s\n", cc, next_event->cmd);
30067c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), FORMAT, localtime(&t));
3007951bafeaSRichard Lowe (void) printf("%c %s %u %c %s",
30087c478bd9Sstevel@tonic-gate cc, (rp->rusr)->name, rp->pid, QUE(rp->que), timebuf);
30097c478bd9Sstevel@tonic-gate if ((ret = TSTAT(rc)) != 0)
30107c478bd9Sstevel@tonic-gate (void) printf(" ts=%d", ret);
30117c478bd9Sstevel@tonic-gate if ((ret = RCODE(rc)) != 0)
30127c478bd9Sstevel@tonic-gate (void) printf(" rc=%d", ret);
30137c478bd9Sstevel@tonic-gate (void) putchar('\n');
30147c478bd9Sstevel@tonic-gate (void) fflush(stdout);
30157c478bd9Sstevel@tonic-gate }
30167c478bd9Sstevel@tonic-gate
30177c478bd9Sstevel@tonic-gate static void
resched(int delay)30187c478bd9Sstevel@tonic-gate resched(int delay)
30197c478bd9Sstevel@tonic-gate {
30207c478bd9Sstevel@tonic-gate time_t nt;
30217c478bd9Sstevel@tonic-gate
30227c478bd9Sstevel@tonic-gate /* run job at a later time */
30237c478bd9Sstevel@tonic-gate nt = next_event->time + delay;
30247c478bd9Sstevel@tonic-gate if (next_event->etype == CRONEVENT) {
30257c478bd9Sstevel@tonic-gate next_event->time = next_time(next_event, (time_t)0);
30267c478bd9Sstevel@tonic-gate if (nt < next_event->time)
30277c478bd9Sstevel@tonic-gate next_event->time = nt;
3028e2553d68SSerge Dussud switch (el_add(next_event, next_event->time,
3029e2553d68SSerge Dussud (next_event->u)->ctid)) {
3030e2553d68SSerge Dussud case -1:
3031e2553d68SSerge Dussud ignore_msg("resched", "cron", next_event);
3032e2553d68SSerge Dussud break;
3033e2553d68SSerge Dussud case -2: /* event time lower than init time */
3034e2553d68SSerge Dussud reset_needed = 1;
3035e2553d68SSerge Dussud break;
3036e2553d68SSerge Dussud }
30377c478bd9Sstevel@tonic-gate delayed = 1;
30387c478bd9Sstevel@tonic-gate msg("rescheduling a cron job");
30397c478bd9Sstevel@tonic-gate return;
30407c478bd9Sstevel@tonic-gate }
30417c478bd9Sstevel@tonic-gate add_atevent(next_event->u, next_event->cmd, nt, next_event->etype);
30427c478bd9Sstevel@tonic-gate msg("rescheduling at job");
30437c478bd9Sstevel@tonic-gate }
30447c478bd9Sstevel@tonic-gate
30457c478bd9Sstevel@tonic-gate static void
quedefs(int action)30467c478bd9Sstevel@tonic-gate quedefs(int action)
30477c478bd9Sstevel@tonic-gate {
30487c478bd9Sstevel@tonic-gate int i;
30497c478bd9Sstevel@tonic-gate int j;
30507c478bd9Sstevel@tonic-gate char qbuf[QBUFSIZ];
30517c478bd9Sstevel@tonic-gate FILE *fd;
30527c478bd9Sstevel@tonic-gate
30537c478bd9Sstevel@tonic-gate /* set up default queue definitions */
30547c478bd9Sstevel@tonic-gate for (i = 0; i < NQUEUE; i++) {
30557c478bd9Sstevel@tonic-gate qt[i].njob = qd.njob;
30567c478bd9Sstevel@tonic-gate qt[i].nice = qd.nice;
30577c478bd9Sstevel@tonic-gate qt[i].nwait = qd.nwait;
30587c478bd9Sstevel@tonic-gate }
30597c478bd9Sstevel@tonic-gate if (action == DEFAULT)
30607c478bd9Sstevel@tonic-gate return;
30617c478bd9Sstevel@tonic-gate if ((fd = fopen(QUEDEFS, "r")) == NULL) {
30627c478bd9Sstevel@tonic-gate msg("cannot open quedefs file");
30637c478bd9Sstevel@tonic-gate msg("using default queue definitions");
30647c478bd9Sstevel@tonic-gate return;
30657c478bd9Sstevel@tonic-gate }
30667c478bd9Sstevel@tonic-gate while (fgets(qbuf, QBUFSIZ, fd) != NULL) {
30677c478bd9Sstevel@tonic-gate if ((j = qbuf[0]-'a') < 0 || j >= NQUEUE || qbuf[1] != '.')
30687c478bd9Sstevel@tonic-gate continue;
30697c478bd9Sstevel@tonic-gate parsqdef(&qbuf[2]);
30707c478bd9Sstevel@tonic-gate qt[j].njob = qq.njob;
30717c478bd9Sstevel@tonic-gate qt[j].nice = qq.nice;
30727c478bd9Sstevel@tonic-gate qt[j].nwait = qq.nwait;
30737c478bd9Sstevel@tonic-gate }
30747c478bd9Sstevel@tonic-gate (void) fclose(fd);
30757c478bd9Sstevel@tonic-gate }
30767c478bd9Sstevel@tonic-gate
30777c478bd9Sstevel@tonic-gate static void
parsqdef(char * name)30787c478bd9Sstevel@tonic-gate parsqdef(char *name)
30797c478bd9Sstevel@tonic-gate {
30807c478bd9Sstevel@tonic-gate int i;
30817c478bd9Sstevel@tonic-gate
30827c478bd9Sstevel@tonic-gate qq = qd;
30837c478bd9Sstevel@tonic-gate while (*name) {
30847c478bd9Sstevel@tonic-gate i = 0;
30857c478bd9Sstevel@tonic-gate while (isdigit(*name)) {
30867c478bd9Sstevel@tonic-gate i *= 10;
30877c478bd9Sstevel@tonic-gate i += *name++ - '0';
30887c478bd9Sstevel@tonic-gate }
30897c478bd9Sstevel@tonic-gate switch (*name++) {
30907c478bd9Sstevel@tonic-gate case JOBF:
30917c478bd9Sstevel@tonic-gate qq.njob = i;
30927c478bd9Sstevel@tonic-gate break;
30937c478bd9Sstevel@tonic-gate case NICEF:
30947c478bd9Sstevel@tonic-gate qq.nice = i;
30957c478bd9Sstevel@tonic-gate break;
30967c478bd9Sstevel@tonic-gate case WAITF:
30977c478bd9Sstevel@tonic-gate qq.nwait = i;
30987c478bd9Sstevel@tonic-gate break;
30997c478bd9Sstevel@tonic-gate }
31007c478bd9Sstevel@tonic-gate }
31017c478bd9Sstevel@tonic-gate }
31027c478bd9Sstevel@tonic-gate
31037c478bd9Sstevel@tonic-gate /*
31047c478bd9Sstevel@tonic-gate * defaults - read defaults from /etc/default/cron
31057c478bd9Sstevel@tonic-gate */
31067c478bd9Sstevel@tonic-gate static void
defaults()31077c478bd9Sstevel@tonic-gate defaults()
31087c478bd9Sstevel@tonic-gate {
31097c478bd9Sstevel@tonic-gate int flags;
31107c478bd9Sstevel@tonic-gate char *deflog;
31117c478bd9Sstevel@tonic-gate char *hz, *tz;
31127c478bd9Sstevel@tonic-gate
31137c478bd9Sstevel@tonic-gate /*
31147c478bd9Sstevel@tonic-gate * get HZ value for environment
31157c478bd9Sstevel@tonic-gate */
31167c478bd9Sstevel@tonic-gate if ((hz = getenv("HZ")) == (char *)NULL)
31177c478bd9Sstevel@tonic-gate (void) sprintf(hzname, "HZ=%d", HZ);
31187c478bd9Sstevel@tonic-gate else
31197c478bd9Sstevel@tonic-gate (void) snprintf(hzname, sizeof (hzname), "HZ=%s", hz);
31207c478bd9Sstevel@tonic-gate /*
31217c478bd9Sstevel@tonic-gate * get TZ value for environment
31227c478bd9Sstevel@tonic-gate */
31237c478bd9Sstevel@tonic-gate (void) snprintf(tzone, sizeof (tzone), "TZ=%s",
31247c478bd9Sstevel@tonic-gate ((tz = getenv("TZ")) != NULL) ? tz : DEFTZ);
31257c478bd9Sstevel@tonic-gate
31267c478bd9Sstevel@tonic-gate if (defopen(DEFFILE) == 0) {
31277c478bd9Sstevel@tonic-gate /* ignore case */
31287c478bd9Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0);
31297c478bd9Sstevel@tonic-gate TURNOFF(flags, DC_CASE);
31307c478bd9Sstevel@tonic-gate (void) defcntl(DC_SETFLAGS, flags);
31317c478bd9Sstevel@tonic-gate
31327c478bd9Sstevel@tonic-gate if (((deflog = defread("CRONLOG=")) == NULL) ||
31337c478bd9Sstevel@tonic-gate (*deflog == 'N') || (*deflog == 'n'))
31347c478bd9Sstevel@tonic-gate log = 0;
31357c478bd9Sstevel@tonic-gate else
31367c478bd9Sstevel@tonic-gate log = 1;
31377c478bd9Sstevel@tonic-gate /* fix for 1087611 - allow paths to be set in defaults file */
31387c478bd9Sstevel@tonic-gate if ((Def_path = defread("PATH=")) != NULL) {
31397c478bd9Sstevel@tonic-gate (void) strlcat(path, Def_path, LINE_MAX);
31407c478bd9Sstevel@tonic-gate } else {
31417c478bd9Sstevel@tonic-gate (void) strlcpy(path, NONROOTPATH, LINE_MAX);
31427c478bd9Sstevel@tonic-gate }
31437c478bd9Sstevel@tonic-gate if ((Def_supath = defread("SUPATH=")) != NULL) {
31447c478bd9Sstevel@tonic-gate (void) strlcat(supath, Def_supath, LINE_MAX);
31457c478bd9Sstevel@tonic-gate } else {
31467c478bd9Sstevel@tonic-gate (void) strlcpy(supath, ROOTPATH, LINE_MAX);
31477c478bd9Sstevel@tonic-gate }
31487c478bd9Sstevel@tonic-gate (void) defopen(NULL);
31497c478bd9Sstevel@tonic-gate }
31507c478bd9Sstevel@tonic-gate }
31517c478bd9Sstevel@tonic-gate
31527c478bd9Sstevel@tonic-gate /*
31537c478bd9Sstevel@tonic-gate * Determine if a user entry for a job is still ok. The method used here
31547c478bd9Sstevel@tonic-gate * is a lot (about 75x) faster than using setgrent() / getgrent()
31557c478bd9Sstevel@tonic-gate * endgrent(). It should be safe because we use the sysconf to determine
31567c478bd9Sstevel@tonic-gate * the max, and it tolerates the max being 0.
31577c478bd9Sstevel@tonic-gate */
31587c478bd9Sstevel@tonic-gate
31597c478bd9Sstevel@tonic-gate static int
verify_user_cred(struct usr * u)31604c4c9110Sbasabi verify_user_cred(struct usr *u)
31617c478bd9Sstevel@tonic-gate {
31627c478bd9Sstevel@tonic-gate struct passwd *pw;
31637c478bd9Sstevel@tonic-gate size_t numUsrGrps = 0;
31647c478bd9Sstevel@tonic-gate size_t numOrigGrps = 0;
31657c478bd9Sstevel@tonic-gate size_t i;
31667c478bd9Sstevel@tonic-gate int retval;
31677c478bd9Sstevel@tonic-gate
31687c478bd9Sstevel@tonic-gate /*
31697c478bd9Sstevel@tonic-gate * Maximum number of groups a user may be in concurrently. This
31707c478bd9Sstevel@tonic-gate * is a value which we obtain at runtime through a sysconf()
31717c478bd9Sstevel@tonic-gate * call.
31727c478bd9Sstevel@tonic-gate */
31737c478bd9Sstevel@tonic-gate
31747c478bd9Sstevel@tonic-gate static size_t nGroupsMax = (size_t)-1;
31757c478bd9Sstevel@tonic-gate
31767c478bd9Sstevel@tonic-gate /*
31777c478bd9Sstevel@tonic-gate * Arrays for cron user's group list, constructed at startup to
31787c478bd9Sstevel@tonic-gate * be nGroupsMax elements long, used for verifying user
31797c478bd9Sstevel@tonic-gate * credentials prior to execution.
31807c478bd9Sstevel@tonic-gate */
31817c478bd9Sstevel@tonic-gate
31827c478bd9Sstevel@tonic-gate static gid_t *UsrGrps;
31837c478bd9Sstevel@tonic-gate static gid_t *OrigGrps;
31847c478bd9Sstevel@tonic-gate
31854c4c9110Sbasabi if ((pw = getpwnam(u->name)) == NULL)
31867c478bd9Sstevel@tonic-gate return (VUC_BADUSER);
31874c4c9110Sbasabi if (u->home != NULL) {
31884c4c9110Sbasabi if (strcmp(u->home, pw->pw_dir) != 0) {
31894c4c9110Sbasabi free(u->home);
31904c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1);
31914c4c9110Sbasabi (void) strcpy(u->home, pw->pw_dir);
31927c478bd9Sstevel@tonic-gate }
31934c4c9110Sbasabi } else {
31944c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1);
31954c4c9110Sbasabi (void) strcpy(u->home, pw->pw_dir);
31964c4c9110Sbasabi }
31974c4c9110Sbasabi if (u->uid != pw->pw_uid)
31984c4c9110Sbasabi u->uid = pw->pw_uid;
31994c4c9110Sbasabi if (u->gid != pw->pw_gid)
32004c4c9110Sbasabi u->gid = pw->pw_gid;
32017c478bd9Sstevel@tonic-gate
32027c478bd9Sstevel@tonic-gate /*
32037c478bd9Sstevel@tonic-gate * Create the group id lists needed for job credential
32047c478bd9Sstevel@tonic-gate * verification.
32057c478bd9Sstevel@tonic-gate */
32067c478bd9Sstevel@tonic-gate
32077c478bd9Sstevel@tonic-gate if (nGroupsMax == (size_t)-1) {
32087c478bd9Sstevel@tonic-gate if ((nGroupsMax = sysconf(_SC_NGROUPS_MAX)) > 0) {
32097c478bd9Sstevel@tonic-gate UsrGrps = xcalloc(nGroupsMax, sizeof (gid_t));
32107c478bd9Sstevel@tonic-gate OrigGrps = xcalloc(nGroupsMax, sizeof (gid_t));
32117c478bd9Sstevel@tonic-gate }
32127c478bd9Sstevel@tonic-gate
32137c478bd9Sstevel@tonic-gate #ifdef DEBUG
32147c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "nGroupsMax = %ld\n", nGroupsMax);
32157c478bd9Sstevel@tonic-gate #endif
32167c478bd9Sstevel@tonic-gate }
32177c478bd9Sstevel@tonic-gate
32187c478bd9Sstevel@tonic-gate #ifdef DEBUG
32197c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred (%s-%d)\n", pw->pw_name,
32207c478bd9Sstevel@tonic-gate pw->pw_uid);
32217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred: pw->pw_gid = %d, "
32227c478bd9Sstevel@tonic-gate "u->gid = %d\n", pw->pw_gid, u->gid);
32237c478bd9Sstevel@tonic-gate #endif
32247c478bd9Sstevel@tonic-gate
32257c478bd9Sstevel@tonic-gate retval = (u->gid == pw->pw_gid) ? VUC_OK : VUC_NOTINGROUP;
32267c478bd9Sstevel@tonic-gate
32277c478bd9Sstevel@tonic-gate if (nGroupsMax > 0) {
32287c478bd9Sstevel@tonic-gate numOrigGrps = getgroups(nGroupsMax, OrigGrps);
32297c478bd9Sstevel@tonic-gate
32307c478bd9Sstevel@tonic-gate (void) initgroups(pw->pw_name, pw->pw_gid);
32317c478bd9Sstevel@tonic-gate numUsrGrps = getgroups(nGroupsMax, UsrGrps);
32327c478bd9Sstevel@tonic-gate
32337c478bd9Sstevel@tonic-gate for (i = 0; i < numUsrGrps; i++) {
32347c478bd9Sstevel@tonic-gate if (UsrGrps[i] == u->gid) {
32357c478bd9Sstevel@tonic-gate retval = VUC_OK;
32367c478bd9Sstevel@tonic-gate break;
32377c478bd9Sstevel@tonic-gate }
32387c478bd9Sstevel@tonic-gate }
32397c478bd9Sstevel@tonic-gate
32407c478bd9Sstevel@tonic-gate if (OrigGrps) {
32417c478bd9Sstevel@tonic-gate (void) setgroups(numOrigGrps, OrigGrps);
32427c478bd9Sstevel@tonic-gate }
32437c478bd9Sstevel@tonic-gate }
32447c478bd9Sstevel@tonic-gate
32457c478bd9Sstevel@tonic-gate #ifdef DEBUG
32467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred: VUC = %d\n", retval);
32477c478bd9Sstevel@tonic-gate #endif
32487c478bd9Sstevel@tonic-gate
32497c478bd9Sstevel@tonic-gate return (retval);
32507c478bd9Sstevel@tonic-gate }
32517c478bd9Sstevel@tonic-gate
32527c478bd9Sstevel@tonic-gate static int
set_user_cred(const struct usr * u,struct project * pproj)32537c478bd9Sstevel@tonic-gate set_user_cred(const struct usr *u, struct project *pproj)
32547c478bd9Sstevel@tonic-gate {
32557c478bd9Sstevel@tonic-gate static char *progname = "cron";
32567c478bd9Sstevel@tonic-gate int r = 0, rval = 0;
32577c478bd9Sstevel@tonic-gate
32587c478bd9Sstevel@tonic-gate if ((r = pam_start(progname, u->name, &pam_conv, &pamh))
32597c478bd9Sstevel@tonic-gate != PAM_SUCCESS) {
32607c478bd9Sstevel@tonic-gate #ifdef DEBUG
32617c478bd9Sstevel@tonic-gate msg("pam_start returns %d\n", r);
32627c478bd9Sstevel@tonic-gate #endif
32637c478bd9Sstevel@tonic-gate rval = VUC_BADUSER;
32647c478bd9Sstevel@tonic-gate goto set_eser_cred_exit;
32657c478bd9Sstevel@tonic-gate }
32667c478bd9Sstevel@tonic-gate
32677c478bd9Sstevel@tonic-gate r = pam_acct_mgmt(pamh, 0);
32687c478bd9Sstevel@tonic-gate #ifdef DEBUG
32697c478bd9Sstevel@tonic-gate msg("pam_acc_mgmt returns %d\n", r);
32707c478bd9Sstevel@tonic-gate #endif
32717c478bd9Sstevel@tonic-gate if (r == PAM_ACCT_EXPIRED) {
32727c478bd9Sstevel@tonic-gate rval = VUC_EXPIRED;
32737c478bd9Sstevel@tonic-gate goto set_eser_cred_exit;
32747c478bd9Sstevel@tonic-gate }
32757c478bd9Sstevel@tonic-gate if (r == PAM_NEW_AUTHTOK_REQD) {
32767c478bd9Sstevel@tonic-gate rval = VUC_NEW_AUTH;
32777c478bd9Sstevel@tonic-gate goto set_eser_cred_exit;
32787c478bd9Sstevel@tonic-gate }
32797c478bd9Sstevel@tonic-gate if (r != PAM_SUCCESS) {
32807c478bd9Sstevel@tonic-gate rval = VUC_BADUSER;
32817c478bd9Sstevel@tonic-gate goto set_eser_cred_exit;
32827c478bd9Sstevel@tonic-gate }
32837c478bd9Sstevel@tonic-gate
32847c478bd9Sstevel@tonic-gate if (pproj != NULL) {
32857c478bd9Sstevel@tonic-gate size_t sz = sizeof (PROJECT) + strlen(pproj->pj_name);
32867c478bd9Sstevel@tonic-gate char *buf = alloca(sz);
32877c478bd9Sstevel@tonic-gate
32887c478bd9Sstevel@tonic-gate (void) snprintf(buf, sz, PROJECT "%s", pproj->pj_name);
32897c478bd9Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_RESOURCE, buf);
32907c478bd9Sstevel@tonic-gate }
32917c478bd9Sstevel@tonic-gate
32927c478bd9Sstevel@tonic-gate r = pam_setcred(pamh, PAM_ESTABLISH_CRED);
32937c478bd9Sstevel@tonic-gate if (r != PAM_SUCCESS)
32947c478bd9Sstevel@tonic-gate rval = VUC_BADUSER;
32957c478bd9Sstevel@tonic-gate
32967c478bd9Sstevel@tonic-gate set_eser_cred_exit:
32977c478bd9Sstevel@tonic-gate (void) pam_end(pamh, r);
32987c478bd9Sstevel@tonic-gate return (rval);
32997c478bd9Sstevel@tonic-gate }
33007c478bd9Sstevel@tonic-gate
33017c478bd9Sstevel@tonic-gate static void
clean_out_user(struct usr * u)33027c478bd9Sstevel@tonic-gate clean_out_user(struct usr *u)
33037c478bd9Sstevel@tonic-gate {
33047c478bd9Sstevel@tonic-gate if (next_event->u == u) {
33057c478bd9Sstevel@tonic-gate next_event = NULL;
33067c478bd9Sstevel@tonic-gate }
33077c478bd9Sstevel@tonic-gate
33087c478bd9Sstevel@tonic-gate clean_out_ctab(u);
33097c478bd9Sstevel@tonic-gate clean_out_atjobs(u);
33107c478bd9Sstevel@tonic-gate free_if_unused(u);
33117c478bd9Sstevel@tonic-gate }
33127c478bd9Sstevel@tonic-gate
33137c478bd9Sstevel@tonic-gate static void
clean_out_atjobs(struct usr * u)33147c478bd9Sstevel@tonic-gate clean_out_atjobs(struct usr *u)
33157c478bd9Sstevel@tonic-gate {
33167c478bd9Sstevel@tonic-gate struct event *ev, *pv;
33177c478bd9Sstevel@tonic-gate
33187c478bd9Sstevel@tonic-gate for (pv = NULL, ev = u->atevents;
33197c478bd9Sstevel@tonic-gate ev != NULL;
33207c478bd9Sstevel@tonic-gate pv = ev, ev = ev->link, free(pv)) {
33217c478bd9Sstevel@tonic-gate el_remove(ev->of.at.eventid, 1);
33227c478bd9Sstevel@tonic-gate if (cwd == AT)
33237c478bd9Sstevel@tonic-gate cron_unlink(ev->cmd);
33247c478bd9Sstevel@tonic-gate else {
33257c478bd9Sstevel@tonic-gate char buf[PATH_MAX];
33267c478bd9Sstevel@tonic-gate if (strlen(ATDIR) + strlen(ev->cmd) + 2
33277c478bd9Sstevel@tonic-gate < PATH_MAX) {
33287c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%s/%s", ATDIR, ev->cmd);
33297c478bd9Sstevel@tonic-gate cron_unlink(buf);
33307c478bd9Sstevel@tonic-gate }
33317c478bd9Sstevel@tonic-gate }
33327c478bd9Sstevel@tonic-gate free(ev->cmd);
33337c478bd9Sstevel@tonic-gate }
33347c478bd9Sstevel@tonic-gate
33357c478bd9Sstevel@tonic-gate u->atevents = NULL;
33367c478bd9Sstevel@tonic-gate }
33377c478bd9Sstevel@tonic-gate
33387c478bd9Sstevel@tonic-gate static void
clean_out_ctab(struct usr * u)33397c478bd9Sstevel@tonic-gate clean_out_ctab(struct usr *u)
33407c478bd9Sstevel@tonic-gate {
33417c478bd9Sstevel@tonic-gate rm_ctevents(u);
33427c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0);
33437c478bd9Sstevel@tonic-gate u->ctid = 0;
33447c478bd9Sstevel@tonic-gate u->ctexists = 0;
33457c478bd9Sstevel@tonic-gate }
33467c478bd9Sstevel@tonic-gate
33477c478bd9Sstevel@tonic-gate static void
cron_unlink(char * name)33487c478bd9Sstevel@tonic-gate cron_unlink(char *name)
33497c478bd9Sstevel@tonic-gate {
33507c478bd9Sstevel@tonic-gate int r;
33517c478bd9Sstevel@tonic-gate
33527c478bd9Sstevel@tonic-gate r = unlink(name);
33537c478bd9Sstevel@tonic-gate if (r == 0 || (r == -1 && errno == ENOENT)) {
33547c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(name, NULL);
33557c478bd9Sstevel@tonic-gate }
33567c478bd9Sstevel@tonic-gate }
33577c478bd9Sstevel@tonic-gate
33587c478bd9Sstevel@tonic-gate static void
create_anc_ctab(struct event * e)33597c478bd9Sstevel@tonic-gate create_anc_ctab(struct event *e)
33607c478bd9Sstevel@tonic-gate {
33617c478bd9Sstevel@tonic-gate if (audit_cron_create_anc_file(e->u->name,
33627c478bd9Sstevel@tonic-gate (cwd == CRON) ? NULL:CRONDIR,
33634c4c9110Sbasabi e->u->name, e->u->uid) == -1) {
33647c478bd9Sstevel@tonic-gate process_anc_files(CRON_ANC_DELETE);
33657c478bd9Sstevel@tonic-gate crabort("cannot create ancillary files for crontabs",
33667c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG);
33677c478bd9Sstevel@tonic-gate }
33687c478bd9Sstevel@tonic-gate }
33697c478bd9Sstevel@tonic-gate
33707c478bd9Sstevel@tonic-gate static void
delete_anc_ctab(struct event * e)33717c478bd9Sstevel@tonic-gate delete_anc_ctab(struct event *e)
33727c478bd9Sstevel@tonic-gate {
33737c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(e->u->name,
33747c478bd9Sstevel@tonic-gate (cwd == CRON) ? NULL:CRONDIR);
33757c478bd9Sstevel@tonic-gate }
33767c478bd9Sstevel@tonic-gate
33777c478bd9Sstevel@tonic-gate static void
create_anc_atjob(struct event * e)33787c478bd9Sstevel@tonic-gate create_anc_atjob(struct event *e)
33797c478bd9Sstevel@tonic-gate {
33807c478bd9Sstevel@tonic-gate if (!e->of.at.exists)
33817c478bd9Sstevel@tonic-gate return;
33827c478bd9Sstevel@tonic-gate
33837c478bd9Sstevel@tonic-gate if (audit_cron_create_anc_file(e->cmd,
33847c478bd9Sstevel@tonic-gate (cwd == AT) ? NULL:ATDIR,
33854c4c9110Sbasabi e->u->name, e->u->uid) == -1) {
33867c478bd9Sstevel@tonic-gate process_anc_files(CRON_ANC_DELETE);
33877c478bd9Sstevel@tonic-gate crabort("cannot create ancillary files for atjobs",
33887c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG);
33897c478bd9Sstevel@tonic-gate }
33907c478bd9Sstevel@tonic-gate }
33917c478bd9Sstevel@tonic-gate
33927c478bd9Sstevel@tonic-gate static void
delete_anc_atjob(struct event * e)33937c478bd9Sstevel@tonic-gate delete_anc_atjob(struct event *e)
33947c478bd9Sstevel@tonic-gate {
33957c478bd9Sstevel@tonic-gate if (!e->of.at.exists)
33967c478bd9Sstevel@tonic-gate return;
33977c478bd9Sstevel@tonic-gate
33987c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(e->cmd,
33997c478bd9Sstevel@tonic-gate (cwd == AT) ? NULL:ATDIR);
34007c478bd9Sstevel@tonic-gate }
34017c478bd9Sstevel@tonic-gate
34027c478bd9Sstevel@tonic-gate
34037c478bd9Sstevel@tonic-gate static void
process_anc_files(int del)34047c478bd9Sstevel@tonic-gate process_anc_files(int del)
34057c478bd9Sstevel@tonic-gate {
34067c478bd9Sstevel@tonic-gate struct usr *u = uhead;
34077c478bd9Sstevel@tonic-gate struct event *e;
34087c478bd9Sstevel@tonic-gate
34097c478bd9Sstevel@tonic-gate if (!audit_cron_mode())
34107c478bd9Sstevel@tonic-gate return;
34117c478bd9Sstevel@tonic-gate
34127c478bd9Sstevel@tonic-gate for (;;) {
34137c478bd9Sstevel@tonic-gate if (u->ctexists && u->ctevents != NULL) {
34147c478bd9Sstevel@tonic-gate e = u->ctevents;
34157c478bd9Sstevel@tonic-gate for (;;) {
34167c478bd9Sstevel@tonic-gate if (del)
34177c478bd9Sstevel@tonic-gate delete_anc_ctab(e);
34187c478bd9Sstevel@tonic-gate else
34197c478bd9Sstevel@tonic-gate create_anc_ctab(e);
34207c478bd9Sstevel@tonic-gate if ((e = e->link) == NULL)
34217c478bd9Sstevel@tonic-gate break;
34227c478bd9Sstevel@tonic-gate }
34237c478bd9Sstevel@tonic-gate }
34247c478bd9Sstevel@tonic-gate
34257c478bd9Sstevel@tonic-gate if (u->atevents != NULL) {
34267c478bd9Sstevel@tonic-gate e = u->atevents;
34277c478bd9Sstevel@tonic-gate for (;;) {
34287c478bd9Sstevel@tonic-gate if (del)
34297c478bd9Sstevel@tonic-gate delete_anc_atjob(e);
34307c478bd9Sstevel@tonic-gate else
34317c478bd9Sstevel@tonic-gate create_anc_atjob(e);
34327c478bd9Sstevel@tonic-gate if ((e = e->link) == NULL)
34337c478bd9Sstevel@tonic-gate break;
34347c478bd9Sstevel@tonic-gate }
34357c478bd9Sstevel@tonic-gate }
34367c478bd9Sstevel@tonic-gate
34377c478bd9Sstevel@tonic-gate if ((u = u->nextusr) == NULL)
34387c478bd9Sstevel@tonic-gate break;
34397c478bd9Sstevel@tonic-gate }
34407c478bd9Sstevel@tonic-gate }
34417c478bd9Sstevel@tonic-gate
34427c478bd9Sstevel@tonic-gate static int
cron_conv(int num_msg,struct pam_message ** msgs,struct pam_response ** response __unused,void * appdata_ptr __unused)34437c478bd9Sstevel@tonic-gate cron_conv(int num_msg, struct pam_message **msgs,
34446b734416SAndy Fiddaman struct pam_response **response __unused, void *appdata_ptr __unused)
34457c478bd9Sstevel@tonic-gate {
34467c478bd9Sstevel@tonic-gate struct pam_message **m = msgs;
34477c478bd9Sstevel@tonic-gate int i;
34487c478bd9Sstevel@tonic-gate
34497c478bd9Sstevel@tonic-gate for (i = 0; i < num_msg; i++) {
34507c478bd9Sstevel@tonic-gate switch (m[i]->msg_style) {
34517c478bd9Sstevel@tonic-gate case PAM_ERROR_MSG:
34527c478bd9Sstevel@tonic-gate case PAM_TEXT_INFO:
34537c478bd9Sstevel@tonic-gate if (m[i]->msg != NULL) {
34547c478bd9Sstevel@tonic-gate (void) msg("%s\n", m[i]->msg);
34557c478bd9Sstevel@tonic-gate }
34567c478bd9Sstevel@tonic-gate break;
34577c478bd9Sstevel@tonic-gate
34587c478bd9Sstevel@tonic-gate default:
34597c478bd9Sstevel@tonic-gate break;
34607c478bd9Sstevel@tonic-gate }
34617c478bd9Sstevel@tonic-gate }
34627c478bd9Sstevel@tonic-gate return (0);
34637c478bd9Sstevel@tonic-gate }
34647c478bd9Sstevel@tonic-gate
34657c478bd9Sstevel@tonic-gate /*
34667c478bd9Sstevel@tonic-gate * Cron creates process for other than job. Mail process is the
34677c478bd9Sstevel@tonic-gate * one which rinfo does not cover. Therefore, miscpid will keep
34687c478bd9Sstevel@tonic-gate * track of the pids executed from cron. Otherwise, we will see
34697c478bd9Sstevel@tonic-gate * "unexpected pid returned.." messages appear in the log file.
34707c478bd9Sstevel@tonic-gate */
34717c478bd9Sstevel@tonic-gate static void
miscpid_insert(pid_t pid)34727c478bd9Sstevel@tonic-gate miscpid_insert(pid_t pid)
34737c478bd9Sstevel@tonic-gate {
34747c478bd9Sstevel@tonic-gate struct miscpid *mp;
34757c478bd9Sstevel@tonic-gate
34767c478bd9Sstevel@tonic-gate mp = xmalloc(sizeof (*mp));
34777c478bd9Sstevel@tonic-gate mp->pid = pid;
34787c478bd9Sstevel@tonic-gate mp->next = miscpid_head;
34797c478bd9Sstevel@tonic-gate miscpid_head = mp;
34807c478bd9Sstevel@tonic-gate }
34817c478bd9Sstevel@tonic-gate
34827c478bd9Sstevel@tonic-gate static int
miscpid_delete(pid_t pid)34837c478bd9Sstevel@tonic-gate miscpid_delete(pid_t pid)
34847c478bd9Sstevel@tonic-gate {
34857c478bd9Sstevel@tonic-gate struct miscpid *mp, *omp;
34867c478bd9Sstevel@tonic-gate int found = 0;
34877c478bd9Sstevel@tonic-gate
34887c478bd9Sstevel@tonic-gate omp = NULL;
34897c478bd9Sstevel@tonic-gate for (mp = miscpid_head; mp != NULL; mp = mp->next) {
34907c478bd9Sstevel@tonic-gate if (mp->pid == pid) {
34917c478bd9Sstevel@tonic-gate found = 1;
34927c478bd9Sstevel@tonic-gate break;
34937c478bd9Sstevel@tonic-gate }
34947c478bd9Sstevel@tonic-gate omp = mp;
34957c478bd9Sstevel@tonic-gate }
34967c478bd9Sstevel@tonic-gate if (found) {
34977c478bd9Sstevel@tonic-gate if (omp != NULL)
34987c478bd9Sstevel@tonic-gate omp->next = mp->next;
34997c478bd9Sstevel@tonic-gate else
35007c478bd9Sstevel@tonic-gate miscpid_head = NULL;
35017c478bd9Sstevel@tonic-gate free(mp);
35027c478bd9Sstevel@tonic-gate }
35037c478bd9Sstevel@tonic-gate return (found);
35047c478bd9Sstevel@tonic-gate }
35057c478bd9Sstevel@tonic-gate
35067c478bd9Sstevel@tonic-gate /*
35077c478bd9Sstevel@tonic-gate * Establish contract terms such that all children are in abandoned
35087c478bd9Sstevel@tonic-gate * process contracts.
35097c478bd9Sstevel@tonic-gate */
3510032624d5Sbasabi static void
contract_set_template(void)3511032624d5Sbasabi contract_set_template(void)
35127c478bd9Sstevel@tonic-gate {
35137c478bd9Sstevel@tonic-gate int fd;
35147c478bd9Sstevel@tonic-gate
35157c478bd9Sstevel@tonic-gate if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) < 0)
35167c478bd9Sstevel@tonic-gate crabort("cannot open process contract template",
35177c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG);
35187c478bd9Sstevel@tonic-gate
35197c478bd9Sstevel@tonic-gate if (ct_pr_tmpl_set_param(fd, 0) ||
35207c478bd9Sstevel@tonic-gate ct_tmpl_set_informative(fd, 0) ||
35217c478bd9Sstevel@tonic-gate ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR))
35227c478bd9Sstevel@tonic-gate crabort("cannot establish contract template terms",
35237c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG);
35247c478bd9Sstevel@tonic-gate
35257c478bd9Sstevel@tonic-gate if (ct_tmpl_activate(fd))
35267c478bd9Sstevel@tonic-gate crabort("cannot activate contract template",
35277c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG);
35287c478bd9Sstevel@tonic-gate
35297c478bd9Sstevel@tonic-gate (void) close(fd);
35307c478bd9Sstevel@tonic-gate }
35317c478bd9Sstevel@tonic-gate
35327c478bd9Sstevel@tonic-gate /*
35337c478bd9Sstevel@tonic-gate * Clear active process contract template.
35347c478bd9Sstevel@tonic-gate */
3535032624d5Sbasabi static void
contract_clear_template(void)3536032624d5Sbasabi contract_clear_template(void)
35377c478bd9Sstevel@tonic-gate {
35387c478bd9Sstevel@tonic-gate int fd;
35397c478bd9Sstevel@tonic-gate
35407c478bd9Sstevel@tonic-gate if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) < 0)
35417c478bd9Sstevel@tonic-gate crabort("cannot open process contract template",
35427c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG);
35437c478bd9Sstevel@tonic-gate
35447c478bd9Sstevel@tonic-gate if (ct_tmpl_clear(fd))
35457c478bd9Sstevel@tonic-gate crabort("cannot clear contract template",
35467c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG);
35477c478bd9Sstevel@tonic-gate
35487c478bd9Sstevel@tonic-gate (void) close(fd);
35497c478bd9Sstevel@tonic-gate }
35507c478bd9Sstevel@tonic-gate
35517c478bd9Sstevel@tonic-gate /*
35527c478bd9Sstevel@tonic-gate * Abandon latest process contract unconditionally. If we have leaked [some
35537c478bd9Sstevel@tonic-gate * critical amount], exit such that the kernel reaps our contracts.
35547c478bd9Sstevel@tonic-gate */
35557c478bd9Sstevel@tonic-gate static void
contract_abandon_latest(pid_t pid)35567c478bd9Sstevel@tonic-gate contract_abandon_latest(pid_t pid)
35577c478bd9Sstevel@tonic-gate {
35587c478bd9Sstevel@tonic-gate int r;
35597c478bd9Sstevel@tonic-gate ctid_t id;
35607c478bd9Sstevel@tonic-gate static uint_t cts_lost;
35617c478bd9Sstevel@tonic-gate
35627c478bd9Sstevel@tonic-gate if (cts_lost > MAX_LOST_CONTRACTS)
35637c478bd9Sstevel@tonic-gate crabort("repeated failure to abandon contracts",
35647c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG);
35657c478bd9Sstevel@tonic-gate
35666b734416SAndy Fiddaman if ((r = contract_latest(&id)) != 0) {
35677c478bd9Sstevel@tonic-gate msg("could not obtain latest contract for "
35687c478bd9Sstevel@tonic-gate "PID %ld: %s", pid, strerror(r));
35697c478bd9Sstevel@tonic-gate cts_lost++;
35707c478bd9Sstevel@tonic-gate return;
35717c478bd9Sstevel@tonic-gate }
35727c478bd9Sstevel@tonic-gate
35736b734416SAndy Fiddaman if ((r = contract_abandon_id(id)) != 0) {
35747c478bd9Sstevel@tonic-gate msg("could not abandon latest contract %ld: %s", id,
35757c478bd9Sstevel@tonic-gate strerror(r));
35767c478bd9Sstevel@tonic-gate cts_lost++;
35777c478bd9Sstevel@tonic-gate return;
35787c478bd9Sstevel@tonic-gate }
35797c478bd9Sstevel@tonic-gate }
35805b08e637SChris Gerhard
35815b08e637SChris Gerhard static struct shared *
create_shared(void * obj,void * (* obj_alloc)(void * obj),void (* obj_free)(void *))35825b08e637SChris Gerhard create_shared(void *obj, void * (*obj_alloc)(void *obj),
35835b08e637SChris Gerhard void (*obj_free)(void *))
35845b08e637SChris Gerhard {
35855b08e637SChris Gerhard struct shared *out;
35865b08e637SChris Gerhard
35875b08e637SChris Gerhard if ((out = xmalloc(sizeof (struct shared))) == NULL) {
35885b08e637SChris Gerhard return (NULL);
35895b08e637SChris Gerhard }
35905b08e637SChris Gerhard if ((out->obj = obj_alloc(obj)) == NULL) {
35915b08e637SChris Gerhard free(out);
35925b08e637SChris Gerhard return (NULL);
35935b08e637SChris Gerhard }
35945b08e637SChris Gerhard out->count = 1;
35955b08e637SChris Gerhard out->free = obj_free;
35965b08e637SChris Gerhard
35975b08e637SChris Gerhard return (out);
35985b08e637SChris Gerhard }
35995b08e637SChris Gerhard
36005b08e637SChris Gerhard static struct shared *
create_shared_str(char * str)36015b08e637SChris Gerhard create_shared_str(char *str)
36025b08e637SChris Gerhard {
36035b08e637SChris Gerhard return (create_shared(str, (void *(*)(void *))strdup, free));
36045b08e637SChris Gerhard }
36055b08e637SChris Gerhard
36065b08e637SChris Gerhard static struct shared *
dup_shared(struct shared * obj)36075b08e637SChris Gerhard dup_shared(struct shared *obj)
36085b08e637SChris Gerhard {
36095b08e637SChris Gerhard if (obj != NULL) {
36105b08e637SChris Gerhard obj->count++;
36115b08e637SChris Gerhard }
36125b08e637SChris Gerhard return (obj);
36135b08e637SChris Gerhard }
36145b08e637SChris Gerhard
36155b08e637SChris Gerhard static void
rel_shared(struct shared * obj)36165b08e637SChris Gerhard rel_shared(struct shared *obj)
36175b08e637SChris Gerhard {
36185b08e637SChris Gerhard if (obj && (--obj->count) == 0) {
36195b08e637SChris Gerhard obj->free(obj->obj);
36205b08e637SChris Gerhard free(obj);
36215b08e637SChris Gerhard }
36225b08e637SChris Gerhard }
36235b08e637SChris Gerhard
36245b08e637SChris Gerhard static void *
get_obj(struct shared * obj)36255b08e637SChris Gerhard get_obj(struct shared *obj)
36265b08e637SChris Gerhard {
36275b08e637SChris Gerhard return (obj->obj);
36285b08e637SChris Gerhard }
3629