1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 31*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #ifdef lint 36*7c478bd9Sstevel@tonic-gate /* make lint happy */ 37*7c478bd9Sstevel@tonic-gate #define __EXTENSIONS__ 38*7c478bd9Sstevel@tonic-gate #endif 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate #include <sys/contract/process.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/ctfs.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/resource.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/task.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 49*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 50*7c478bd9Sstevel@tonic-gate 51*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h> 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #include <alloca.h> 54*7c478bd9Sstevel@tonic-gate #include <ctype.h> 55*7c478bd9Sstevel@tonic-gate #include <deflt.h> 56*7c478bd9Sstevel@tonic-gate #include <dirent.h> 57*7c478bd9Sstevel@tonic-gate #include <errno.h> 58*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 59*7c478bd9Sstevel@tonic-gate #include <grp.h> 60*7c478bd9Sstevel@tonic-gate #include <libcontract.h> 61*7c478bd9Sstevel@tonic-gate #include <libcontract_priv.h> 62*7c478bd9Sstevel@tonic-gate #include <limits.h> 63*7c478bd9Sstevel@tonic-gate #include <locale.h> 64*7c478bd9Sstevel@tonic-gate #include <poll.h> 65*7c478bd9Sstevel@tonic-gate #include <project.h> 66*7c478bd9Sstevel@tonic-gate #include <pwd.h> 67*7c478bd9Sstevel@tonic-gate #include <signal.h> 68*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 69*7c478bd9Sstevel@tonic-gate #include <stdio.h> 70*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 71*7c478bd9Sstevel@tonic-gate #include <string.h> 72*7c478bd9Sstevel@tonic-gate #include <stropts.h> 73*7c478bd9Sstevel@tonic-gate #include <time.h> 74*7c478bd9Sstevel@tonic-gate #include <unistd.h> 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate #include "cron.h" 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate /* 79*7c478bd9Sstevel@tonic-gate * #define DEBUG 80*7c478bd9Sstevel@tonic-gate */ 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate #define MAIL "/usr/bin/mail" /* mail program to use */ 83*7c478bd9Sstevel@tonic-gate #define CONSOLE "/dev/console" /* where messages go when cron dies */ 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate #define TMPINFILE "/tmp/crinXXXXXX" /* file to put stdin in for cmd */ 86*7c478bd9Sstevel@tonic-gate #define TMPDIR "/tmp" 87*7c478bd9Sstevel@tonic-gate #define PFX "crout" 88*7c478bd9Sstevel@tonic-gate #define TMPOUTFILE "/tmp/croutXXXXXX" /* file to place stdout, stderr */ 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate #define INMODE 00400 /* mode for stdin file */ 91*7c478bd9Sstevel@tonic-gate #define OUTMODE 00600 /* mode for stdout file */ 92*7c478bd9Sstevel@tonic-gate #define ISUID S_ISUID /* mode for verifing at jobs */ 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate #define INFINITY 2147483647L /* upper bound on time */ 95*7c478bd9Sstevel@tonic-gate #define CUSHION 180L 96*7c478bd9Sstevel@tonic-gate #define MAXRUN 100 /* max total jobs allowed in system */ 97*7c478bd9Sstevel@tonic-gate #define ZOMB 100 /* proc slot used for mailing output */ 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #define JOBF 'j' 100*7c478bd9Sstevel@tonic-gate #define NICEF 'n' 101*7c478bd9Sstevel@tonic-gate #define USERF 'u' 102*7c478bd9Sstevel@tonic-gate #define WAITF 'w' 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate #define BCHAR '>' 105*7c478bd9Sstevel@tonic-gate #define ECHAR '<' 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate #define DEFAULT 0 108*7c478bd9Sstevel@tonic-gate #define LOAD 1 109*7c478bd9Sstevel@tonic-gate #define QBUFSIZ 80 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate /* Defined actions for crabort() routine */ 112*7c478bd9Sstevel@tonic-gate #define NO_ACTION 000 113*7c478bd9Sstevel@tonic-gate #define REMOVE_FIFO 001 114*7c478bd9Sstevel@tonic-gate #define CONSOLE_MSG 002 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate #define BADCD "can't change directory to the crontab directory." 117*7c478bd9Sstevel@tonic-gate #define NOREADDIR "can't read the crontab directory." 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate #define BADJOBOPEN "unable to read your at job." 120*7c478bd9Sstevel@tonic-gate #define BADSHELL "because your login shell \ 121*7c478bd9Sstevel@tonic-gate isn't /usr/bin/sh, you can't use cron." 122*7c478bd9Sstevel@tonic-gate 123*7c478bd9Sstevel@tonic-gate #define BADSTAT "can't access your crontab file. Resubmit it." 124*7c478bd9Sstevel@tonic-gate #define BADPROJID "can't set project id for your job." 125*7c478bd9Sstevel@tonic-gate #define CANTCDHOME "can't change directory to your home directory.\ 126*7c478bd9Sstevel@tonic-gate \nYour commands will not be executed." 127*7c478bd9Sstevel@tonic-gate #define CANTEXECSH "unable to exec the shell for one of your commands." 128*7c478bd9Sstevel@tonic-gate #define NOREAD "can't read your crontab file. Resubmit it." 129*7c478bd9Sstevel@tonic-gate #define BADTYPE "crontab is not a regular file.\n" 130*7c478bd9Sstevel@tonic-gate #define NOSTDIN "unable to create a standard input file for \ 131*7c478bd9Sstevel@tonic-gate one of your crontab commands. \ 132*7c478bd9Sstevel@tonic-gate \nThat command was not executed." 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate #define NOTALLOWED "you are not authorized to use cron. Sorry." 135*7c478bd9Sstevel@tonic-gate #define STDERRMSG "\n\n********************************************\ 136*7c478bd9Sstevel@tonic-gate *****\nCron: The previous message is the \ 137*7c478bd9Sstevel@tonic-gate standard output and standard error \ 138*7c478bd9Sstevel@tonic-gate \nof one of your cron commands.\n" 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate #define STDOUTERR "one of your commands generated output or errors, \ 141*7c478bd9Sstevel@tonic-gate but cron was unable to mail you this output.\ 142*7c478bd9Sstevel@tonic-gate \nRemember to redirect standard output and standard \ 143*7c478bd9Sstevel@tonic-gate error for each of your commands." 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate #define CLOCK_DRIFT "clock time drifted backwards after event!\n" 146*7c478bd9Sstevel@tonic-gate #define PIDERR "unexpected pid returned %d (ignored)" 147*7c478bd9Sstevel@tonic-gate #define CRONTABERR "Subject: Your crontab file has an error in it\n\n" 148*7c478bd9Sstevel@tonic-gate #define CRONOUT "Subject: Output from \"cron\" command\n\n" 149*7c478bd9Sstevel@tonic-gate #define MALLOCERR "out of space, cannot create new string\n" 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate #define DIDFORK didfork 152*7c478bd9Sstevel@tonic-gate #define NOFORK !didfork 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate #define MAILBUFLEN (8*1024) 155*7c478bd9Sstevel@tonic-gate #define LINELIMIT 80 156*7c478bd9Sstevel@tonic-gate #define MAILBINITFREE (MAILBUFLEN - (sizeof (cte_intro) - 1) \ 157*7c478bd9Sstevel@tonic-gate - (sizeof (cte_trail1) - 1) - (sizeof (cte_trail2) - 1) - 1) 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate #define ERR_CRONTABENT 0 /* error in crontab file entry */ 160*7c478bd9Sstevel@tonic-gate #define ERR_UNIXERR 1 /* error in some system call */ 161*7c478bd9Sstevel@tonic-gate #define ERR_CANTEXECCRON 2 /* error setting up "cron" job environment */ 162*7c478bd9Sstevel@tonic-gate #define ERR_CANTEXECAT 3 /* error setting up "at" job environment */ 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate #define PROJECT "project=" 165*7c478bd9Sstevel@tonic-gate 166*7c478bd9Sstevel@tonic-gate #define MAX_LOST_CONTRACTS 2048 /* reset if this many failed abandons */ 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate #define FORMAT "%a %b %e %H:%M:%S %Y" 169*7c478bd9Sstevel@tonic-gate static char timebuf[80]; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate struct event { 172*7c478bd9Sstevel@tonic-gate time_t time; /* time of the event */ 173*7c478bd9Sstevel@tonic-gate short etype; /* what type of event; 0=cron, 1=at */ 174*7c478bd9Sstevel@tonic-gate char *cmd; /* command for cron, job name for at */ 175*7c478bd9Sstevel@tonic-gate struct usr *u; /* ptr to the owner (usr) of this event */ 176*7c478bd9Sstevel@tonic-gate struct event *link; /* ptr to another event for this user */ 177*7c478bd9Sstevel@tonic-gate union { 178*7c478bd9Sstevel@tonic-gate struct { /* for crontab events */ 179*7c478bd9Sstevel@tonic-gate char *minute; /* (these */ 180*7c478bd9Sstevel@tonic-gate char *hour; /* fields */ 181*7c478bd9Sstevel@tonic-gate char *daymon; /* are */ 182*7c478bd9Sstevel@tonic-gate char *month; /* from */ 183*7c478bd9Sstevel@tonic-gate char *dayweek; /* crontab) */ 184*7c478bd9Sstevel@tonic-gate char *input; /* ptr to stdin */ 185*7c478bd9Sstevel@tonic-gate } ct; 186*7c478bd9Sstevel@tonic-gate struct { /* for at events */ 187*7c478bd9Sstevel@tonic-gate short exists; /* for revising at events */ 188*7c478bd9Sstevel@tonic-gate int eventid; /* for el_remove-ing at events */ 189*7c478bd9Sstevel@tonic-gate } at; 190*7c478bd9Sstevel@tonic-gate } of; 191*7c478bd9Sstevel@tonic-gate }; 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate struct usr { 194*7c478bd9Sstevel@tonic-gate char *name; /* name of user (e.g. "root") */ 195*7c478bd9Sstevel@tonic-gate char *home; /* home directory for user */ 196*7c478bd9Sstevel@tonic-gate uid_t uid; /* user id */ 197*7c478bd9Sstevel@tonic-gate gid_t gid; /* group id */ 198*7c478bd9Sstevel@tonic-gate int aruncnt; /* counter for running jobs per uid */ 199*7c478bd9Sstevel@tonic-gate int cruncnt; /* counter for running cron jobs per uid */ 200*7c478bd9Sstevel@tonic-gate int ctid; /* for el_remove-ing crontab events */ 201*7c478bd9Sstevel@tonic-gate short ctexists; /* for revising crontab events */ 202*7c478bd9Sstevel@tonic-gate struct event *ctevents; /* list of this usr's crontab events */ 203*7c478bd9Sstevel@tonic-gate struct event *atevents; /* list of this usr's at events */ 204*7c478bd9Sstevel@tonic-gate struct usr *nextusr; 205*7c478bd9Sstevel@tonic-gate }; /* ptr to next user */ 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate static struct queue 208*7c478bd9Sstevel@tonic-gate { 209*7c478bd9Sstevel@tonic-gate int njob; /* limit */ 210*7c478bd9Sstevel@tonic-gate int nice; /* nice for execution */ 211*7c478bd9Sstevel@tonic-gate int nwait; /* wait time to next execution attempt */ 212*7c478bd9Sstevel@tonic-gate int nrun; /* number running */ 213*7c478bd9Sstevel@tonic-gate } 214*7c478bd9Sstevel@tonic-gate qd = {100, 2, 60}, /* default values for queue defs */ 215*7c478bd9Sstevel@tonic-gate qt[NQUEUE]; 216*7c478bd9Sstevel@tonic-gate static struct queue qq; 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate struct runinfo 219*7c478bd9Sstevel@tonic-gate { 220*7c478bd9Sstevel@tonic-gate pid_t pid; 221*7c478bd9Sstevel@tonic-gate short que; 222*7c478bd9Sstevel@tonic-gate struct usr *rusr; /* pointer to usr struct */ 223*7c478bd9Sstevel@tonic-gate char *outfile; /* file where stdout & stderr are trapped */ 224*7c478bd9Sstevel@tonic-gate short jobtype; /* what type of event: 0=cron, 1=at */ 225*7c478bd9Sstevel@tonic-gate char *jobname; /* command for "cron", jobname for "at" */ 226*7c478bd9Sstevel@tonic-gate int mailwhendone; /* 1 = send mail even if no ouptut */ 227*7c478bd9Sstevel@tonic-gate } rt[MAXRUN]; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate static struct miscpid { 230*7c478bd9Sstevel@tonic-gate pid_t pid; 231*7c478bd9Sstevel@tonic-gate struct miscpid *next; 232*7c478bd9Sstevel@tonic-gate } *miscpid_head; 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate static pid_t cron_pid; /* own pid */ 235*7c478bd9Sstevel@tonic-gate static char didfork = 0; /* flag to see if I'm process group leader */ 236*7c478bd9Sstevel@tonic-gate static int msgfd; /* file descriptor for fifo queue */ 237*7c478bd9Sstevel@tonic-gate static int ecid = 1; /* event class id for el_remove(); MUST be set to 1 */ 238*7c478bd9Sstevel@tonic-gate static int delayed; /* is job being rescheduled or did it run first time */ 239*7c478bd9Sstevel@tonic-gate static int cwd; /* current working directory */ 240*7c478bd9Sstevel@tonic-gate static struct event *next_event; /* the next event to execute */ 241*7c478bd9Sstevel@tonic-gate static struct usr *uhead; /* ptr to the list of users */ 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate /* Variables for error handling at reading crontabs. */ 244*7c478bd9Sstevel@tonic-gate static char cte_intro[] = "Line(s) with errors:\n\n"; 245*7c478bd9Sstevel@tonic-gate static char cte_trail1[] = "\nMax number of errors encountered."; 246*7c478bd9Sstevel@tonic-gate static char cte_trail2[] = " Evaluation of crontab aborted.\n"; 247*7c478bd9Sstevel@tonic-gate static int cte_free = MAILBINITFREE; /* Free buffer space */ 248*7c478bd9Sstevel@tonic-gate static char *cte_text = NULL; /* Text buffer pointer */ 249*7c478bd9Sstevel@tonic-gate static char *cte_lp; /* Next free line in cte_text */ 250*7c478bd9Sstevel@tonic-gate static int cte_nvalid; /* Valid lines found */ 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate /* user's default environment for the shell */ 253*7c478bd9Sstevel@tonic-gate #define ROOTPATH "PATH=/usr/sbin:/usr/bin" 254*7c478bd9Sstevel@tonic-gate #define NONROOTPATH "PATH=/usr/bin:" 255*7c478bd9Sstevel@tonic-gate 256*7c478bd9Sstevel@tonic-gate static char *Def_supath = NULL; 257*7c478bd9Sstevel@tonic-gate static char *Def_path = NULL; 258*7c478bd9Sstevel@tonic-gate static char path[LINE_MAX] = "PATH="; 259*7c478bd9Sstevel@tonic-gate static char supath[LINE_MAX] = "PATH="; 260*7c478bd9Sstevel@tonic-gate static char homedir[LINE_MAX] = "HOME="; 261*7c478bd9Sstevel@tonic-gate static char logname[LINE_MAX] = "LOGNAME="; 262*7c478bd9Sstevel@tonic-gate static char tzone[LINE_MAX] = "TZ="; 263*7c478bd9Sstevel@tonic-gate static char *envinit[] = { 264*7c478bd9Sstevel@tonic-gate homedir, 265*7c478bd9Sstevel@tonic-gate logname, 266*7c478bd9Sstevel@tonic-gate ROOTPATH, 267*7c478bd9Sstevel@tonic-gate "SHELL=/usr/bin/sh", 268*7c478bd9Sstevel@tonic-gate tzone, 269*7c478bd9Sstevel@tonic-gate NULL 270*7c478bd9Sstevel@tonic-gate }; 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate extern char **environ; 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate #define DEFTZ "GMT" 275*7c478bd9Sstevel@tonic-gate static int log = 0; 276*7c478bd9Sstevel@tonic-gate static char hzname[10]; 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate static void cronend(int); 279*7c478bd9Sstevel@tonic-gate static void thaw_handler(int); 280*7c478bd9Sstevel@tonic-gate static void child_handler(int); 281*7c478bd9Sstevel@tonic-gate static void child_sigreset(void); 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate static void dscan(DIR *dir, void (*fp)(char *, time_t)); 284*7c478bd9Sstevel@tonic-gate static void mod_ctab(char *, time_t); 285*7c478bd9Sstevel@tonic-gate static void mod_atjob(char *, time_t); 286*7c478bd9Sstevel@tonic-gate static void add_atevent(struct usr *, char *, time_t, int); 287*7c478bd9Sstevel@tonic-gate static void rm_ctevents(struct usr *); 288*7c478bd9Sstevel@tonic-gate static void cleanup(struct runinfo *rn, int r); 289*7c478bd9Sstevel@tonic-gate static void crabort(char *, int); 290*7c478bd9Sstevel@tonic-gate static void msg(char *fmt, ...); 291*7c478bd9Sstevel@tonic-gate static void logit(int, struct runinfo *, int); 292*7c478bd9Sstevel@tonic-gate static void parsqdef(char *); 293*7c478bd9Sstevel@tonic-gate static void defaults(); 294*7c478bd9Sstevel@tonic-gate static void initialize(int); 295*7c478bd9Sstevel@tonic-gate static void quedefs(int); 296*7c478bd9Sstevel@tonic-gate static int idle(long); 297*7c478bd9Sstevel@tonic-gate static struct usr *find_usr(char *); 298*7c478bd9Sstevel@tonic-gate static int ex(struct event *e); 299*7c478bd9Sstevel@tonic-gate static void read_dirs(void); 300*7c478bd9Sstevel@tonic-gate static void mail(char *, char *, int); 301*7c478bd9Sstevel@tonic-gate static char *next_field(int, int); 302*7c478bd9Sstevel@tonic-gate static void readcron(struct usr *, time_t); 303*7c478bd9Sstevel@tonic-gate static int next_ge(int, char *); 304*7c478bd9Sstevel@tonic-gate static void free_if_unused(struct usr *); 305*7c478bd9Sstevel@tonic-gate static void del_atjob(char *, char *); 306*7c478bd9Sstevel@tonic-gate static void del_ctab(char *); 307*7c478bd9Sstevel@tonic-gate static void resched(int); 308*7c478bd9Sstevel@tonic-gate static int msg_wait(long); 309*7c478bd9Sstevel@tonic-gate static struct runinfo *rinfo_get(pid_t); 310*7c478bd9Sstevel@tonic-gate static void rinfo_free(struct runinfo *rp); 311*7c478bd9Sstevel@tonic-gate static void mail_result(struct usr *p, struct runinfo *pr, size_t filesize); 312*7c478bd9Sstevel@tonic-gate static time_t next_time(struct event *, time_t); 313*7c478bd9Sstevel@tonic-gate static time_t get_switching_time(int, time_t); 314*7c478bd9Sstevel@tonic-gate static time_t xmktime(struct tm *); 315*7c478bd9Sstevel@tonic-gate static void process_msg(struct message *, time_t); 316*7c478bd9Sstevel@tonic-gate static void reap_child(void); 317*7c478bd9Sstevel@tonic-gate static void miscpid_insert(pid_t); 318*7c478bd9Sstevel@tonic-gate static int miscpid_delete(pid_t); 319*7c478bd9Sstevel@tonic-gate static int contract_set_template(void); 320*7c478bd9Sstevel@tonic-gate static int contract_clear_template(void); 321*7c478bd9Sstevel@tonic-gate static void contract_abandon_latest(pid_t); 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate static void cte_init(void); 324*7c478bd9Sstevel@tonic-gate static void cte_add(int, char *); 325*7c478bd9Sstevel@tonic-gate static void cte_valid(void); 326*7c478bd9Sstevel@tonic-gate static int cte_istoomany(void); 327*7c478bd9Sstevel@tonic-gate static void cte_sendmail(char *); 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate static int set_user_cred(const struct usr *, struct project *); 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate /* 332*7c478bd9Sstevel@tonic-gate * last_time is set immediately prior to exection of an event (via ex()) 333*7c478bd9Sstevel@tonic-gate * to indicate the last time an event was executed. This was (surely) 334*7c478bd9Sstevel@tonic-gate * it's original intended use. 335*7c478bd9Sstevel@tonic-gate */ 336*7c478bd9Sstevel@tonic-gate static time_t last_time, init_time, t_old; 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate static int accept_sigcld, notifypipe[2]; 339*7c478bd9Sstevel@tonic-gate static sigset_t defmask, childmask; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* 342*7c478bd9Sstevel@tonic-gate * BSM hooks 343*7c478bd9Sstevel@tonic-gate */ 344*7c478bd9Sstevel@tonic-gate extern int audit_cron_session(char *, char *, uid_t, gid_t, char *); 345*7c478bd9Sstevel@tonic-gate extern void audit_cron_new_job(char *, int, void *); 346*7c478bd9Sstevel@tonic-gate extern void audit_cron_bad_user(char *); 347*7c478bd9Sstevel@tonic-gate extern void audit_cron_user_acct_expired(char *); 348*7c478bd9Sstevel@tonic-gate extern int audit_cron_create_anc_file(char *, char *, char *, uid_t); 349*7c478bd9Sstevel@tonic-gate extern int audit_cron_delete_anc_file(char *, char *); 350*7c478bd9Sstevel@tonic-gate extern int audit_cron_is_anc_name(char *); 351*7c478bd9Sstevel@tonic-gate extern int audit_cron_mode(); 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate static int cron_conv(int, struct pam_message **, 354*7c478bd9Sstevel@tonic-gate struct pam_response **, void *); 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate static struct pam_conv pam_conv = {cron_conv, NULL}; 357*7c478bd9Sstevel@tonic-gate static pam_handle_t *pamh; /* Authentication handle */ 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate /* 360*7c478bd9Sstevel@tonic-gate * Function to help check a user's credentials. 361*7c478bd9Sstevel@tonic-gate */ 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate static int verify_user_cred(const struct usr *u); 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate /* 366*7c478bd9Sstevel@tonic-gate * Values returned by verify_user_cred and set_user_cred: 367*7c478bd9Sstevel@tonic-gate */ 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate #define VUC_OK 0 370*7c478bd9Sstevel@tonic-gate #define VUC_BADUSER 1 371*7c478bd9Sstevel@tonic-gate #define VUC_NOTINGROUP 2 372*7c478bd9Sstevel@tonic-gate #define VUC_EXPIRED 3 373*7c478bd9Sstevel@tonic-gate #define VUC_NEW_AUTH 4 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate /* 376*7c478bd9Sstevel@tonic-gate * Modes of process_anc_files function 377*7c478bd9Sstevel@tonic-gate */ 378*7c478bd9Sstevel@tonic-gate #define CRON_ANC_DELETE 1 379*7c478bd9Sstevel@tonic-gate #define CRON_ANC_CREATE 0 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate /* 382*7c478bd9Sstevel@tonic-gate * Functions to remove a user or job completely from the running database. 383*7c478bd9Sstevel@tonic-gate */ 384*7c478bd9Sstevel@tonic-gate static void clean_out_atjobs(struct usr *u); 385*7c478bd9Sstevel@tonic-gate static void clean_out_ctab(struct usr *u); 386*7c478bd9Sstevel@tonic-gate static void clean_out_user(struct usr *u); 387*7c478bd9Sstevel@tonic-gate static void cron_unlink(char *name); 388*7c478bd9Sstevel@tonic-gate static void process_anc_files(int); 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate /* 391*7c478bd9Sstevel@tonic-gate * functions in elm.c 392*7c478bd9Sstevel@tonic-gate */ 393*7c478bd9Sstevel@tonic-gate extern void el_init(int, time_t, time_t, int); 394*7c478bd9Sstevel@tonic-gate extern void el_add(void *, time_t, int); 395*7c478bd9Sstevel@tonic-gate extern void el_remove(int, int); 396*7c478bd9Sstevel@tonic-gate extern int el_empty(void); 397*7c478bd9Sstevel@tonic-gate extern void *el_first(void); 398*7c478bd9Sstevel@tonic-gate extern void el_delete(void); 399*7c478bd9Sstevel@tonic-gate 400*7c478bd9Sstevel@tonic-gate int 401*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 402*7c478bd9Sstevel@tonic-gate { 403*7c478bd9Sstevel@tonic-gate time_t t; 404*7c478bd9Sstevel@tonic-gate time_t ne_time; /* amt of time until next event execution */ 405*7c478bd9Sstevel@tonic-gate time_t newtime, lastmtime = 0L; 406*7c478bd9Sstevel@tonic-gate struct usr *u; 407*7c478bd9Sstevel@tonic-gate struct event *e, *e2, *eprev; 408*7c478bd9Sstevel@tonic-gate struct stat buf; 409*7c478bd9Sstevel@tonic-gate pid_t rfork; 410*7c478bd9Sstevel@tonic-gate struct sigaction act; 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* 413*7c478bd9Sstevel@tonic-gate * reset is set to 1 via the return from ex() should ex() find 414*7c478bd9Sstevel@tonic-gate * that the event to be executed is being run at the wrong time. 415*7c478bd9Sstevel@tonic-gate * We immediately return to the top of the while (TRUE) loop in 416*7c478bd9Sstevel@tonic-gate * main() where the event list is cleared and rebuilt, and reset 417*7c478bd9Sstevel@tonic-gate * is set back to 0. 418*7c478bd9Sstevel@tonic-gate */ 419*7c478bd9Sstevel@tonic-gate int reset = 0; 420*7c478bd9Sstevel@tonic-gate 421*7c478bd9Sstevel@tonic-gate /* 422*7c478bd9Sstevel@tonic-gate * Only the privileged user can run this command. 423*7c478bd9Sstevel@tonic-gate */ 424*7c478bd9Sstevel@tonic-gate if (getuid() != 0) 425*7c478bd9Sstevel@tonic-gate crabort(NOTALLOWED, 0); 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate begin: 428*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 429*7c478bd9Sstevel@tonic-gate /* fork unless 'nofork' is specified */ 430*7c478bd9Sstevel@tonic-gate if ((argc <= 1) || (strcmp(argv[1], "nofork"))) { 431*7c478bd9Sstevel@tonic-gate if (rfork = fork()) { 432*7c478bd9Sstevel@tonic-gate if (rfork == (pid_t)-1) { 433*7c478bd9Sstevel@tonic-gate (void) sleep(30); 434*7c478bd9Sstevel@tonic-gate goto begin; 435*7c478bd9Sstevel@tonic-gate } 436*7c478bd9Sstevel@tonic-gate return (0); 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate didfork++; 439*7c478bd9Sstevel@tonic-gate (void) setpgrp(); /* detach cron from console */ 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate (void) umask(022); 443*7c478bd9Sstevel@tonic-gate (void) signal(SIGHUP, SIG_IGN); 444*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); 445*7c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 446*7c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, cronend); 447*7c478bd9Sstevel@tonic-gate 448*7c478bd9Sstevel@tonic-gate defaults(); 449*7c478bd9Sstevel@tonic-gate initialize(1); 450*7c478bd9Sstevel@tonic-gate quedefs(DEFAULT); /* load default queue definitions */ 451*7c478bd9Sstevel@tonic-gate cron_pid = getpid(); 452*7c478bd9Sstevel@tonic-gate msg("*** cron started *** pid = %d", cron_pid); 453*7c478bd9Sstevel@tonic-gate (void) sigset(SIGTHAW, thaw_handler); 454*7c478bd9Sstevel@tonic-gate /* 455*7c478bd9Sstevel@tonic-gate * setup SIGCLD handler/mask 456*7c478bd9Sstevel@tonic-gate */ 457*7c478bd9Sstevel@tonic-gate act.sa_handler = child_handler; 458*7c478bd9Sstevel@tonic-gate act.sa_flags = 0; 459*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&act.sa_mask); 460*7c478bd9Sstevel@tonic-gate (void) sigaddset(&act.sa_mask, SIGCLD); 461*7c478bd9Sstevel@tonic-gate (void) sigaction(SIGCLD, &act, NULL); 462*7c478bd9Sstevel@tonic-gate (void) sigemptyset(&childmask); 463*7c478bd9Sstevel@tonic-gate (void) sigaddset(&childmask, SIGCLD); 464*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &childmask, &defmask); 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate if (pipe(notifypipe) != 0) { 467*7c478bd9Sstevel@tonic-gate crabort("cannot create pipe", REMOVE_FIFO|CONSOLE_MSG); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate /* 470*7c478bd9Sstevel@tonic-gate * will set O_NONBLOCK, so that the write() from child_handler 471*7c478bd9Sstevel@tonic-gate * never be blocked. 472*7c478bd9Sstevel@tonic-gate */ 473*7c478bd9Sstevel@tonic-gate (void) fcntl(notifypipe[0], F_SETFL, O_WRONLY|O_NONBLOCK); 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate t_old = time(NULL); 476*7c478bd9Sstevel@tonic-gate last_time = t_old; 477*7c478bd9Sstevel@tonic-gate for (;;) { /* MAIN LOOP */ 478*7c478bd9Sstevel@tonic-gate t = time(NULL); 479*7c478bd9Sstevel@tonic-gate if ((t_old > t) || (t-last_time > CUSHION) || reset) { 480*7c478bd9Sstevel@tonic-gate reset = 0; 481*7c478bd9Sstevel@tonic-gate /* the time was set backwards or forward */ 482*7c478bd9Sstevel@tonic-gate el_delete(); 483*7c478bd9Sstevel@tonic-gate u = uhead; 484*7c478bd9Sstevel@tonic-gate while (u != NULL) { 485*7c478bd9Sstevel@tonic-gate rm_ctevents(u); 486*7c478bd9Sstevel@tonic-gate e = u->atevents; 487*7c478bd9Sstevel@tonic-gate while (e != NULL) { 488*7c478bd9Sstevel@tonic-gate free(e->cmd); 489*7c478bd9Sstevel@tonic-gate e2 = e->link; 490*7c478bd9Sstevel@tonic-gate free(e); 491*7c478bd9Sstevel@tonic-gate e = e2; 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate u->atevents = NULL; 494*7c478bd9Sstevel@tonic-gate u = u->nextusr; 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate (void) close(msgfd); 497*7c478bd9Sstevel@tonic-gate initialize(0); 498*7c478bd9Sstevel@tonic-gate t = time(NULL); 499*7c478bd9Sstevel@tonic-gate last_time = t; 500*7c478bd9Sstevel@tonic-gate } 501*7c478bd9Sstevel@tonic-gate t_old = t; 502*7c478bd9Sstevel@tonic-gate 503*7c478bd9Sstevel@tonic-gate if (next_event == NULL && !el_empty()) { 504*7c478bd9Sstevel@tonic-gate next_event = (struct event *)el_first(); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate if (next_event == NULL) { 507*7c478bd9Sstevel@tonic-gate ne_time = INFINITY; 508*7c478bd9Sstevel@tonic-gate } else { 509*7c478bd9Sstevel@tonic-gate ne_time = next_event->time - t; 510*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 511*7c478bd9Sstevel@tonic-gate cftime(timebuf, "%C", &next_event->time); 512*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "next_time=%ld %s\n", 513*7c478bd9Sstevel@tonic-gate next_event->time, timebuf); 514*7c478bd9Sstevel@tonic-gate #endif 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate if (ne_time > 0) { 517*7c478bd9Sstevel@tonic-gate if ((reset = idle(ne_time)) != 0) 518*7c478bd9Sstevel@tonic-gate continue; 519*7c478bd9Sstevel@tonic-gate } 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate if (stat(QUEDEFS, &buf)) { 522*7c478bd9Sstevel@tonic-gate msg("cannot stat QUEDEFS file"); 523*7c478bd9Sstevel@tonic-gate } else if (lastmtime != buf.st_mtime) { 524*7c478bd9Sstevel@tonic-gate quedefs(LOAD); 525*7c478bd9Sstevel@tonic-gate lastmtime = buf.st_mtime; 526*7c478bd9Sstevel@tonic-gate } 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate last_time = next_event->time; /* save execution time */ 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate if (reset = ex(next_event)) 531*7c478bd9Sstevel@tonic-gate continue; 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate switch (next_event->etype) { 534*7c478bd9Sstevel@tonic-gate case CRONEVENT: 535*7c478bd9Sstevel@tonic-gate /* add cronevent back into the main event list */ 536*7c478bd9Sstevel@tonic-gate if (delayed) { 537*7c478bd9Sstevel@tonic-gate delayed = 0; 538*7c478bd9Sstevel@tonic-gate break; 539*7c478bd9Sstevel@tonic-gate } 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate /* 542*7c478bd9Sstevel@tonic-gate * check if time(0)< last_time. if so, then the 543*7c478bd9Sstevel@tonic-gate * system clock has gone backwards. to prevent this 544*7c478bd9Sstevel@tonic-gate * job from being started twice, we reschedule this 545*7c478bd9Sstevel@tonic-gate * job for the >>next time after last_time<<, and 546*7c478bd9Sstevel@tonic-gate * then set next_event->time to this. note that 547*7c478bd9Sstevel@tonic-gate * crontab's resolution is 1 minute. 548*7c478bd9Sstevel@tonic-gate */ 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate if (last_time > time(NULL)) { 551*7c478bd9Sstevel@tonic-gate msg(CLOCK_DRIFT); 552*7c478bd9Sstevel@tonic-gate /* 553*7c478bd9Sstevel@tonic-gate * bump up to next 30 second 554*7c478bd9Sstevel@tonic-gate * increment 555*7c478bd9Sstevel@tonic-gate * 1 <= newtime <= 30 556*7c478bd9Sstevel@tonic-gate */ 557*7c478bd9Sstevel@tonic-gate newtime = 30 - (last_time % 30); 558*7c478bd9Sstevel@tonic-gate newtime += last_time; 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * get the next scheduled event, 562*7c478bd9Sstevel@tonic-gate * not the one that we just 563*7c478bd9Sstevel@tonic-gate * kicked off! 564*7c478bd9Sstevel@tonic-gate */ 565*7c478bd9Sstevel@tonic-gate next_event->time = 566*7c478bd9Sstevel@tonic-gate next_time(next_event, newtime); 567*7c478bd9Sstevel@tonic-gate t_old = time(NULL); 568*7c478bd9Sstevel@tonic-gate } else { 569*7c478bd9Sstevel@tonic-gate next_event->time = 570*7c478bd9Sstevel@tonic-gate next_time(next_event, (time_t)0); 571*7c478bd9Sstevel@tonic-gate } 572*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 573*7c478bd9Sstevel@tonic-gate cftime(timebuf, "%C", &next_event->time); 574*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 575*7c478bd9Sstevel@tonic-gate "pushing back cron event %s at %ld (%s)\n", 576*7c478bd9Sstevel@tonic-gate next_event->cmd, next_event->time, timebuf); 577*7c478bd9Sstevel@tonic-gate #endif 578*7c478bd9Sstevel@tonic-gate 579*7c478bd9Sstevel@tonic-gate el_add(next_event, next_event->time, 580*7c478bd9Sstevel@tonic-gate (next_event->u)->ctid); 581*7c478bd9Sstevel@tonic-gate break; 582*7c478bd9Sstevel@tonic-gate default: 583*7c478bd9Sstevel@tonic-gate /* remove at or batch job from system */ 584*7c478bd9Sstevel@tonic-gate if (delayed) { 585*7c478bd9Sstevel@tonic-gate delayed = 0; 586*7c478bd9Sstevel@tonic-gate break; 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate eprev = NULL; 589*7c478bd9Sstevel@tonic-gate e = (next_event->u)->atevents; 590*7c478bd9Sstevel@tonic-gate while (e != NULL) { 591*7c478bd9Sstevel@tonic-gate if (e == next_event) { 592*7c478bd9Sstevel@tonic-gate if (eprev == NULL) 593*7c478bd9Sstevel@tonic-gate (e->u)->atevents = e->link; 594*7c478bd9Sstevel@tonic-gate else 595*7c478bd9Sstevel@tonic-gate eprev->link = e->link; 596*7c478bd9Sstevel@tonic-gate free(e->cmd); 597*7c478bd9Sstevel@tonic-gate free(e); 598*7c478bd9Sstevel@tonic-gate break; 599*7c478bd9Sstevel@tonic-gate } else { 600*7c478bd9Sstevel@tonic-gate eprev = e; 601*7c478bd9Sstevel@tonic-gate e = e->link; 602*7c478bd9Sstevel@tonic-gate } 603*7c478bd9Sstevel@tonic-gate } 604*7c478bd9Sstevel@tonic-gate break; 605*7c478bd9Sstevel@tonic-gate } 606*7c478bd9Sstevel@tonic-gate next_event = NULL; 607*7c478bd9Sstevel@tonic-gate } 608*7c478bd9Sstevel@tonic-gate 609*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate 612*7c478bd9Sstevel@tonic-gate static void 613*7c478bd9Sstevel@tonic-gate initialize(int firstpass) 614*7c478bd9Sstevel@tonic-gate { 615*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 616*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "in initialize\n"); 617*7c478bd9Sstevel@tonic-gate #endif 618*7c478bd9Sstevel@tonic-gate init_time = time(NULL); 619*7c478bd9Sstevel@tonic-gate el_init(8, init_time, (time_t)(60*60*24), 10); 620*7c478bd9Sstevel@tonic-gate if (firstpass) { 621*7c478bd9Sstevel@tonic-gate /* for mail(1), make sure messages come from root */ 622*7c478bd9Sstevel@tonic-gate if (putenv("LOGNAME=root") != 0) { 623*7c478bd9Sstevel@tonic-gate crabort("cannot expand env variable", 624*7c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate if (access(FIFO, R_OK) == -1) { 627*7c478bd9Sstevel@tonic-gate if (errno == ENOENT) { 628*7c478bd9Sstevel@tonic-gate if (mknod(FIFO, S_IFIFO|0600, 0) != 0) 629*7c478bd9Sstevel@tonic-gate crabort("cannot create fifo queue", 630*7c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG); 631*7c478bd9Sstevel@tonic-gate } else { 632*7c478bd9Sstevel@tonic-gate if (NOFORK) { 633*7c478bd9Sstevel@tonic-gate /* didn't fork... init(1M) is waiting */ 634*7c478bd9Sstevel@tonic-gate (void) sleep(60); 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate perror("FIFO"); 637*7c478bd9Sstevel@tonic-gate crabort("cannot access fifo queue", 638*7c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG); 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate } else { 641*7c478bd9Sstevel@tonic-gate if (NOFORK) { 642*7c478bd9Sstevel@tonic-gate /* didn't fork... init(1M) is waiting */ 643*7c478bd9Sstevel@tonic-gate (void) sleep(60); 644*7c478bd9Sstevel@tonic-gate /* 645*7c478bd9Sstevel@tonic-gate * the wait is painful, but we don't want 646*7c478bd9Sstevel@tonic-gate * init respawning this quickly 647*7c478bd9Sstevel@tonic-gate */ 648*7c478bd9Sstevel@tonic-gate } 649*7c478bd9Sstevel@tonic-gate crabort("cannot start cron; FIFO exists", CONSOLE_MSG); 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate 653*7c478bd9Sstevel@tonic-gate if ((msgfd = open(FIFO, O_RDWR)) < 0) { 654*7c478bd9Sstevel@tonic-gate perror("! open"); 655*7c478bd9Sstevel@tonic-gate crabort("cannot open fifo queue", REMOVE_FIFO|CONSOLE_MSG); 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate /* 659*7c478bd9Sstevel@tonic-gate * read directories, create users list, and add events to the 660*7c478bd9Sstevel@tonic-gate * main event list. Only zero user list on firstpass. 661*7c478bd9Sstevel@tonic-gate */ 662*7c478bd9Sstevel@tonic-gate if (firstpass) 663*7c478bd9Sstevel@tonic-gate uhead = NULL; 664*7c478bd9Sstevel@tonic-gate read_dirs(); 665*7c478bd9Sstevel@tonic-gate next_event = NULL; 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate if (!firstpass) 668*7c478bd9Sstevel@tonic-gate return; 669*7c478bd9Sstevel@tonic-gate 670*7c478bd9Sstevel@tonic-gate /* stdout is log file */ 671*7c478bd9Sstevel@tonic-gate if (freopen(ACCTFILE, "a", stdout) == NULL) 672*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "cannot open %s\n", ACCTFILE); 673*7c478bd9Sstevel@tonic-gate 674*7c478bd9Sstevel@tonic-gate /* log should be root-only */ 675*7c478bd9Sstevel@tonic-gate (void) fchmod(1, S_IRUSR|S_IWUSR); 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate /* stderr also goes to ACCTFILE */ 678*7c478bd9Sstevel@tonic-gate (void) close(fileno(stderr)); 679*7c478bd9Sstevel@tonic-gate (void) dup(1); 680*7c478bd9Sstevel@tonic-gate 681*7c478bd9Sstevel@tonic-gate /* null for stdin */ 682*7c478bd9Sstevel@tonic-gate (void) freopen("/dev/null", "r", stdin); 683*7c478bd9Sstevel@tonic-gate 684*7c478bd9Sstevel@tonic-gate contract_set_template(); 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate static void 688*7c478bd9Sstevel@tonic-gate read_dirs() 689*7c478bd9Sstevel@tonic-gate { 690*7c478bd9Sstevel@tonic-gate DIR *dir; 691*7c478bd9Sstevel@tonic-gate 692*7c478bd9Sstevel@tonic-gate if (chdir(CRONDIR) == -1) 693*7c478bd9Sstevel@tonic-gate crabort(BADCD, REMOVE_FIFO|CONSOLE_MSG); 694*7c478bd9Sstevel@tonic-gate cwd = CRON; 695*7c478bd9Sstevel@tonic-gate if ((dir = opendir(".")) == NULL) 696*7c478bd9Sstevel@tonic-gate crabort(NOREADDIR, REMOVE_FIFO|CONSOLE_MSG); 697*7c478bd9Sstevel@tonic-gate dscan(dir, mod_ctab); 698*7c478bd9Sstevel@tonic-gate (void) closedir(dir); 699*7c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == -1) { 700*7c478bd9Sstevel@tonic-gate msg("cannot chdir to at directory"); 701*7c478bd9Sstevel@tonic-gate return; 702*7c478bd9Sstevel@tonic-gate } 703*7c478bd9Sstevel@tonic-gate cwd = AT; 704*7c478bd9Sstevel@tonic-gate if ((dir = opendir(".")) == NULL) { 705*7c478bd9Sstevel@tonic-gate msg("cannot read at at directory"); 706*7c478bd9Sstevel@tonic-gate return; 707*7c478bd9Sstevel@tonic-gate } 708*7c478bd9Sstevel@tonic-gate dscan(dir, mod_atjob); 709*7c478bd9Sstevel@tonic-gate (void) closedir(dir); 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate static void 713*7c478bd9Sstevel@tonic-gate dscan(DIR *df, void (*fp)(char *, time_t)) 714*7c478bd9Sstevel@tonic-gate { 715*7c478bd9Sstevel@tonic-gate struct dirent *dp; 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate while ((dp = readdir(df)) != NULL) { 718*7c478bd9Sstevel@tonic-gate if (strcmp(dp->d_name, ".") == 0 || 719*7c478bd9Sstevel@tonic-gate strcmp(dp->d_name, "..") == 0) { 720*7c478bd9Sstevel@tonic-gate continue; 721*7c478bd9Sstevel@tonic-gate } 722*7c478bd9Sstevel@tonic-gate (*fp)(dp->d_name, 0); 723*7c478bd9Sstevel@tonic-gate } 724*7c478bd9Sstevel@tonic-gate } 725*7c478bd9Sstevel@tonic-gate 726*7c478bd9Sstevel@tonic-gate static void 727*7c478bd9Sstevel@tonic-gate mod_ctab(char *name, time_t reftime) 728*7c478bd9Sstevel@tonic-gate { 729*7c478bd9Sstevel@tonic-gate struct passwd *pw; 730*7c478bd9Sstevel@tonic-gate struct stat buf; 731*7c478bd9Sstevel@tonic-gate struct usr *u; 732*7c478bd9Sstevel@tonic-gate char namebuf[PATH_MAX]; 733*7c478bd9Sstevel@tonic-gate char *pname; 734*7c478bd9Sstevel@tonic-gate 735*7c478bd9Sstevel@tonic-gate /* skip over ancillary file names */ 736*7c478bd9Sstevel@tonic-gate if (audit_cron_is_anc_name(name)) 737*7c478bd9Sstevel@tonic-gate return; 738*7c478bd9Sstevel@tonic-gate 739*7c478bd9Sstevel@tonic-gate if ((pw = getpwnam(name)) == NULL) { 740*7c478bd9Sstevel@tonic-gate msg("No such user as %s - cron entries not created", name); 741*7c478bd9Sstevel@tonic-gate return; 742*7c478bd9Sstevel@tonic-gate } 743*7c478bd9Sstevel@tonic-gate if (cwd != CRON) { 744*7c478bd9Sstevel@tonic-gate if (snprintf(namebuf, sizeof (namebuf), "%s/%s", 745*7c478bd9Sstevel@tonic-gate CRONDIR, name) >= sizeof (namebuf)) { 746*7c478bd9Sstevel@tonic-gate msg("Too long path name %s - cron entries not created", 747*7c478bd9Sstevel@tonic-gate namebuf); 748*7c478bd9Sstevel@tonic-gate return; 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate pname = namebuf; 751*7c478bd9Sstevel@tonic-gate } else { 752*7c478bd9Sstevel@tonic-gate pname = name; 753*7c478bd9Sstevel@tonic-gate } 754*7c478bd9Sstevel@tonic-gate /* 755*7c478bd9Sstevel@tonic-gate * a warning message is given by the crontab command so there is 756*7c478bd9Sstevel@tonic-gate * no need to give one here...... use this code if you only want 757*7c478bd9Sstevel@tonic-gate * users with a login shell of /usr/bin/sh to use cron 758*7c478bd9Sstevel@tonic-gate */ 759*7c478bd9Sstevel@tonic-gate #ifdef BOURNESHELLONLY 760*7c478bd9Sstevel@tonic-gate if ((strcmp(pw->pw_shell, "") != 0) && 761*7c478bd9Sstevel@tonic-gate (strcmp(pw->pw_shell, SHELL) != 0)) { 762*7c478bd9Sstevel@tonic-gate mail(name, BADSHELL, ERR_CANTEXECCRON); 763*7c478bd9Sstevel@tonic-gate cron_unlink(pname); 764*7c478bd9Sstevel@tonic-gate return; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate #endif 767*7c478bd9Sstevel@tonic-gate if (stat(pname, &buf)) { 768*7c478bd9Sstevel@tonic-gate mail(name, BADSTAT, ERR_UNIXERR); 769*7c478bd9Sstevel@tonic-gate cron_unlink(pname); 770*7c478bd9Sstevel@tonic-gate return; 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate if (!S_ISREG(buf.st_mode)) { 773*7c478bd9Sstevel@tonic-gate mail(name, BADTYPE, ERR_CRONTABENT); 774*7c478bd9Sstevel@tonic-gate return; 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate if ((u = find_usr(name)) == NULL) { 777*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 778*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "new user (%s) with a crontab\n", name); 779*7c478bd9Sstevel@tonic-gate #endif 780*7c478bd9Sstevel@tonic-gate u = xmalloc(sizeof (struct usr)); 781*7c478bd9Sstevel@tonic-gate u->name = xmalloc(strlen(name)+1); 782*7c478bd9Sstevel@tonic-gate (void) strcpy(u->name, name); 783*7c478bd9Sstevel@tonic-gate u->home = xmalloc(strlen(pw->pw_dir)+1); 784*7c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir); 785*7c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 786*7c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 787*7c478bd9Sstevel@tonic-gate u->ctexists = TRUE; 788*7c478bd9Sstevel@tonic-gate u->ctid = ecid++; 789*7c478bd9Sstevel@tonic-gate u->ctevents = NULL; 790*7c478bd9Sstevel@tonic-gate u->atevents = NULL; 791*7c478bd9Sstevel@tonic-gate u->aruncnt = 0; 792*7c478bd9Sstevel@tonic-gate u->cruncnt = 0; 793*7c478bd9Sstevel@tonic-gate u->nextusr = uhead; 794*7c478bd9Sstevel@tonic-gate uhead = u; 795*7c478bd9Sstevel@tonic-gate readcron(u, reftime); 796*7c478bd9Sstevel@tonic-gate } else { 797*7c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 798*7c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 799*7c478bd9Sstevel@tonic-gate if (strcmp(u->home, pw->pw_dir) != 0) { 800*7c478bd9Sstevel@tonic-gate free(u->home); 801*7c478bd9Sstevel@tonic-gate u->home = xmalloc(strlen(pw->pw_dir)+1); 802*7c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir); 803*7c478bd9Sstevel@tonic-gate } 804*7c478bd9Sstevel@tonic-gate u->ctexists = TRUE; 805*7c478bd9Sstevel@tonic-gate if (u->ctid == 0) { 806*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 807*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s now has a crontab\n", 808*7c478bd9Sstevel@tonic-gate u->name); 809*7c478bd9Sstevel@tonic-gate #endif 810*7c478bd9Sstevel@tonic-gate /* user didnt have a crontab last time */ 811*7c478bd9Sstevel@tonic-gate u->ctid = ecid++; 812*7c478bd9Sstevel@tonic-gate u->ctevents = NULL; 813*7c478bd9Sstevel@tonic-gate readcron(u, reftime); 814*7c478bd9Sstevel@tonic-gate return; 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 817*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s has revised his crontab\n", u->name); 818*7c478bd9Sstevel@tonic-gate #endif 819*7c478bd9Sstevel@tonic-gate rm_ctevents(u); 820*7c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0); 821*7c478bd9Sstevel@tonic-gate readcron(u, reftime); 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate } 824*7c478bd9Sstevel@tonic-gate 825*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 826*7c478bd9Sstevel@tonic-gate static void 827*7c478bd9Sstevel@tonic-gate mod_atjob(char *name, time_t reftime) 828*7c478bd9Sstevel@tonic-gate { 829*7c478bd9Sstevel@tonic-gate char *ptr; 830*7c478bd9Sstevel@tonic-gate time_t tim; 831*7c478bd9Sstevel@tonic-gate struct passwd *pw; 832*7c478bd9Sstevel@tonic-gate struct stat buf; 833*7c478bd9Sstevel@tonic-gate struct usr *u; 834*7c478bd9Sstevel@tonic-gate struct event *e; 835*7c478bd9Sstevel@tonic-gate char namebuf[PATH_MAX]; 836*7c478bd9Sstevel@tonic-gate char *pname; 837*7c478bd9Sstevel@tonic-gate int jobtype; 838*7c478bd9Sstevel@tonic-gate 839*7c478bd9Sstevel@tonic-gate ptr = name; 840*7c478bd9Sstevel@tonic-gate if (((tim = num(&ptr)) == 0) || (*ptr != '.')) 841*7c478bd9Sstevel@tonic-gate return; 842*7c478bd9Sstevel@tonic-gate ptr++; 843*7c478bd9Sstevel@tonic-gate if (!isalpha(*ptr)) 844*7c478bd9Sstevel@tonic-gate return; 845*7c478bd9Sstevel@tonic-gate jobtype = *ptr - 'a'; 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate /* check for audit ancillary file */ 848*7c478bd9Sstevel@tonic-gate if (audit_cron_is_anc_name(name)) 849*7c478bd9Sstevel@tonic-gate return; 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate if (cwd != AT) { 852*7c478bd9Sstevel@tonic-gate if (snprintf(namebuf, sizeof (namebuf), "%s/%s", ATDIR, name) 853*7c478bd9Sstevel@tonic-gate >= sizeof (namebuf)) { 854*7c478bd9Sstevel@tonic-gate return; 855*7c478bd9Sstevel@tonic-gate } 856*7c478bd9Sstevel@tonic-gate pname = namebuf; 857*7c478bd9Sstevel@tonic-gate } else { 858*7c478bd9Sstevel@tonic-gate pname = name; 859*7c478bd9Sstevel@tonic-gate } 860*7c478bd9Sstevel@tonic-gate if (stat(pname, &buf) || jobtype >= NQUEUE) { 861*7c478bd9Sstevel@tonic-gate cron_unlink(pname); 862*7c478bd9Sstevel@tonic-gate return; 863*7c478bd9Sstevel@tonic-gate } 864*7c478bd9Sstevel@tonic-gate if (!(buf.st_mode & ISUID) || !S_ISREG(buf.st_mode)) { 865*7c478bd9Sstevel@tonic-gate cron_unlink(pname); 866*7c478bd9Sstevel@tonic-gate return; 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate if ((pw = getpwuid(buf.st_uid)) == NULL) { 869*7c478bd9Sstevel@tonic-gate cron_unlink(pname); 870*7c478bd9Sstevel@tonic-gate return; 871*7c478bd9Sstevel@tonic-gate } 872*7c478bd9Sstevel@tonic-gate /* 873*7c478bd9Sstevel@tonic-gate * a warning message is given by the at command so there is no 874*7c478bd9Sstevel@tonic-gate * need to give one here......use this code if you only want 875*7c478bd9Sstevel@tonic-gate * users with a login shell of /usr/bin/sh to use cron 876*7c478bd9Sstevel@tonic-gate */ 877*7c478bd9Sstevel@tonic-gate #ifdef BOURNESHELLONLY 878*7c478bd9Sstevel@tonic-gate if ((strcmp(pw->pw_shell, "") != 0) && 879*7c478bd9Sstevel@tonic-gate (strcmp(pw->pw_shell, SHELL) != 0)) { 880*7c478bd9Sstevel@tonic-gate mail(pw->pw_name, BADSHELL, ERR_CANTEXECAT); 881*7c478bd9Sstevel@tonic-gate cron_unlink(pname); 882*7c478bd9Sstevel@tonic-gate return; 883*7c478bd9Sstevel@tonic-gate } 884*7c478bd9Sstevel@tonic-gate #endif 885*7c478bd9Sstevel@tonic-gate if ((u = find_usr(pw->pw_name)) == NULL) { 886*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 887*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "new user (%s) with an at job = %s\n", 888*7c478bd9Sstevel@tonic-gate pw->pw_name, name); 889*7c478bd9Sstevel@tonic-gate #endif 890*7c478bd9Sstevel@tonic-gate u = xmalloc(sizeof (struct usr)); 891*7c478bd9Sstevel@tonic-gate u->name = xmalloc(strlen(pw->pw_name)+1); 892*7c478bd9Sstevel@tonic-gate (void) strcpy(u->name, pw->pw_name); 893*7c478bd9Sstevel@tonic-gate u->home = xmalloc(strlen(pw->pw_dir)+1); 894*7c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir); 895*7c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 896*7c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 897*7c478bd9Sstevel@tonic-gate u->ctexists = FALSE; 898*7c478bd9Sstevel@tonic-gate u->ctid = 0; 899*7c478bd9Sstevel@tonic-gate u->ctevents = NULL; 900*7c478bd9Sstevel@tonic-gate u->atevents = NULL; 901*7c478bd9Sstevel@tonic-gate u->aruncnt = 0; 902*7c478bd9Sstevel@tonic-gate u->cruncnt = 0; 903*7c478bd9Sstevel@tonic-gate u->nextusr = uhead; 904*7c478bd9Sstevel@tonic-gate uhead = u; 905*7c478bd9Sstevel@tonic-gate add_atevent(u, name, tim, jobtype); 906*7c478bd9Sstevel@tonic-gate } else { 907*7c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 908*7c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 909*7c478bd9Sstevel@tonic-gate if (strcmp(u->home, pw->pw_dir) != 0) { 910*7c478bd9Sstevel@tonic-gate free(u->home); 911*7c478bd9Sstevel@tonic-gate u->home = xmalloc(strlen(pw->pw_dir)+1); 912*7c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir); 913*7c478bd9Sstevel@tonic-gate } 914*7c478bd9Sstevel@tonic-gate e = u->atevents; 915*7c478bd9Sstevel@tonic-gate while (e != NULL) { 916*7c478bd9Sstevel@tonic-gate if (strcmp(e->cmd, name) == 0) { 917*7c478bd9Sstevel@tonic-gate e->of.at.exists = TRUE; 918*7c478bd9Sstevel@tonic-gate break; 919*7c478bd9Sstevel@tonic-gate } else { 920*7c478bd9Sstevel@tonic-gate e = e->link; 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate } 923*7c478bd9Sstevel@tonic-gate if (e == NULL) { 924*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 925*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s has a new at job = %s\n", 926*7c478bd9Sstevel@tonic-gate u->name, name); 927*7c478bd9Sstevel@tonic-gate #endif 928*7c478bd9Sstevel@tonic-gate add_atevent(u, name, tim, jobtype); 929*7c478bd9Sstevel@tonic-gate } 930*7c478bd9Sstevel@tonic-gate } 931*7c478bd9Sstevel@tonic-gate } 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate static void 934*7c478bd9Sstevel@tonic-gate add_atevent(struct usr *u, char *job, time_t tim, int jobtype) 935*7c478bd9Sstevel@tonic-gate { 936*7c478bd9Sstevel@tonic-gate struct event *e; 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate e = xmalloc(sizeof (struct event)); 939*7c478bd9Sstevel@tonic-gate e->etype = jobtype; 940*7c478bd9Sstevel@tonic-gate e->cmd = xmalloc(strlen(job)+1); 941*7c478bd9Sstevel@tonic-gate (void) strcpy(e->cmd, job); 942*7c478bd9Sstevel@tonic-gate e->u = u; 943*7c478bd9Sstevel@tonic-gate e->link = u->atevents; 944*7c478bd9Sstevel@tonic-gate u->atevents = e; 945*7c478bd9Sstevel@tonic-gate e->of.at.exists = TRUE; 946*7c478bd9Sstevel@tonic-gate e->of.at.eventid = ecid++; 947*7c478bd9Sstevel@tonic-gate if (tim < init_time) /* old job */ 948*7c478bd9Sstevel@tonic-gate e->time = init_time; 949*7c478bd9Sstevel@tonic-gate else 950*7c478bd9Sstevel@tonic-gate e->time = tim; 951*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 952*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "add_atevent: user=%s, job=%s, time=%ld\n", 953*7c478bd9Sstevel@tonic-gate u->name, e->cmd, e->time); 954*7c478bd9Sstevel@tonic-gate #endif 955*7c478bd9Sstevel@tonic-gate el_add(e, e->time, e->of.at.eventid); 956*7c478bd9Sstevel@tonic-gate } 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate static char line[CTLINESIZE]; /* holds a line from a crontab file */ 960*7c478bd9Sstevel@tonic-gate static int cursor; /* cursor for the above line */ 961*7c478bd9Sstevel@tonic-gate 962*7c478bd9Sstevel@tonic-gate static void 963*7c478bd9Sstevel@tonic-gate readcron(struct usr *u, time_t reftime) 964*7c478bd9Sstevel@tonic-gate { 965*7c478bd9Sstevel@tonic-gate /* 966*7c478bd9Sstevel@tonic-gate * readcron reads in a crontab file for a user (u). The list of 967*7c478bd9Sstevel@tonic-gate * events for user u is built, and u->events is made to point to 968*7c478bd9Sstevel@tonic-gate * this list. Each event is also entered into the main event 969*7c478bd9Sstevel@tonic-gate * list. 970*7c478bd9Sstevel@tonic-gate */ 971*7c478bd9Sstevel@tonic-gate FILE *cf; /* cf will be a user's crontab file */ 972*7c478bd9Sstevel@tonic-gate struct event *e; 973*7c478bd9Sstevel@tonic-gate int start; 974*7c478bd9Sstevel@tonic-gate unsigned int i; 975*7c478bd9Sstevel@tonic-gate char namebuf[PATH_MAX]; 976*7c478bd9Sstevel@tonic-gate char *pname; 977*7c478bd9Sstevel@tonic-gate int lineno = 0; 978*7c478bd9Sstevel@tonic-gate 979*7c478bd9Sstevel@tonic-gate /* read the crontab file */ 980*7c478bd9Sstevel@tonic-gate cte_init(); /* Init error handling */ 981*7c478bd9Sstevel@tonic-gate if (cwd != CRON) { 982*7c478bd9Sstevel@tonic-gate if (snprintf(namebuf, sizeof (namebuf), "%s/%s", 983*7c478bd9Sstevel@tonic-gate CRONDIR, u->name) >= sizeof (namebuf)) { 984*7c478bd9Sstevel@tonic-gate return; 985*7c478bd9Sstevel@tonic-gate } 986*7c478bd9Sstevel@tonic-gate pname = namebuf; 987*7c478bd9Sstevel@tonic-gate } else { 988*7c478bd9Sstevel@tonic-gate pname = u->name; 989*7c478bd9Sstevel@tonic-gate } 990*7c478bd9Sstevel@tonic-gate if ((cf = fopen(pname, "r")) == NULL) { 991*7c478bd9Sstevel@tonic-gate mail(u->name, NOREAD, ERR_UNIXERR); 992*7c478bd9Sstevel@tonic-gate return; 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate while (fgets(line, CTLINESIZE, cf) != NULL) { 995*7c478bd9Sstevel@tonic-gate /* process a line of a crontab file */ 996*7c478bd9Sstevel@tonic-gate lineno++; 997*7c478bd9Sstevel@tonic-gate if (cte_istoomany()) 998*7c478bd9Sstevel@tonic-gate break; 999*7c478bd9Sstevel@tonic-gate cursor = 0; 1000*7c478bd9Sstevel@tonic-gate while (line[cursor] == ' ' || line[cursor] == '\t') 1001*7c478bd9Sstevel@tonic-gate cursor++; 1002*7c478bd9Sstevel@tonic-gate if (line[cursor] == '#' || line[cursor] == '\n') 1003*7c478bd9Sstevel@tonic-gate continue; 1004*7c478bd9Sstevel@tonic-gate e = xmalloc(sizeof (struct event)); 1005*7c478bd9Sstevel@tonic-gate e->etype = CRONEVENT; 1006*7c478bd9Sstevel@tonic-gate if (!(((e->of.ct.minute = next_field(0, 59)) != NULL) && 1007*7c478bd9Sstevel@tonic-gate ((e->of.ct.hour = next_field(0, 23)) != NULL) && 1008*7c478bd9Sstevel@tonic-gate ((e->of.ct.daymon = next_field(1, 31)) != NULL) && 1009*7c478bd9Sstevel@tonic-gate ((e->of.ct.month = next_field(1, 12)) != NULL) && 1010*7c478bd9Sstevel@tonic-gate ((e->of.ct.dayweek = next_field(0, 6)) != NULL))) { 1011*7c478bd9Sstevel@tonic-gate free(e); 1012*7c478bd9Sstevel@tonic-gate cte_add(lineno, line); 1013*7c478bd9Sstevel@tonic-gate continue; 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate while (line[cursor] == ' ' || line[cursor] == '\t') 1016*7c478bd9Sstevel@tonic-gate cursor++; 1017*7c478bd9Sstevel@tonic-gate if (line[cursor] == '\n' || line[cursor] == '\0') 1018*7c478bd9Sstevel@tonic-gate continue; 1019*7c478bd9Sstevel@tonic-gate /* get the command to execute */ 1020*7c478bd9Sstevel@tonic-gate start = cursor; 1021*7c478bd9Sstevel@tonic-gate again: 1022*7c478bd9Sstevel@tonic-gate while ((line[cursor] != '%') && 1023*7c478bd9Sstevel@tonic-gate (line[cursor] != '\n') && 1024*7c478bd9Sstevel@tonic-gate (line[cursor] != '\0') && 1025*7c478bd9Sstevel@tonic-gate (line[cursor] != '\\')) 1026*7c478bd9Sstevel@tonic-gate cursor++; 1027*7c478bd9Sstevel@tonic-gate if (line[cursor] == '\\') { 1028*7c478bd9Sstevel@tonic-gate cursor += 2; 1029*7c478bd9Sstevel@tonic-gate goto again; 1030*7c478bd9Sstevel@tonic-gate } 1031*7c478bd9Sstevel@tonic-gate e->cmd = xmalloc(cursor-start+1); 1032*7c478bd9Sstevel@tonic-gate (void) strncpy(e->cmd, line+start, cursor-start); 1033*7c478bd9Sstevel@tonic-gate e->cmd[cursor-start] = '\0'; 1034*7c478bd9Sstevel@tonic-gate /* see if there is any standard input */ 1035*7c478bd9Sstevel@tonic-gate if (line[cursor] == '%') { 1036*7c478bd9Sstevel@tonic-gate e->of.ct.input = xmalloc(strlen(line)-cursor+1); 1037*7c478bd9Sstevel@tonic-gate (void) strcpy(e->of.ct.input, line+cursor+1); 1038*7c478bd9Sstevel@tonic-gate for (i = 0; i < strlen(e->of.ct.input); i++) { 1039*7c478bd9Sstevel@tonic-gate if (e->of.ct.input[i] == '%') 1040*7c478bd9Sstevel@tonic-gate e->of.ct.input[i] = '\n'; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate } else { 1043*7c478bd9Sstevel@tonic-gate e->of.ct.input = NULL; 1044*7c478bd9Sstevel@tonic-gate } 1045*7c478bd9Sstevel@tonic-gate /* have the event point to it's owner */ 1046*7c478bd9Sstevel@tonic-gate e->u = u; 1047*7c478bd9Sstevel@tonic-gate /* insert this event at the front of this user's event list */ 1048*7c478bd9Sstevel@tonic-gate e->link = u->ctevents; 1049*7c478bd9Sstevel@tonic-gate u->ctevents = e; 1050*7c478bd9Sstevel@tonic-gate /* set the time for the first occurance of this event */ 1051*7c478bd9Sstevel@tonic-gate e->time = next_time(e, reftime); 1052*7c478bd9Sstevel@tonic-gate /* finally, add this event to the main event list */ 1053*7c478bd9Sstevel@tonic-gate el_add(e, e->time, u->ctid); 1054*7c478bd9Sstevel@tonic-gate cte_valid(); 1055*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1056*7c478bd9Sstevel@tonic-gate cftime(timebuf, "%C", &e->time); 1057*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "inserting cron event %s at %ld (%s)\n", 1058*7c478bd9Sstevel@tonic-gate e->cmd, e->time, timebuf); 1059*7c478bd9Sstevel@tonic-gate #endif 1060*7c478bd9Sstevel@tonic-gate } 1061*7c478bd9Sstevel@tonic-gate cte_sendmail(u->name); /* mail errors if any to user */ 1062*7c478bd9Sstevel@tonic-gate (void) fclose(cf); 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate 1065*7c478bd9Sstevel@tonic-gate /* 1066*7c478bd9Sstevel@tonic-gate * Below are the functions for handling of errors in crontabs. Concept is to 1067*7c478bd9Sstevel@tonic-gate * collect faulty lines and send one email at the end of the crontab 1068*7c478bd9Sstevel@tonic-gate * evaluation. If there are erroneous lines only ((cte_nvalid == 0), evaluation 1069*7c478bd9Sstevel@tonic-gate * of crontab is aborted. Otherwise reading of crontab is continued to the end 1070*7c478bd9Sstevel@tonic-gate * of the file but no further error logging appears. 1071*7c478bd9Sstevel@tonic-gate */ 1072*7c478bd9Sstevel@tonic-gate static void 1073*7c478bd9Sstevel@tonic-gate cte_init() 1074*7c478bd9Sstevel@tonic-gate { 1075*7c478bd9Sstevel@tonic-gate if (cte_text == NULL) 1076*7c478bd9Sstevel@tonic-gate cte_text = xmalloc(MAILBUFLEN); 1077*7c478bd9Sstevel@tonic-gate (void) strlcpy(cte_text, cte_intro, MAILBUFLEN); 1078*7c478bd9Sstevel@tonic-gate cte_lp = cte_text + sizeof (cte_intro) - 1; 1079*7c478bd9Sstevel@tonic-gate cte_free = MAILBINITFREE; 1080*7c478bd9Sstevel@tonic-gate cte_nvalid = 0; 1081*7c478bd9Sstevel@tonic-gate } 1082*7c478bd9Sstevel@tonic-gate 1083*7c478bd9Sstevel@tonic-gate static void 1084*7c478bd9Sstevel@tonic-gate cte_add(int lineno, char *ctline) 1085*7c478bd9Sstevel@tonic-gate { 1086*7c478bd9Sstevel@tonic-gate int len; 1087*7c478bd9Sstevel@tonic-gate char *p; 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate if (cte_free >= LINELIMIT) { 1090*7c478bd9Sstevel@tonic-gate (void) sprintf(cte_lp, "%4d: ", lineno); 1091*7c478bd9Sstevel@tonic-gate (void) strlcat(cte_lp, ctline, LINELIMIT - 1); 1092*7c478bd9Sstevel@tonic-gate len = strlen(cte_lp); 1093*7c478bd9Sstevel@tonic-gate if (cte_lp[len - 1] != '\n') { 1094*7c478bd9Sstevel@tonic-gate cte_lp[len++] = '\n'; 1095*7c478bd9Sstevel@tonic-gate cte_lp[len] = '\0'; 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate for (p = cte_lp; *p; p++) { 1098*7c478bd9Sstevel@tonic-gate if (isprint(*p) || *p == '\n' || *p == '\t') 1099*7c478bd9Sstevel@tonic-gate continue; 1100*7c478bd9Sstevel@tonic-gate *p = '.'; 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate cte_lp += len; 1103*7c478bd9Sstevel@tonic-gate cte_free -= len; 1104*7c478bd9Sstevel@tonic-gate if (cte_free < LINELIMIT) { 1105*7c478bd9Sstevel@tonic-gate size_t buflen = MAILBUFLEN - (cte_lp - cte_text); 1106*7c478bd9Sstevel@tonic-gate (void) strlcpy(cte_lp, cte_trail1, buflen); 1107*7c478bd9Sstevel@tonic-gate if (cte_nvalid == 0) 1108*7c478bd9Sstevel@tonic-gate (void) strlcat(cte_lp, cte_trail2, buflen); 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate static void 1114*7c478bd9Sstevel@tonic-gate cte_valid() 1115*7c478bd9Sstevel@tonic-gate { 1116*7c478bd9Sstevel@tonic-gate cte_nvalid++; 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate static int 1120*7c478bd9Sstevel@tonic-gate cte_istoomany() 1121*7c478bd9Sstevel@tonic-gate { 1122*7c478bd9Sstevel@tonic-gate /* 1123*7c478bd9Sstevel@tonic-gate * Return TRUE only if all lines are faulty. So evaluation of 1124*7c478bd9Sstevel@tonic-gate * a crontab is not aborted if at least one valid line was found. 1125*7c478bd9Sstevel@tonic-gate */ 1126*7c478bd9Sstevel@tonic-gate return (cte_nvalid == 0 && cte_free < LINELIMIT); 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate static void 1130*7c478bd9Sstevel@tonic-gate cte_sendmail(char *username) 1131*7c478bd9Sstevel@tonic-gate { 1132*7c478bd9Sstevel@tonic-gate if (cte_free < MAILBINITFREE) 1133*7c478bd9Sstevel@tonic-gate mail(username, cte_text, ERR_CRONTABENT); 1134*7c478bd9Sstevel@tonic-gate } 1135*7c478bd9Sstevel@tonic-gate 1136*7c478bd9Sstevel@tonic-gate /* 1137*7c478bd9Sstevel@tonic-gate * Send mail with error message to a user 1138*7c478bd9Sstevel@tonic-gate */ 1139*7c478bd9Sstevel@tonic-gate static void 1140*7c478bd9Sstevel@tonic-gate mail(char *usrname, char *mesg, int format) 1141*7c478bd9Sstevel@tonic-gate { 1142*7c478bd9Sstevel@tonic-gate /* mail mails a user a message. */ 1143*7c478bd9Sstevel@tonic-gate FILE *pipe; 1144*7c478bd9Sstevel@tonic-gate char *temp; 1145*7c478bd9Sstevel@tonic-gate struct passwd *ruser_ids; 1146*7c478bd9Sstevel@tonic-gate pid_t fork_val; 1147*7c478bd9Sstevel@tonic-gate int saveerrno = errno; 1148*7c478bd9Sstevel@tonic-gate struct utsname name; 1149*7c478bd9Sstevel@tonic-gate 1150*7c478bd9Sstevel@tonic-gate #ifdef TESTING 1151*7c478bd9Sstevel@tonic-gate return; 1152*7c478bd9Sstevel@tonic-gate #endif 1153*7c478bd9Sstevel@tonic-gate (void) uname(&name); 1154*7c478bd9Sstevel@tonic-gate if ((fork_val = fork()) == (pid_t)-1) { 1155*7c478bd9Sstevel@tonic-gate msg("cron cannot fork\n"); 1156*7c478bd9Sstevel@tonic-gate return; 1157*7c478bd9Sstevel@tonic-gate } 1158*7c478bd9Sstevel@tonic-gate if (fork_val == 0) { 1159*7c478bd9Sstevel@tonic-gate child_sigreset(); 1160*7c478bd9Sstevel@tonic-gate contract_clear_template(); 1161*7c478bd9Sstevel@tonic-gate if ((ruser_ids = getpwnam(usrname)) == NULL) 1162*7c478bd9Sstevel@tonic-gate exit(0); 1163*7c478bd9Sstevel@tonic-gate (void) setuid(ruser_ids->pw_uid); 1164*7c478bd9Sstevel@tonic-gate temp = xmalloc(strlen(MAIL)+strlen(usrname)+2); 1165*7c478bd9Sstevel@tonic-gate (void) sprintf(temp, "%s %s", MAIL, usrname); 1166*7c478bd9Sstevel@tonic-gate pipe = popen(temp, "w"); 1167*7c478bd9Sstevel@tonic-gate if (pipe != NULL) { 1168*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "To: %s\n", usrname); 1169*7c478bd9Sstevel@tonic-gate switch (format) { 1170*7c478bd9Sstevel@tonic-gate case ERR_CRONTABENT: 1171*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, CRONTABERR); 1172*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Your \"crontab\" on %s\n", 1173*7c478bd9Sstevel@tonic-gate name.nodename); 1174*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, mesg); 1175*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 1176*7c478bd9Sstevel@tonic-gate "\nEntries or crontab have been ignored\n"); 1177*7c478bd9Sstevel@tonic-gate break; 1178*7c478bd9Sstevel@tonic-gate case ERR_UNIXERR: 1179*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Subject: %s\n\n", mesg); 1180*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 1181*7c478bd9Sstevel@tonic-gate "The error on %s was \"%s\"\n", 1182*7c478bd9Sstevel@tonic-gate name.nodename, errmsg(saveerrno)); 1183*7c478bd9Sstevel@tonic-gate break; 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate case ERR_CANTEXECCRON: 1186*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 1187*7c478bd9Sstevel@tonic-gate "Subject: Couldn't run your \"cron\" job\n\n"); 1188*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 1189*7c478bd9Sstevel@tonic-gate "Your \"cron\" job on %s ", name.nodename); 1190*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "couldn't be run\n"); 1191*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "%s\n", mesg); 1192*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 1193*7c478bd9Sstevel@tonic-gate "The error was \"%s\"\n", errmsg(saveerrno)); 1194*7c478bd9Sstevel@tonic-gate break; 1195*7c478bd9Sstevel@tonic-gate 1196*7c478bd9Sstevel@tonic-gate case ERR_CANTEXECAT: 1197*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 1198*7c478bd9Sstevel@tonic-gate "Subject: Couldn't run your \"at\" job\n\n"); 1199*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Your \"at\" job on %s ", 1200*7c478bd9Sstevel@tonic-gate name.nodename); 1201*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "couldn't be run\n"); 1202*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "%s\n", mesg); 1203*7c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 1204*7c478bd9Sstevel@tonic-gate "The error was \"%s\"\n", errmsg(saveerrno)); 1205*7c478bd9Sstevel@tonic-gate break; 1206*7c478bd9Sstevel@tonic-gate 1207*7c478bd9Sstevel@tonic-gate default: 1208*7c478bd9Sstevel@tonic-gate break; 1209*7c478bd9Sstevel@tonic-gate } 1210*7c478bd9Sstevel@tonic-gate (void) pclose(pipe); 1211*7c478bd9Sstevel@tonic-gate } 1212*7c478bd9Sstevel@tonic-gate free(temp); 1213*7c478bd9Sstevel@tonic-gate exit(0); 1214*7c478bd9Sstevel@tonic-gate } 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate contract_abandon_latest(fork_val); 1217*7c478bd9Sstevel@tonic-gate 1218*7c478bd9Sstevel@tonic-gate if (cron_pid == getpid()) { 1219*7c478bd9Sstevel@tonic-gate miscpid_insert(fork_val); 1220*7c478bd9Sstevel@tonic-gate } 1221*7c478bd9Sstevel@tonic-gate } 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate static char * 1224*7c478bd9Sstevel@tonic-gate next_field(int lower, int upper) 1225*7c478bd9Sstevel@tonic-gate { 1226*7c478bd9Sstevel@tonic-gate /* 1227*7c478bd9Sstevel@tonic-gate * next_field returns a pointer to a string which holds the next 1228*7c478bd9Sstevel@tonic-gate * field of a line of a crontab file. 1229*7c478bd9Sstevel@tonic-gate * if (numbers in this field are out of range (lower..upper), 1230*7c478bd9Sstevel@tonic-gate * or there is a syntax error) then 1231*7c478bd9Sstevel@tonic-gate * NULL is returned, and a mail message is sent to the 1232*7c478bd9Sstevel@tonic-gate * user telling him which line the error was in. 1233*7c478bd9Sstevel@tonic-gate */ 1234*7c478bd9Sstevel@tonic-gate 1235*7c478bd9Sstevel@tonic-gate char *s; 1236*7c478bd9Sstevel@tonic-gate int num, num2, start; 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate while ((line[cursor] == ' ') || (line[cursor] == '\t')) 1239*7c478bd9Sstevel@tonic-gate cursor++; 1240*7c478bd9Sstevel@tonic-gate start = cursor; 1241*7c478bd9Sstevel@tonic-gate if (line[cursor] == '\0') { 1242*7c478bd9Sstevel@tonic-gate return (NULL); 1243*7c478bd9Sstevel@tonic-gate } 1244*7c478bd9Sstevel@tonic-gate if (line[cursor] == '*') { 1245*7c478bd9Sstevel@tonic-gate cursor++; 1246*7c478bd9Sstevel@tonic-gate if ((line[cursor] != ' ') && (line[cursor] != '\t')) 1247*7c478bd9Sstevel@tonic-gate return (NULL); 1248*7c478bd9Sstevel@tonic-gate s = xmalloc(2); 1249*7c478bd9Sstevel@tonic-gate (void) strcpy(s, "*"); 1250*7c478bd9Sstevel@tonic-gate return (s); 1251*7c478bd9Sstevel@tonic-gate } 1252*7c478bd9Sstevel@tonic-gate for (;;) { 1253*7c478bd9Sstevel@tonic-gate if (!isdigit(line[cursor])) 1254*7c478bd9Sstevel@tonic-gate return (NULL); 1255*7c478bd9Sstevel@tonic-gate num = 0; 1256*7c478bd9Sstevel@tonic-gate do { 1257*7c478bd9Sstevel@tonic-gate num = num*10 + (line[cursor]-'0'); 1258*7c478bd9Sstevel@tonic-gate } while (isdigit(line[++cursor])); 1259*7c478bd9Sstevel@tonic-gate if ((num < lower) || (num > upper)) 1260*7c478bd9Sstevel@tonic-gate return (NULL); 1261*7c478bd9Sstevel@tonic-gate if (line[cursor] == '-') { 1262*7c478bd9Sstevel@tonic-gate if (!isdigit(line[++cursor])) 1263*7c478bd9Sstevel@tonic-gate return (NULL); 1264*7c478bd9Sstevel@tonic-gate num2 = 0; 1265*7c478bd9Sstevel@tonic-gate do { 1266*7c478bd9Sstevel@tonic-gate num2 = num2*10 + (line[cursor]-'0'); 1267*7c478bd9Sstevel@tonic-gate } while (isdigit(line[++cursor])); 1268*7c478bd9Sstevel@tonic-gate if ((num2 < lower) || (num2 > upper)) 1269*7c478bd9Sstevel@tonic-gate return (NULL); 1270*7c478bd9Sstevel@tonic-gate } 1271*7c478bd9Sstevel@tonic-gate if ((line[cursor] == ' ') || (line[cursor] == '\t')) 1272*7c478bd9Sstevel@tonic-gate break; 1273*7c478bd9Sstevel@tonic-gate if (line[cursor] == '\0') 1274*7c478bd9Sstevel@tonic-gate return (NULL); 1275*7c478bd9Sstevel@tonic-gate if (line[cursor++] != ',') 1276*7c478bd9Sstevel@tonic-gate return (NULL); 1277*7c478bd9Sstevel@tonic-gate } 1278*7c478bd9Sstevel@tonic-gate s = xmalloc(cursor-start+1); 1279*7c478bd9Sstevel@tonic-gate (void) strncpy(s, line+start, cursor-start); 1280*7c478bd9Sstevel@tonic-gate s[cursor-start] = '\0'; 1281*7c478bd9Sstevel@tonic-gate return (s); 1282*7c478bd9Sstevel@tonic-gate } 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate #define tm_cmp(t1, t2) (\ 1285*7c478bd9Sstevel@tonic-gate (t1)->tm_year == (t2)->tm_year && \ 1286*7c478bd9Sstevel@tonic-gate (t1)->tm_mon == (t2)->tm_mon && \ 1287*7c478bd9Sstevel@tonic-gate (t1)->tm_mday == (t2)->tm_mday && \ 1288*7c478bd9Sstevel@tonic-gate (t1)->tm_hour == (t2)->tm_hour && \ 1289*7c478bd9Sstevel@tonic-gate (t1)->tm_min == (t2)->tm_min) 1290*7c478bd9Sstevel@tonic-gate 1291*7c478bd9Sstevel@tonic-gate #define tm_setup(tp, yr, mon, dy, hr, min, dst) \ 1292*7c478bd9Sstevel@tonic-gate (tp)->tm_year = yr; \ 1293*7c478bd9Sstevel@tonic-gate (tp)->tm_mon = mon; \ 1294*7c478bd9Sstevel@tonic-gate (tp)->tm_mday = dy; \ 1295*7c478bd9Sstevel@tonic-gate (tp)->tm_hour = hr; \ 1296*7c478bd9Sstevel@tonic-gate (tp)->tm_min = min; \ 1297*7c478bd9Sstevel@tonic-gate (tp)->tm_isdst = dst; \ 1298*7c478bd9Sstevel@tonic-gate (tp)->tm_sec = 0; \ 1299*7c478bd9Sstevel@tonic-gate (tp)->tm_wday = 0; \ 1300*7c478bd9Sstevel@tonic-gate (tp)->tm_yday = 0; 1301*7c478bd9Sstevel@tonic-gate 1302*7c478bd9Sstevel@tonic-gate /* 1303*7c478bd9Sstevel@tonic-gate * modification for bugid 1104537. the second argument to next_time is 1304*7c478bd9Sstevel@tonic-gate * now the value of time(2) to be used. if this is 0, then use the 1305*7c478bd9Sstevel@tonic-gate * current time. otherwise, the second argument is the time from which to 1306*7c478bd9Sstevel@tonic-gate * calculate things. this is useful to correct situations where you've 1307*7c478bd9Sstevel@tonic-gate * gone backwards in time (I.e. the system's internal clock is correcting 1308*7c478bd9Sstevel@tonic-gate * itself backwards). 1309*7c478bd9Sstevel@tonic-gate */ 1310*7c478bd9Sstevel@tonic-gate 1311*7c478bd9Sstevel@tonic-gate static time_t 1312*7c478bd9Sstevel@tonic-gate next_time(struct event *e, time_t tflag) 1313*7c478bd9Sstevel@tonic-gate { 1314*7c478bd9Sstevel@tonic-gate /* 1315*7c478bd9Sstevel@tonic-gate * returns the integer time for the next occurance of event e. 1316*7c478bd9Sstevel@tonic-gate * the following fields have ranges as indicated: 1317*7c478bd9Sstevel@tonic-gate * PRGM | min hour day of month mon day of week 1318*7c478bd9Sstevel@tonic-gate * ------|------------------------------------------------------- 1319*7c478bd9Sstevel@tonic-gate * cron | 0-59 0-23 1-31 1-12 0-6 (0=sunday) 1320*7c478bd9Sstevel@tonic-gate * time | 0-59 0-23 1-31 0-11 0-6 (0=sunday) 1321*7c478bd9Sstevel@tonic-gate * NOTE: this routine is hard to understand. 1322*7c478bd9Sstevel@tonic-gate */ 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate struct tm *tm, ref_tm, tmp, tmp1, tmp2; 1325*7c478bd9Sstevel@tonic-gate int tm_mon, tm_mday, tm_wday, wday, m, min, h, hr, carry, day, days, 1326*7c478bd9Sstevel@tonic-gate d1, day1, carry1, d2, day2, carry2, daysahead, mon, yr, db, wd, today; 1327*7c478bd9Sstevel@tonic-gate time_t t, ref_t, t1, t2, zone_start; 1328*7c478bd9Sstevel@tonic-gate int fallback; 1329*7c478bd9Sstevel@tonic-gate extern int days_btwn(int, int, int, int, int, int); 1330*7c478bd9Sstevel@tonic-gate 1331*7c478bd9Sstevel@tonic-gate if (tflag == 0) { 1332*7c478bd9Sstevel@tonic-gate t = time(NULL); /* original way of doing things */ 1333*7c478bd9Sstevel@tonic-gate } else { 1334*7c478bd9Sstevel@tonic-gate t = tflag; 1335*7c478bd9Sstevel@tonic-gate } 1336*7c478bd9Sstevel@tonic-gate 1337*7c478bd9Sstevel@tonic-gate tm = &ref_tm; /* use a local variable and call localtime_r() */ 1338*7c478bd9Sstevel@tonic-gate ref_t = t; /* keep a copy of the reference time */ 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate recalc: 1341*7c478bd9Sstevel@tonic-gate fallback = 0; 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t, tm); 1344*7c478bd9Sstevel@tonic-gate 1345*7c478bd9Sstevel@tonic-gate if (daylight) { 1346*7c478bd9Sstevel@tonic-gate tmp = *tm; 1347*7c478bd9Sstevel@tonic-gate tmp.tm_isdst = (tm->tm_isdst > 0 ? 0 : 1); 1348*7c478bd9Sstevel@tonic-gate t1 = xmktime(&tmp); 1349*7c478bd9Sstevel@tonic-gate /* 1350*7c478bd9Sstevel@tonic-gate * see if we will have timezone switch over, and clock will 1351*7c478bd9Sstevel@tonic-gate * fall back. zone_start will hold the time when it happens 1352*7c478bd9Sstevel@tonic-gate * (ie time of PST -> PDT switch over). 1353*7c478bd9Sstevel@tonic-gate */ 1354*7c478bd9Sstevel@tonic-gate if (tm->tm_isdst != tmp.tm_isdst && 1355*7c478bd9Sstevel@tonic-gate (t1 - t) == (timezone - altzone) && 1356*7c478bd9Sstevel@tonic-gate tm_cmp(tm, &tmp)) { 1357*7c478bd9Sstevel@tonic-gate zone_start = get_switching_time(tmp.tm_isdst, t); 1358*7c478bd9Sstevel@tonic-gate fallback = 1; 1359*7c478bd9Sstevel@tonic-gate } 1360*7c478bd9Sstevel@tonic-gate } 1361*7c478bd9Sstevel@tonic-gate 1362*7c478bd9Sstevel@tonic-gate tm_mon = next_ge(tm->tm_mon+1, e->of.ct.month) - 1; /* 0-11 */ 1363*7c478bd9Sstevel@tonic-gate tm_mday = next_ge(tm->tm_mday, e->of.ct.daymon); /* 1-31 */ 1364*7c478bd9Sstevel@tonic-gate tm_wday = next_ge(tm->tm_wday, e->of.ct.dayweek); /* 0-6 */ 1365*7c478bd9Sstevel@tonic-gate today = TRUE; 1366*7c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0 && tm->tm_wday != tm_wday) || 1367*7c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0 && tm->tm_mday != tm_mday) || 1368*7c478bd9Sstevel@tonic-gate (tm->tm_mday != tm_mday && tm->tm_wday != tm_wday) || 1369*7c478bd9Sstevel@tonic-gate (tm->tm_mon != tm_mon)) { 1370*7c478bd9Sstevel@tonic-gate today = FALSE; 1371*7c478bd9Sstevel@tonic-gate } 1372*7c478bd9Sstevel@tonic-gate m = tm->tm_min + (t == ref_t ? 1 : 0); 1373*7c478bd9Sstevel@tonic-gate if ((tm->tm_hour + 1) <= next_ge(tm->tm_hour, e->of.ct.hour)) { 1374*7c478bd9Sstevel@tonic-gate m = 0; 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate min = next_ge(m%60, e->of.ct.minute); 1377*7c478bd9Sstevel@tonic-gate carry = (min < m) ? 1 : 0; 1378*7c478bd9Sstevel@tonic-gate h = tm->tm_hour + carry; 1379*7c478bd9Sstevel@tonic-gate hr = next_ge(h%24, e->of.ct.hour); 1380*7c478bd9Sstevel@tonic-gate carry = (hr < h) ? 1 : 0; 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate if (carry == 0 && today) { 1383*7c478bd9Sstevel@tonic-gate /* this event must occur today */ 1384*7c478bd9Sstevel@tonic-gate tm_setup(&tmp, tm->tm_year, tm->tm_mon, tm->tm_mday, 1385*7c478bd9Sstevel@tonic-gate hr, min, tm->tm_isdst); 1386*7c478bd9Sstevel@tonic-gate tmp1 = tmp; 1387*7c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp1)) == (time_t)-1) { 1388*7c478bd9Sstevel@tonic-gate return (0); 1389*7c478bd9Sstevel@tonic-gate } 1390*7c478bd9Sstevel@tonic-gate if (daylight && tmp.tm_isdst != tmp1.tm_isdst) { 1391*7c478bd9Sstevel@tonic-gate /* In case we are falling back */ 1392*7c478bd9Sstevel@tonic-gate if (fallback) { 1393*7c478bd9Sstevel@tonic-gate /* we may need to run the job once more. */ 1394*7c478bd9Sstevel@tonic-gate t = zone_start; 1395*7c478bd9Sstevel@tonic-gate goto recalc; 1396*7c478bd9Sstevel@tonic-gate } 1397*7c478bd9Sstevel@tonic-gate 1398*7c478bd9Sstevel@tonic-gate /* 1399*7c478bd9Sstevel@tonic-gate * In case we are not in falling back period, 1400*7c478bd9Sstevel@tonic-gate * calculate the time assuming the DST. If the 1401*7c478bd9Sstevel@tonic-gate * date/time is not altered by mktime, it is the 1402*7c478bd9Sstevel@tonic-gate * time to execute the job. 1403*7c478bd9Sstevel@tonic-gate */ 1404*7c478bd9Sstevel@tonic-gate tmp2 = tmp; 1405*7c478bd9Sstevel@tonic-gate tmp2.tm_isdst = tmp1.tm_isdst; 1406*7c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp2)) == (time_t)-1) { 1407*7c478bd9Sstevel@tonic-gate return (0); 1408*7c478bd9Sstevel@tonic-gate } 1409*7c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst == tmp2.tm_isdst && 1410*7c478bd9Sstevel@tonic-gate tm_cmp(&tmp, &tmp2)) { 1411*7c478bd9Sstevel@tonic-gate /* 1412*7c478bd9Sstevel@tonic-gate * We got a valid time. 1413*7c478bd9Sstevel@tonic-gate */ 1414*7c478bd9Sstevel@tonic-gate return (t1); 1415*7c478bd9Sstevel@tonic-gate } else { 1416*7c478bd9Sstevel@tonic-gate /* 1417*7c478bd9Sstevel@tonic-gate * If the date does not match even if 1418*7c478bd9Sstevel@tonic-gate * we assume the alternate timezone, then 1419*7c478bd9Sstevel@tonic-gate * it must be the invalid time. eg 1420*7c478bd9Sstevel@tonic-gate * 2am while switching 1:59am to 3am. 1421*7c478bd9Sstevel@tonic-gate * t1 should point the time before the 1422*7c478bd9Sstevel@tonic-gate * switching over as we've calculate the 1423*7c478bd9Sstevel@tonic-gate * time with assuming alternate zone. 1424*7c478bd9Sstevel@tonic-gate */ 1425*7c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst != tmp2.tm_isdst) { 1426*7c478bd9Sstevel@tonic-gate t = get_switching_time(tmp1.tm_isdst, 1427*7c478bd9Sstevel@tonic-gate t1); 1428*7c478bd9Sstevel@tonic-gate } else { 1429*7c478bd9Sstevel@tonic-gate /* does this really happen? */ 1430*7c478bd9Sstevel@tonic-gate t = get_switching_time(tmp1.tm_isdst, 1431*7c478bd9Sstevel@tonic-gate t1 - abs(timezone - altzone)); 1432*7c478bd9Sstevel@tonic-gate } 1433*7c478bd9Sstevel@tonic-gate if (t == (time_t)-1) 1434*7c478bd9Sstevel@tonic-gate return (0); 1435*7c478bd9Sstevel@tonic-gate } 1436*7c478bd9Sstevel@tonic-gate goto recalc; 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp1)) { 1439*7c478bd9Sstevel@tonic-gate /* got valid time */ 1440*7c478bd9Sstevel@tonic-gate return (t1); 1441*7c478bd9Sstevel@tonic-gate } else { 1442*7c478bd9Sstevel@tonic-gate /* 1443*7c478bd9Sstevel@tonic-gate * This should never happen, but just in 1444*7c478bd9Sstevel@tonic-gate * case, we fall back to the old code. 1445*7c478bd9Sstevel@tonic-gate */ 1446*7c478bd9Sstevel@tonic-gate if (tm->tm_min > min) { 1447*7c478bd9Sstevel@tonic-gate t += (time_t)(hr-tm->tm_hour-1) * HOUR + 1448*7c478bd9Sstevel@tonic-gate (time_t)(60-tm->tm_min+min) * MINUTE; 1449*7c478bd9Sstevel@tonic-gate } else { 1450*7c478bd9Sstevel@tonic-gate t += (time_t)(hr-tm->tm_hour) * HOUR + 1451*7c478bd9Sstevel@tonic-gate (time_t)(min-tm->tm_min) * MINUTE; 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate t1 = t; 1454*7c478bd9Sstevel@tonic-gate t -= (time_t)tm->tm_sec; 1455*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp); 1456*7c478bd9Sstevel@tonic-gate if ((tm->tm_isdst == 0) && (tmp.tm_isdst > 0)) 1457*7c478bd9Sstevel@tonic-gate t -= (timezone - altzone); 1458*7c478bd9Sstevel@tonic-gate return ((t <= ref_t) ? t1 : t); 1459*7c478bd9Sstevel@tonic-gate } 1460*7c478bd9Sstevel@tonic-gate } 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate /* 1463*7c478bd9Sstevel@tonic-gate * Job won't run today, however if we have a switch over within 1464*7c478bd9Sstevel@tonic-gate * one hour and we will have one hour time drifting back in this 1465*7c478bd9Sstevel@tonic-gate * period, we may need to run the job one more time if the job was 1466*7c478bd9Sstevel@tonic-gate * set to run on this hour of clock. 1467*7c478bd9Sstevel@tonic-gate */ 1468*7c478bd9Sstevel@tonic-gate if (fallback) { 1469*7c478bd9Sstevel@tonic-gate t = zone_start; 1470*7c478bd9Sstevel@tonic-gate goto recalc; 1471*7c478bd9Sstevel@tonic-gate } 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate min = next_ge(0, e->of.ct.minute); 1474*7c478bd9Sstevel@tonic-gate hr = next_ge(0, e->of.ct.hour); 1475*7c478bd9Sstevel@tonic-gate 1476*7c478bd9Sstevel@tonic-gate /* 1477*7c478bd9Sstevel@tonic-gate * calculate the date of the next occurance of this event, which 1478*7c478bd9Sstevel@tonic-gate * will be on a different day than the current 1479*7c478bd9Sstevel@tonic-gate */ 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate /* check monthly day specification */ 1482*7c478bd9Sstevel@tonic-gate d1 = tm->tm_mday+1; 1483*7c478bd9Sstevel@tonic-gate day1 = next_ge((d1-1)%days_in_mon(tm->tm_mon, tm->tm_year)+1, 1484*7c478bd9Sstevel@tonic-gate e->of.ct.daymon); 1485*7c478bd9Sstevel@tonic-gate carry1 = (day1 < d1) ? 1 : 0; 1486*7c478bd9Sstevel@tonic-gate 1487*7c478bd9Sstevel@tonic-gate /* check weekly day specification */ 1488*7c478bd9Sstevel@tonic-gate d2 = tm->tm_wday+1; 1489*7c478bd9Sstevel@tonic-gate wday = next_ge(d2%7, e->of.ct.dayweek); 1490*7c478bd9Sstevel@tonic-gate if (wday < d2) 1491*7c478bd9Sstevel@tonic-gate daysahead = 7 - d2 + wday; 1492*7c478bd9Sstevel@tonic-gate else 1493*7c478bd9Sstevel@tonic-gate daysahead = wday - d2; 1494*7c478bd9Sstevel@tonic-gate day2 = (d1+daysahead-1)%days_in_mon(tm->tm_mon, tm->tm_year)+1; 1495*7c478bd9Sstevel@tonic-gate carry2 = (day2 < d1) ? 1 : 0; 1496*7c478bd9Sstevel@tonic-gate 1497*7c478bd9Sstevel@tonic-gate /* 1498*7c478bd9Sstevel@tonic-gate * based on their respective specifications, day1, and day2 give 1499*7c478bd9Sstevel@tonic-gate * the day of the month for the next occurance of this event. 1500*7c478bd9Sstevel@tonic-gate */ 1501*7c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0) && 1502*7c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") != 0)) { 1503*7c478bd9Sstevel@tonic-gate day1 = day2; 1504*7c478bd9Sstevel@tonic-gate carry1 = carry2; 1505*7c478bd9Sstevel@tonic-gate } 1506*7c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") != 0) && 1507*7c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0)) { 1508*7c478bd9Sstevel@tonic-gate day2 = day1; 1509*7c478bd9Sstevel@tonic-gate carry2 = carry1; 1510*7c478bd9Sstevel@tonic-gate } 1511*7c478bd9Sstevel@tonic-gate 1512*7c478bd9Sstevel@tonic-gate yr = tm->tm_year; 1513*7c478bd9Sstevel@tonic-gate if ((carry1 && carry2) || (tm->tm_mon != tm_mon)) { 1514*7c478bd9Sstevel@tonic-gate /* event does not occur in this month */ 1515*7c478bd9Sstevel@tonic-gate m = tm->tm_mon+1; 1516*7c478bd9Sstevel@tonic-gate mon = next_ge(m%12+1, e->of.ct.month) - 1; /* 0..11 */ 1517*7c478bd9Sstevel@tonic-gate carry = (mon < m) ? 1 : 0; 1518*7c478bd9Sstevel@tonic-gate yr += carry; 1519*7c478bd9Sstevel@tonic-gate /* recompute day1 and day2 */ 1520*7c478bd9Sstevel@tonic-gate day1 = next_ge(1, e->of.ct.daymon); 1521*7c478bd9Sstevel@tonic-gate db = days_btwn(tm->tm_mon, tm->tm_mday, tm->tm_year, mon, 1522*7c478bd9Sstevel@tonic-gate 1, yr) + 1; 1523*7c478bd9Sstevel@tonic-gate wd = (tm->tm_wday+db)%7; 1524*7c478bd9Sstevel@tonic-gate /* wd is the day of the week of the first of month mon */ 1525*7c478bd9Sstevel@tonic-gate wday = next_ge(wd, e->of.ct.dayweek); 1526*7c478bd9Sstevel@tonic-gate if (wday < wd) 1527*7c478bd9Sstevel@tonic-gate day2 = 1 + 7 - wd + wday; 1528*7c478bd9Sstevel@tonic-gate else 1529*7c478bd9Sstevel@tonic-gate day2 = 1 + wday - wd; 1530*7c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") != 0) && 1531*7c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0)) 1532*7c478bd9Sstevel@tonic-gate day2 = day1; 1533*7c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0) && 1534*7c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") != 0)) 1535*7c478bd9Sstevel@tonic-gate day1 = day2; 1536*7c478bd9Sstevel@tonic-gate day = (day1 < day2) ? day1 : day2; 1537*7c478bd9Sstevel@tonic-gate } else { /* event occurs in this month */ 1538*7c478bd9Sstevel@tonic-gate mon = tm->tm_mon; 1539*7c478bd9Sstevel@tonic-gate if (!carry1 && !carry2) 1540*7c478bd9Sstevel@tonic-gate day = (day1 < day2) ? day1 : day2; 1541*7c478bd9Sstevel@tonic-gate else if (!carry1) 1542*7c478bd9Sstevel@tonic-gate day = day1; 1543*7c478bd9Sstevel@tonic-gate else 1544*7c478bd9Sstevel@tonic-gate day = day2; 1545*7c478bd9Sstevel@tonic-gate } 1546*7c478bd9Sstevel@tonic-gate 1547*7c478bd9Sstevel@tonic-gate /* 1548*7c478bd9Sstevel@tonic-gate * now that we have the min, hr, day, mon, yr of the next event, 1549*7c478bd9Sstevel@tonic-gate * figure out what time that turns out to be. 1550*7c478bd9Sstevel@tonic-gate */ 1551*7c478bd9Sstevel@tonic-gate tm_setup(&tmp, yr, mon, day, hr, min, -1); 1552*7c478bd9Sstevel@tonic-gate tmp2 = tmp; 1553*7c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp2)) == (time_t)-1) { 1554*7c478bd9Sstevel@tonic-gate return (0); 1555*7c478bd9Sstevel@tonic-gate } 1556*7c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp2)) { 1557*7c478bd9Sstevel@tonic-gate /* 1558*7c478bd9Sstevel@tonic-gate * mktime returns clock for the current time zone. If the 1559*7c478bd9Sstevel@tonic-gate * target date was in fallback period, it needs to be adjusted 1560*7c478bd9Sstevel@tonic-gate * to the time comes first. 1561*7c478bd9Sstevel@tonic-gate * Suppose, we are at Jan and scheduling job at 1:30am10/26/03. 1562*7c478bd9Sstevel@tonic-gate * mktime returns the time in PST, but 1:30am in PDT comes 1563*7c478bd9Sstevel@tonic-gate * first. So reverse the tm_isdst, and see if we have such 1564*7c478bd9Sstevel@tonic-gate * time/date. 1565*7c478bd9Sstevel@tonic-gate */ 1566*7c478bd9Sstevel@tonic-gate if (daylight) { 1567*7c478bd9Sstevel@tonic-gate int dst = tmp2.tm_isdst; 1568*7c478bd9Sstevel@tonic-gate 1569*7c478bd9Sstevel@tonic-gate tmp2 = tmp; 1570*7c478bd9Sstevel@tonic-gate tmp2.tm_isdst = (dst > 0 ? 0 : 1); 1571*7c478bd9Sstevel@tonic-gate if ((t2 = xmktime(&tmp2)) == (time_t)-1) { 1572*7c478bd9Sstevel@tonic-gate return (0); 1573*7c478bd9Sstevel@tonic-gate } 1574*7c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp2)) { 1575*7c478bd9Sstevel@tonic-gate /* 1576*7c478bd9Sstevel@tonic-gate * same time/date found in the opposite zone. 1577*7c478bd9Sstevel@tonic-gate * check the clock to see which comes early. 1578*7c478bd9Sstevel@tonic-gate */ 1579*7c478bd9Sstevel@tonic-gate if (t2 > ref_t && t2 < t1) { 1580*7c478bd9Sstevel@tonic-gate t1 = t2; 1581*7c478bd9Sstevel@tonic-gate } 1582*7c478bd9Sstevel@tonic-gate } 1583*7c478bd9Sstevel@tonic-gate } 1584*7c478bd9Sstevel@tonic-gate return (t1); 1585*7c478bd9Sstevel@tonic-gate } else { 1586*7c478bd9Sstevel@tonic-gate /* 1587*7c478bd9Sstevel@tonic-gate * mktime has set different time/date for the given date. 1588*7c478bd9Sstevel@tonic-gate * This means that the next job is scheduled to be run on the 1589*7c478bd9Sstevel@tonic-gate * invalid time. There are three possible invalid date/time. 1590*7c478bd9Sstevel@tonic-gate * 1. Non existing day of the month. such as April 31th. 1591*7c478bd9Sstevel@tonic-gate * 2. Feb 29th in the non-leap year. 1592*7c478bd9Sstevel@tonic-gate * 3. Time gap during the DST switch over. 1593*7c478bd9Sstevel@tonic-gate */ 1594*7c478bd9Sstevel@tonic-gate d1 = days_in_mon(mon, yr); 1595*7c478bd9Sstevel@tonic-gate if ((mon != 1 && day > d1) || (mon == 1 && day > 29)) { 1596*7c478bd9Sstevel@tonic-gate /* 1597*7c478bd9Sstevel@tonic-gate * see if we have got a specific date which 1598*7c478bd9Sstevel@tonic-gate * is invalid. 1599*7c478bd9Sstevel@tonic-gate */ 1600*7c478bd9Sstevel@tonic-gate if (strcmp(e->of.ct.dayweek, "*") == 0 && 1601*7c478bd9Sstevel@tonic-gate mon == (next_ge((mon+1)%12+1, e->of.ct.month)-1) && 1602*7c478bd9Sstevel@tonic-gate day <= next_ge(1, e->of.ct.daymon)) { 1603*7c478bd9Sstevel@tonic-gate /* job never run */ 1604*7c478bd9Sstevel@tonic-gate return (0); 1605*7c478bd9Sstevel@tonic-gate } 1606*7c478bd9Sstevel@tonic-gate /* 1607*7c478bd9Sstevel@tonic-gate * Since the day has gone invalid, we need to go to 1608*7c478bd9Sstevel@tonic-gate * next month, and recalcuate the first occurrence. 1609*7c478bd9Sstevel@tonic-gate * eg the cron tab such as: 1610*7c478bd9Sstevel@tonic-gate * 0 0 1,15,31 1,2,3,4,5 * /usr/bin.... 1611*7c478bd9Sstevel@tonic-gate * 2/31 is invalid, so the next job is 3/1. 1612*7c478bd9Sstevel@tonic-gate */ 1613*7c478bd9Sstevel@tonic-gate tmp2 = tmp; 1614*7c478bd9Sstevel@tonic-gate tmp2.tm_min = 0; 1615*7c478bd9Sstevel@tonic-gate tmp2.tm_hour = 0; 1616*7c478bd9Sstevel@tonic-gate tmp2.tm_mday = 1; /* 1st day of the month */ 1617*7c478bd9Sstevel@tonic-gate if (mon == 11) { 1618*7c478bd9Sstevel@tonic-gate tmp2.tm_mon = 0; 1619*7c478bd9Sstevel@tonic-gate tmp2.tm_year = yr + 1; 1620*7c478bd9Sstevel@tonic-gate } else { 1621*7c478bd9Sstevel@tonic-gate tmp2.tm_mon = mon + 1; 1622*7c478bd9Sstevel@tonic-gate } 1623*7c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp2)) == (time_t)-1) { 1624*7c478bd9Sstevel@tonic-gate return (0); 1625*7c478bd9Sstevel@tonic-gate } 1626*7c478bd9Sstevel@tonic-gate } else if (mon == 1 && day > d1) { 1627*7c478bd9Sstevel@tonic-gate /* 1628*7c478bd9Sstevel@tonic-gate * ie 29th in the non-leap year. Forwarding the 1629*7c478bd9Sstevel@tonic-gate * clock to Feb 29th 00:00 (March 1st), and recalculate 1630*7c478bd9Sstevel@tonic-gate * the next time. 1631*7c478bd9Sstevel@tonic-gate */ 1632*7c478bd9Sstevel@tonic-gate tmp2 = tmp; 1633*7c478bd9Sstevel@tonic-gate tmp2.tm_min = 0; 1634*7c478bd9Sstevel@tonic-gate tmp2.tm_hour = 0; 1635*7c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp2)) == (time_t)-1) { 1636*7c478bd9Sstevel@tonic-gate return (0); 1637*7c478bd9Sstevel@tonic-gate } 1638*7c478bd9Sstevel@tonic-gate } else if (daylight) { 1639*7c478bd9Sstevel@tonic-gate /* 1640*7c478bd9Sstevel@tonic-gate * Non existing time, eg 2am PST during summer time 1641*7c478bd9Sstevel@tonic-gate * switch. 1642*7c478bd9Sstevel@tonic-gate * We need to get the correct isdst which we are 1643*7c478bd9Sstevel@tonic-gate * swithing to, by adding time difference to make sure 1644*7c478bd9Sstevel@tonic-gate * that t2 is in the zone being switched. 1645*7c478bd9Sstevel@tonic-gate */ 1646*7c478bd9Sstevel@tonic-gate t2 = t1; 1647*7c478bd9Sstevel@tonic-gate t2 += abs(timezone - altzone); 1648*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t2, &tmp2); 1649*7c478bd9Sstevel@tonic-gate zone_start = get_switching_time(tmp2.tm_isdst, 1650*7c478bd9Sstevel@tonic-gate t1 - abs(timezone - altzone)); 1651*7c478bd9Sstevel@tonic-gate if (zone_start == (time_t)-1) { 1652*7c478bd9Sstevel@tonic-gate return (0); 1653*7c478bd9Sstevel@tonic-gate } 1654*7c478bd9Sstevel@tonic-gate t = zone_start; 1655*7c478bd9Sstevel@tonic-gate } else { 1656*7c478bd9Sstevel@tonic-gate /* 1657*7c478bd9Sstevel@tonic-gate * This should never happen, but fall back to the 1658*7c478bd9Sstevel@tonic-gate * old code. 1659*7c478bd9Sstevel@tonic-gate */ 1660*7c478bd9Sstevel@tonic-gate days = days_btwn(tm->tm_mon, 1661*7c478bd9Sstevel@tonic-gate tm->tm_mday, tm->tm_year, mon, day, yr); 1662*7c478bd9Sstevel@tonic-gate t += (time_t)(23-tm->tm_hour)*HOUR 1663*7c478bd9Sstevel@tonic-gate + (time_t)(60-tm->tm_min)*MINUTE 1664*7c478bd9Sstevel@tonic-gate + (time_t)hr*HOUR + (time_t)min*MINUTE 1665*7c478bd9Sstevel@tonic-gate + (time_t)days*DAY; 1666*7c478bd9Sstevel@tonic-gate t1 = t; 1667*7c478bd9Sstevel@tonic-gate t -= (time_t)tm->tm_sec; 1668*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp); 1669*7c478bd9Sstevel@tonic-gate if ((tm->tm_isdst == 0) && (tmp.tm_isdst > 0)) 1670*7c478bd9Sstevel@tonic-gate t -= (timezone - altzone); 1671*7c478bd9Sstevel@tonic-gate return (t <= ref_t ? t1 : t); 1672*7c478bd9Sstevel@tonic-gate } 1673*7c478bd9Sstevel@tonic-gate goto recalc; 1674*7c478bd9Sstevel@tonic-gate } 1675*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1676*7c478bd9Sstevel@tonic-gate } 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate /* 1679*7c478bd9Sstevel@tonic-gate * This returns TOD in time_t that zone switch will happen, and this 1680*7c478bd9Sstevel@tonic-gate * will be called when clock fallback is about to happen. 1681*7c478bd9Sstevel@tonic-gate * (ie 30minutes before the time of PST -> PDT switch. 2:00 AM PST 1682*7c478bd9Sstevel@tonic-gate * will fall back to 1:00 PDT. So this function will be called only 1683*7c478bd9Sstevel@tonic-gate * for the time between 1:00 AM PST and 2:00 PST(1:00 PST)). 1684*7c478bd9Sstevel@tonic-gate * First goes through the common time differences to see if zone 1685*7c478bd9Sstevel@tonic-gate * switch happens at those minutes later. If not, check every minutes 1686*7c478bd9Sstevel@tonic-gate * until 6 hours ahead see if it happens(We might have 45minutes 1687*7c478bd9Sstevel@tonic-gate * fallback). 1688*7c478bd9Sstevel@tonic-gate */ 1689*7c478bd9Sstevel@tonic-gate static time_t 1690*7c478bd9Sstevel@tonic-gate get_switching_time(int to_dst, time_t t_ref) 1691*7c478bd9Sstevel@tonic-gate { 1692*7c478bd9Sstevel@tonic-gate time_t t, t1; 1693*7c478bd9Sstevel@tonic-gate struct tm tmp, tmp1; 1694*7c478bd9Sstevel@tonic-gate int hints[] = { 60, 120, 30, 90, 0}; /* minutes */ 1695*7c478bd9Sstevel@tonic-gate int i; 1696*7c478bd9Sstevel@tonic-gate 1697*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t_ref, &tmp); 1698*7c478bd9Sstevel@tonic-gate tmp1 = tmp; 1699*7c478bd9Sstevel@tonic-gate tmp1.tm_sec = 0; 1700*7c478bd9Sstevel@tonic-gate tmp1.tm_min = 0; 1701*7c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp1)) == (time_t)-1) 1702*7c478bd9Sstevel@tonic-gate return ((time_t)-1); 1703*7c478bd9Sstevel@tonic-gate 1704*7c478bd9Sstevel@tonic-gate /* fast path */ 1705*7c478bd9Sstevel@tonic-gate for (i = 0; hints[i] != 0; i++) { 1706*7c478bd9Sstevel@tonic-gate t1 = t + hints[i] * 60; 1707*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t1, &tmp1); 1708*7c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst == to_dst) { 1709*7c478bd9Sstevel@tonic-gate t1--; 1710*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t1, &tmp1); 1711*7c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst != to_dst) { 1712*7c478bd9Sstevel@tonic-gate return (t1 + 1); 1713*7c478bd9Sstevel@tonic-gate } 1714*7c478bd9Sstevel@tonic-gate } 1715*7c478bd9Sstevel@tonic-gate } 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate /* ugly, but don't know other than this. */ 1718*7c478bd9Sstevel@tonic-gate tmp1 = tmp; 1719*7c478bd9Sstevel@tonic-gate tmp1.tm_sec = 0; 1720*7c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp1)) == (time_t)-1) 1721*7c478bd9Sstevel@tonic-gate return ((time_t)-1); 1722*7c478bd9Sstevel@tonic-gate while (t < (t_ref + 6*60*60)) { /* 6 hours should be enough */ 1723*7c478bd9Sstevel@tonic-gate t += 60; /* at least one minute, I assume */ 1724*7c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp); 1725*7c478bd9Sstevel@tonic-gate if (tmp.tm_isdst == to_dst) 1726*7c478bd9Sstevel@tonic-gate return (t); 1727*7c478bd9Sstevel@tonic-gate } 1728*7c478bd9Sstevel@tonic-gate return ((time_t)-1); 1729*7c478bd9Sstevel@tonic-gate } 1730*7c478bd9Sstevel@tonic-gate 1731*7c478bd9Sstevel@tonic-gate static time_t 1732*7c478bd9Sstevel@tonic-gate xmktime(struct tm *tmp) 1733*7c478bd9Sstevel@tonic-gate { 1734*7c478bd9Sstevel@tonic-gate time_t ret; 1735*7c478bd9Sstevel@tonic-gate 1736*7c478bd9Sstevel@tonic-gate if ((ret = mktime(tmp)) == (time_t)-1) { 1737*7c478bd9Sstevel@tonic-gate if (errno == EOVERFLOW) { 1738*7c478bd9Sstevel@tonic-gate return ((time_t)-1); 1739*7c478bd9Sstevel@tonic-gate } 1740*7c478bd9Sstevel@tonic-gate crabort("internal error: mktime failed", 1741*7c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG); 1742*7c478bd9Sstevel@tonic-gate } 1743*7c478bd9Sstevel@tonic-gate return (ret); 1744*7c478bd9Sstevel@tonic-gate } 1745*7c478bd9Sstevel@tonic-gate 1746*7c478bd9Sstevel@tonic-gate #define DUMMY 100 1747*7c478bd9Sstevel@tonic-gate 1748*7c478bd9Sstevel@tonic-gate static int 1749*7c478bd9Sstevel@tonic-gate next_ge(int current, char *list) 1750*7c478bd9Sstevel@tonic-gate { 1751*7c478bd9Sstevel@tonic-gate /* 1752*7c478bd9Sstevel@tonic-gate * list is a character field as in a crontab file; 1753*7c478bd9Sstevel@tonic-gate * for example: "40, 20, 50-10" 1754*7c478bd9Sstevel@tonic-gate * next_ge returns the next number in the list that is 1755*7c478bd9Sstevel@tonic-gate * greater than or equal to current. if no numbers of list 1756*7c478bd9Sstevel@tonic-gate * are >= current, the smallest element of list is returned. 1757*7c478bd9Sstevel@tonic-gate * NOTE: current must be in the appropriate range. 1758*7c478bd9Sstevel@tonic-gate */ 1759*7c478bd9Sstevel@tonic-gate 1760*7c478bd9Sstevel@tonic-gate char *ptr; 1761*7c478bd9Sstevel@tonic-gate int n, n2, min, min_gt; 1762*7c478bd9Sstevel@tonic-gate 1763*7c478bd9Sstevel@tonic-gate if (strcmp(list, "*") == 0) 1764*7c478bd9Sstevel@tonic-gate return (current); 1765*7c478bd9Sstevel@tonic-gate ptr = list; 1766*7c478bd9Sstevel@tonic-gate min = DUMMY; 1767*7c478bd9Sstevel@tonic-gate min_gt = DUMMY; 1768*7c478bd9Sstevel@tonic-gate for (;;) { 1769*7c478bd9Sstevel@tonic-gate if ((n = (int)num(&ptr)) == current) 1770*7c478bd9Sstevel@tonic-gate return (current); 1771*7c478bd9Sstevel@tonic-gate if (n < min) 1772*7c478bd9Sstevel@tonic-gate min = n; 1773*7c478bd9Sstevel@tonic-gate if ((n > current) && (n < min_gt)) 1774*7c478bd9Sstevel@tonic-gate min_gt = n; 1775*7c478bd9Sstevel@tonic-gate if (*ptr == '-') { 1776*7c478bd9Sstevel@tonic-gate ptr++; 1777*7c478bd9Sstevel@tonic-gate if ((n2 = (int)num(&ptr)) > n) { 1778*7c478bd9Sstevel@tonic-gate if ((current > n) && (current <= n2)) 1779*7c478bd9Sstevel@tonic-gate return (current); 1780*7c478bd9Sstevel@tonic-gate } else { /* range that wraps around */ 1781*7c478bd9Sstevel@tonic-gate if (current > n) 1782*7c478bd9Sstevel@tonic-gate return (current); 1783*7c478bd9Sstevel@tonic-gate if (current <= n2) 1784*7c478bd9Sstevel@tonic-gate return (current); 1785*7c478bd9Sstevel@tonic-gate } 1786*7c478bd9Sstevel@tonic-gate } 1787*7c478bd9Sstevel@tonic-gate if (*ptr == '\0') 1788*7c478bd9Sstevel@tonic-gate break; 1789*7c478bd9Sstevel@tonic-gate ptr += 1; 1790*7c478bd9Sstevel@tonic-gate } 1791*7c478bd9Sstevel@tonic-gate if (min_gt != DUMMY) 1792*7c478bd9Sstevel@tonic-gate return (min_gt); 1793*7c478bd9Sstevel@tonic-gate else 1794*7c478bd9Sstevel@tonic-gate return (min); 1795*7c478bd9Sstevel@tonic-gate } 1796*7c478bd9Sstevel@tonic-gate 1797*7c478bd9Sstevel@tonic-gate static void 1798*7c478bd9Sstevel@tonic-gate free_if_unused(struct usr *u) 1799*7c478bd9Sstevel@tonic-gate { 1800*7c478bd9Sstevel@tonic-gate struct usr *cur, *prev; 1801*7c478bd9Sstevel@tonic-gate /* 1802*7c478bd9Sstevel@tonic-gate * To make sure a usr structure is idle we must check that 1803*7c478bd9Sstevel@tonic-gate * there are no at jobs queued for the user; the user does 1804*7c478bd9Sstevel@tonic-gate * not have a crontab, and also that there are no running at 1805*7c478bd9Sstevel@tonic-gate * or cron jobs (since the runinfo structure also has a 1806*7c478bd9Sstevel@tonic-gate * pointer to the usr structure). 1807*7c478bd9Sstevel@tonic-gate */ 1808*7c478bd9Sstevel@tonic-gate if (!u->ctexists && u->atevents == NULL && 1809*7c478bd9Sstevel@tonic-gate u->cruncnt == 0 && u->aruncnt == 0) { 1810*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1811*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s removed from usr list\n", u->name); 1812*7c478bd9Sstevel@tonic-gate #endif 1813*7c478bd9Sstevel@tonic-gate for (cur = uhead, prev = NULL; 1814*7c478bd9Sstevel@tonic-gate cur != u; 1815*7c478bd9Sstevel@tonic-gate prev = cur, cur = cur->nextusr) { 1816*7c478bd9Sstevel@tonic-gate if (cur == NULL) { 1817*7c478bd9Sstevel@tonic-gate return; 1818*7c478bd9Sstevel@tonic-gate } 1819*7c478bd9Sstevel@tonic-gate } 1820*7c478bd9Sstevel@tonic-gate 1821*7c478bd9Sstevel@tonic-gate if (prev == NULL) 1822*7c478bd9Sstevel@tonic-gate uhead = u->nextusr; 1823*7c478bd9Sstevel@tonic-gate else 1824*7c478bd9Sstevel@tonic-gate prev->nextusr = u->nextusr; 1825*7c478bd9Sstevel@tonic-gate free(u->name); 1826*7c478bd9Sstevel@tonic-gate free(u->home); 1827*7c478bd9Sstevel@tonic-gate free(u); 1828*7c478bd9Sstevel@tonic-gate } 1829*7c478bd9Sstevel@tonic-gate } 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate static void 1832*7c478bd9Sstevel@tonic-gate del_atjob(char *name, char *usrname) 1833*7c478bd9Sstevel@tonic-gate { 1834*7c478bd9Sstevel@tonic-gate 1835*7c478bd9Sstevel@tonic-gate struct event *e, *eprev; 1836*7c478bd9Sstevel@tonic-gate struct usr *u; 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate if ((u = find_usr(usrname)) == NULL) 1839*7c478bd9Sstevel@tonic-gate return; 1840*7c478bd9Sstevel@tonic-gate e = u->atevents; 1841*7c478bd9Sstevel@tonic-gate eprev = NULL; 1842*7c478bd9Sstevel@tonic-gate while (e != NULL) { 1843*7c478bd9Sstevel@tonic-gate if (strcmp(name, e->cmd) == 0) { 1844*7c478bd9Sstevel@tonic-gate if (next_event == e) 1845*7c478bd9Sstevel@tonic-gate next_event = NULL; 1846*7c478bd9Sstevel@tonic-gate if (eprev == NULL) 1847*7c478bd9Sstevel@tonic-gate u->atevents = e->link; 1848*7c478bd9Sstevel@tonic-gate else 1849*7c478bd9Sstevel@tonic-gate eprev->link = e->link; 1850*7c478bd9Sstevel@tonic-gate el_remove(e->of.at.eventid, 1); 1851*7c478bd9Sstevel@tonic-gate free(e->cmd); 1852*7c478bd9Sstevel@tonic-gate free(e); 1853*7c478bd9Sstevel@tonic-gate break; 1854*7c478bd9Sstevel@tonic-gate } else { 1855*7c478bd9Sstevel@tonic-gate eprev = e; 1856*7c478bd9Sstevel@tonic-gate e = e->link; 1857*7c478bd9Sstevel@tonic-gate } 1858*7c478bd9Sstevel@tonic-gate } 1859*7c478bd9Sstevel@tonic-gate 1860*7c478bd9Sstevel@tonic-gate free_if_unused(u); 1861*7c478bd9Sstevel@tonic-gate } 1862*7c478bd9Sstevel@tonic-gate 1863*7c478bd9Sstevel@tonic-gate static void 1864*7c478bd9Sstevel@tonic-gate del_ctab(char *name) 1865*7c478bd9Sstevel@tonic-gate { 1866*7c478bd9Sstevel@tonic-gate 1867*7c478bd9Sstevel@tonic-gate struct usr *u; 1868*7c478bd9Sstevel@tonic-gate 1869*7c478bd9Sstevel@tonic-gate if ((u = find_usr(name)) == NULL) 1870*7c478bd9Sstevel@tonic-gate return; 1871*7c478bd9Sstevel@tonic-gate rm_ctevents(u); 1872*7c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0); 1873*7c478bd9Sstevel@tonic-gate u->ctid = 0; 1874*7c478bd9Sstevel@tonic-gate u->ctexists = 0; 1875*7c478bd9Sstevel@tonic-gate 1876*7c478bd9Sstevel@tonic-gate free_if_unused(u); 1877*7c478bd9Sstevel@tonic-gate } 1878*7c478bd9Sstevel@tonic-gate 1879*7c478bd9Sstevel@tonic-gate static void 1880*7c478bd9Sstevel@tonic-gate rm_ctevents(struct usr *u) 1881*7c478bd9Sstevel@tonic-gate { 1882*7c478bd9Sstevel@tonic-gate struct event *e2, *e3; 1883*7c478bd9Sstevel@tonic-gate 1884*7c478bd9Sstevel@tonic-gate /* 1885*7c478bd9Sstevel@tonic-gate * see if the next event (to be run by cron) is a cronevent 1886*7c478bd9Sstevel@tonic-gate * owned by this user. 1887*7c478bd9Sstevel@tonic-gate */ 1888*7c478bd9Sstevel@tonic-gate 1889*7c478bd9Sstevel@tonic-gate if ((next_event != NULL) && 1890*7c478bd9Sstevel@tonic-gate (next_event->etype == CRONEVENT) && 1891*7c478bd9Sstevel@tonic-gate (next_event->u == u)) { 1892*7c478bd9Sstevel@tonic-gate next_event = NULL; 1893*7c478bd9Sstevel@tonic-gate } 1894*7c478bd9Sstevel@tonic-gate e2 = u->ctevents; 1895*7c478bd9Sstevel@tonic-gate while (e2 != NULL) { 1896*7c478bd9Sstevel@tonic-gate free(e2->cmd); 1897*7c478bd9Sstevel@tonic-gate free(e2->of.ct.minute); 1898*7c478bd9Sstevel@tonic-gate free(e2->of.ct.hour); 1899*7c478bd9Sstevel@tonic-gate free(e2->of.ct.daymon); 1900*7c478bd9Sstevel@tonic-gate free(e2->of.ct.month); 1901*7c478bd9Sstevel@tonic-gate free(e2->of.ct.dayweek); 1902*7c478bd9Sstevel@tonic-gate if (e2->of.ct.input != NULL) 1903*7c478bd9Sstevel@tonic-gate free(e2->of.ct.input); 1904*7c478bd9Sstevel@tonic-gate e3 = e2->link; 1905*7c478bd9Sstevel@tonic-gate free(e2); 1906*7c478bd9Sstevel@tonic-gate e2 = e3; 1907*7c478bd9Sstevel@tonic-gate } 1908*7c478bd9Sstevel@tonic-gate u->ctevents = NULL; 1909*7c478bd9Sstevel@tonic-gate } 1910*7c478bd9Sstevel@tonic-gate 1911*7c478bd9Sstevel@tonic-gate 1912*7c478bd9Sstevel@tonic-gate static struct usr * 1913*7c478bd9Sstevel@tonic-gate find_usr(char *uname) 1914*7c478bd9Sstevel@tonic-gate { 1915*7c478bd9Sstevel@tonic-gate struct usr *u; 1916*7c478bd9Sstevel@tonic-gate 1917*7c478bd9Sstevel@tonic-gate u = uhead; 1918*7c478bd9Sstevel@tonic-gate while (u != NULL) { 1919*7c478bd9Sstevel@tonic-gate if (strcmp(u->name, uname) == 0) 1920*7c478bd9Sstevel@tonic-gate return (u); 1921*7c478bd9Sstevel@tonic-gate u = u->nextusr; 1922*7c478bd9Sstevel@tonic-gate } 1923*7c478bd9Sstevel@tonic-gate return (NULL); 1924*7c478bd9Sstevel@tonic-gate } 1925*7c478bd9Sstevel@tonic-gate 1926*7c478bd9Sstevel@tonic-gate /* 1927*7c478bd9Sstevel@tonic-gate * Execute cron command or at/batch job. 1928*7c478bd9Sstevel@tonic-gate * If ever a premature return is added to this function pay attention to 1929*7c478bd9Sstevel@tonic-gate * free at_cmdfile and outfile plus jobname buffers of the runinfo structure. 1930*7c478bd9Sstevel@tonic-gate */ 1931*7c478bd9Sstevel@tonic-gate static int 1932*7c478bd9Sstevel@tonic-gate ex(struct event *e) 1933*7c478bd9Sstevel@tonic-gate { 1934*7c478bd9Sstevel@tonic-gate int r; 1935*7c478bd9Sstevel@tonic-gate int fd; 1936*7c478bd9Sstevel@tonic-gate pid_t rfork; 1937*7c478bd9Sstevel@tonic-gate FILE *atcmdfp; 1938*7c478bd9Sstevel@tonic-gate char mailvar[4]; 1939*7c478bd9Sstevel@tonic-gate char *at_cmdfile = NULL; 1940*7c478bd9Sstevel@tonic-gate struct stat buf; 1941*7c478bd9Sstevel@tonic-gate struct queue *qp; 1942*7c478bd9Sstevel@tonic-gate struct runinfo *rp; 1943*7c478bd9Sstevel@tonic-gate struct project proj, *pproj = NULL; 1944*7c478bd9Sstevel@tonic-gate char mybuf[PROJECT_BUFSZ]; 1945*7c478bd9Sstevel@tonic-gate char mybuf2[PROJECT_BUFSZ]; 1946*7c478bd9Sstevel@tonic-gate char *tmpfile; 1947*7c478bd9Sstevel@tonic-gate FILE *fptr; 1948*7c478bd9Sstevel@tonic-gate time_t dhltime; 1949*7c478bd9Sstevel@tonic-gate projid_t projid; 1950*7c478bd9Sstevel@tonic-gate int projflag = 0; 1951*7c478bd9Sstevel@tonic-gate 1952*7c478bd9Sstevel@tonic-gate qp = &qt[e->etype]; /* set pointer to queue defs */ 1953*7c478bd9Sstevel@tonic-gate if (qp->nrun >= qp->njob) { 1954*7c478bd9Sstevel@tonic-gate msg("%c queue max run limit reached", e->etype+'a'); 1955*7c478bd9Sstevel@tonic-gate resched(qp->nwait); 1956*7c478bd9Sstevel@tonic-gate return (0); 1957*7c478bd9Sstevel@tonic-gate } 1958*7c478bd9Sstevel@tonic-gate if ((rp = rinfo_get(0)) == NULL) { 1959*7c478bd9Sstevel@tonic-gate msg("MAXRUN (%d) procs reached", MAXRUN); 1960*7c478bd9Sstevel@tonic-gate resched(qp->nwait); 1961*7c478bd9Sstevel@tonic-gate return (0); 1962*7c478bd9Sstevel@tonic-gate } 1963*7c478bd9Sstevel@tonic-gate 1964*7c478bd9Sstevel@tonic-gate #ifdef ATLIMIT 1965*7c478bd9Sstevel@tonic-gate if ((e->u)->uid != 0 && (e->u)->aruncnt >= ATLIMIT) { 1966*7c478bd9Sstevel@tonic-gate msg("ATLIMIT (%d) reached for uid %d", 1967*7c478bd9Sstevel@tonic-gate ATLIMIT, (e->u)->uid); 1968*7c478bd9Sstevel@tonic-gate rinfo_free(rp); 1969*7c478bd9Sstevel@tonic-gate resched(qp->nwait); 1970*7c478bd9Sstevel@tonic-gate return (0); 1971*7c478bd9Sstevel@tonic-gate } 1972*7c478bd9Sstevel@tonic-gate #endif 1973*7c478bd9Sstevel@tonic-gate #ifdef CRONLIMIT 1974*7c478bd9Sstevel@tonic-gate if ((e->u)->uid != 0 && (e->u)->cruncnt >= CRONLIMIT) { 1975*7c478bd9Sstevel@tonic-gate msg("CRONLIMIT (%d) reached for uid %d", 1976*7c478bd9Sstevel@tonic-gate CRONLIMIT, (e->u)->uid); 1977*7c478bd9Sstevel@tonic-gate rinfo_free(rp); 1978*7c478bd9Sstevel@tonic-gate resched(qp->nwait); 1979*7c478bd9Sstevel@tonic-gate return (0); 1980*7c478bd9Sstevel@tonic-gate } 1981*7c478bd9Sstevel@tonic-gate #endif 1982*7c478bd9Sstevel@tonic-gate if ((e->u)->uid == 0) { /* set default path */ 1983*7c478bd9Sstevel@tonic-gate /* path settable in defaults file */ 1984*7c478bd9Sstevel@tonic-gate envinit[2] = supath; 1985*7c478bd9Sstevel@tonic-gate } else { 1986*7c478bd9Sstevel@tonic-gate envinit[2] = path; 1987*7c478bd9Sstevel@tonic-gate } 1988*7c478bd9Sstevel@tonic-gate 1989*7c478bd9Sstevel@tonic-gate /* 1990*7c478bd9Sstevel@tonic-gate * the tempnam() function uses malloc(3C) to allocate space for the 1991*7c478bd9Sstevel@tonic-gate * constructed file name, and returns a pointer to this area, which 1992*7c478bd9Sstevel@tonic-gate * is assigned to rp->outfile. Here rp->outfile is not overwritten. 1993*7c478bd9Sstevel@tonic-gate */ 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate rp->outfile = tempnam(TMPDIR, PFX); 1996*7c478bd9Sstevel@tonic-gate rp->jobtype = e->etype; 1997*7c478bd9Sstevel@tonic-gate if (e->etype == CRONEVENT) { 1998*7c478bd9Sstevel@tonic-gate rp->jobname = xmalloc(strlen(e->cmd)+1); 1999*7c478bd9Sstevel@tonic-gate (void) strcpy(rp->jobname, e->cmd); 2000*7c478bd9Sstevel@tonic-gate /* "cron" jobs only produce mail if there's output */ 2001*7c478bd9Sstevel@tonic-gate rp->mailwhendone = 0; 2002*7c478bd9Sstevel@tonic-gate } else { 2003*7c478bd9Sstevel@tonic-gate at_cmdfile = xmalloc(strlen(ATDIR)+strlen(e->cmd)+2); 2004*7c478bd9Sstevel@tonic-gate (void) sprintf(at_cmdfile, "%s/%s", ATDIR, e->cmd); 2005*7c478bd9Sstevel@tonic-gate if ((atcmdfp = fopen(at_cmdfile, "r")) == NULL) { 2006*7c478bd9Sstevel@tonic-gate if (errno == ENAMETOOLONG) { 2007*7c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == 0) 2008*7c478bd9Sstevel@tonic-gate cron_unlink(e->cmd); 2009*7c478bd9Sstevel@tonic-gate } else { 2010*7c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 2011*7c478bd9Sstevel@tonic-gate } 2012*7c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECAT); 2013*7c478bd9Sstevel@tonic-gate free(at_cmdfile); 2014*7c478bd9Sstevel@tonic-gate rinfo_free(rp); 2015*7c478bd9Sstevel@tonic-gate return (0); 2016*7c478bd9Sstevel@tonic-gate } 2017*7c478bd9Sstevel@tonic-gate rp->jobname = xmalloc(strlen(at_cmdfile)+1); 2018*7c478bd9Sstevel@tonic-gate (void) strcpy(rp->jobname, at_cmdfile); 2019*7c478bd9Sstevel@tonic-gate 2020*7c478bd9Sstevel@tonic-gate /* 2021*7c478bd9Sstevel@tonic-gate * Skip over the first two lines. 2022*7c478bd9Sstevel@tonic-gate */ 2023*7c478bd9Sstevel@tonic-gate (void) fscanf(atcmdfp, "%*[^\n]\n"); 2024*7c478bd9Sstevel@tonic-gate (void) fscanf(atcmdfp, "%*[^\n]\n"); 2025*7c478bd9Sstevel@tonic-gate if (fscanf(atcmdfp, ": notify by mail: %3s%*[^\n]\n", 2026*7c478bd9Sstevel@tonic-gate mailvar) == 1) { 2027*7c478bd9Sstevel@tonic-gate /* 2028*7c478bd9Sstevel@tonic-gate * Check to see if we should always send mail 2029*7c478bd9Sstevel@tonic-gate * to the owner. 2030*7c478bd9Sstevel@tonic-gate */ 2031*7c478bd9Sstevel@tonic-gate rp->mailwhendone = (strcmp(mailvar, "yes") == 0); 2032*7c478bd9Sstevel@tonic-gate } else { 2033*7c478bd9Sstevel@tonic-gate rp->mailwhendone = 0; 2034*7c478bd9Sstevel@tonic-gate } 2035*7c478bd9Sstevel@tonic-gate 2036*7c478bd9Sstevel@tonic-gate if (fscanf(atcmdfp, "\n: project: %d\n", &projid) == 1) { 2037*7c478bd9Sstevel@tonic-gate projflag = 1; 2038*7c478bd9Sstevel@tonic-gate } 2039*7c478bd9Sstevel@tonic-gate (void) fclose(atcmdfp); 2040*7c478bd9Sstevel@tonic-gate } 2041*7c478bd9Sstevel@tonic-gate 2042*7c478bd9Sstevel@tonic-gate /* 2043*7c478bd9Sstevel@tonic-gate * we make sure that the system time 2044*7c478bd9Sstevel@tonic-gate * hasn't drifted backwards. if it has, el_add() is now 2045*7c478bd9Sstevel@tonic-gate * called, to make sure that the event queue is back in order, 2046*7c478bd9Sstevel@tonic-gate * and we set the delayed flag. cron will pick up the request 2047*7c478bd9Sstevel@tonic-gate * later on at the proper time. 2048*7c478bd9Sstevel@tonic-gate */ 2049*7c478bd9Sstevel@tonic-gate dhltime = time(NULL); 2050*7c478bd9Sstevel@tonic-gate if ((dhltime - e->time) < 0) { 2051*7c478bd9Sstevel@tonic-gate msg("clock time drifted backwards!\n"); 2052*7c478bd9Sstevel@tonic-gate if (next_event->etype == CRONEVENT) { 2053*7c478bd9Sstevel@tonic-gate msg("correcting cron event\n"); 2054*7c478bd9Sstevel@tonic-gate next_event->time = next_time(next_event, dhltime); 2055*7c478bd9Sstevel@tonic-gate el_add(next_event, next_event->time, 2056*7c478bd9Sstevel@tonic-gate (next_event->u)->ctid); 2057*7c478bd9Sstevel@tonic-gate } else { /* etype == ATEVENT */ 2058*7c478bd9Sstevel@tonic-gate msg("correcting batch event\n"); 2059*7c478bd9Sstevel@tonic-gate el_add(next_event, next_event->time, 2060*7c478bd9Sstevel@tonic-gate next_event->of.at.eventid); 2061*7c478bd9Sstevel@tonic-gate } 2062*7c478bd9Sstevel@tonic-gate delayed++; 2063*7c478bd9Sstevel@tonic-gate t_old = time(NULL); 2064*7c478bd9Sstevel@tonic-gate free(at_cmdfile); 2065*7c478bd9Sstevel@tonic-gate rinfo_free(rp); 2066*7c478bd9Sstevel@tonic-gate return (0); 2067*7c478bd9Sstevel@tonic-gate } 2068*7c478bd9Sstevel@tonic-gate 2069*7c478bd9Sstevel@tonic-gate if ((rfork = fork()) == (pid_t)-1) { 2070*7c478bd9Sstevel@tonic-gate reap_child(); 2071*7c478bd9Sstevel@tonic-gate if ((rfork = fork()) == (pid_t)-1) { 2072*7c478bd9Sstevel@tonic-gate msg("cannot fork"); 2073*7c478bd9Sstevel@tonic-gate free(at_cmdfile); 2074*7c478bd9Sstevel@tonic-gate rinfo_free(rp); 2075*7c478bd9Sstevel@tonic-gate resched(60); 2076*7c478bd9Sstevel@tonic-gate (void) sleep(30); 2077*7c478bd9Sstevel@tonic-gate return (0); 2078*7c478bd9Sstevel@tonic-gate } 2079*7c478bd9Sstevel@tonic-gate } 2080*7c478bd9Sstevel@tonic-gate if (rfork) { /* parent process */ 2081*7c478bd9Sstevel@tonic-gate contract_abandon_latest(rfork); 2082*7c478bd9Sstevel@tonic-gate 2083*7c478bd9Sstevel@tonic-gate ++qp->nrun; 2084*7c478bd9Sstevel@tonic-gate rp->pid = rfork; 2085*7c478bd9Sstevel@tonic-gate rp->que = e->etype; 2086*7c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) 2087*7c478bd9Sstevel@tonic-gate (e->u)->aruncnt++; 2088*7c478bd9Sstevel@tonic-gate else 2089*7c478bd9Sstevel@tonic-gate (e->u)->cruncnt++; 2090*7c478bd9Sstevel@tonic-gate rp->rusr = (e->u); 2091*7c478bd9Sstevel@tonic-gate logit(BCHAR, rp, 0); 2092*7c478bd9Sstevel@tonic-gate free(at_cmdfile); 2093*7c478bd9Sstevel@tonic-gate 2094*7c478bd9Sstevel@tonic-gate return (0); 2095*7c478bd9Sstevel@tonic-gate } 2096*7c478bd9Sstevel@tonic-gate 2097*7c478bd9Sstevel@tonic-gate child_sigreset(); 2098*7c478bd9Sstevel@tonic-gate contract_clear_template(); 2099*7c478bd9Sstevel@tonic-gate 2100*7c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) { 2101*7c478bd9Sstevel@tonic-gate /* open jobfile as stdin to shell */ 2102*7c478bd9Sstevel@tonic-gate if (stat(at_cmdfile, &buf)) { 2103*7c478bd9Sstevel@tonic-gate if (errno == ENAMETOOLONG) { 2104*7c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == 0) 2105*7c478bd9Sstevel@tonic-gate cron_unlink(e->cmd); 2106*7c478bd9Sstevel@tonic-gate } else 2107*7c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 2108*7c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECCRON); 2109*7c478bd9Sstevel@tonic-gate exit(1); 2110*7c478bd9Sstevel@tonic-gate } 2111*7c478bd9Sstevel@tonic-gate if (!(buf.st_mode&ISUID)) { 2112*7c478bd9Sstevel@tonic-gate /* 2113*7c478bd9Sstevel@tonic-gate * if setuid bit off, original owner has 2114*7c478bd9Sstevel@tonic-gate * given this file to someone else 2115*7c478bd9Sstevel@tonic-gate */ 2116*7c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 2117*7c478bd9Sstevel@tonic-gate exit(1); 2118*7c478bd9Sstevel@tonic-gate } 2119*7c478bd9Sstevel@tonic-gate if ((fd = open(at_cmdfile, O_RDONLY)) == -1) { 2120*7c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECCRON); 2121*7c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 2122*7c478bd9Sstevel@tonic-gate exit(1); 2123*7c478bd9Sstevel@tonic-gate } 2124*7c478bd9Sstevel@tonic-gate if (fd != 0) { 2125*7c478bd9Sstevel@tonic-gate (void) dup2(fd, 0); 2126*7c478bd9Sstevel@tonic-gate (void) close(fd); 2127*7c478bd9Sstevel@tonic-gate } 2128*7c478bd9Sstevel@tonic-gate /* 2129*7c478bd9Sstevel@tonic-gate * retrieve the project id of the at job and convert it 2130*7c478bd9Sstevel@tonic-gate * to a project name. fail if it's not a valid project 2131*7c478bd9Sstevel@tonic-gate * or if the user isn't a member of the project. 2132*7c478bd9Sstevel@tonic-gate */ 2133*7c478bd9Sstevel@tonic-gate if (projflag == 1) { 2134*7c478bd9Sstevel@tonic-gate if ((pproj = getprojbyid(projid, &proj, 2135*7c478bd9Sstevel@tonic-gate (void *)&mybuf, sizeof (mybuf))) == NULL || 2136*7c478bd9Sstevel@tonic-gate !inproj(e->u->name, pproj->pj_name, 2137*7c478bd9Sstevel@tonic-gate mybuf2, sizeof (mybuf2))) { 2138*7c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 2139*7c478bd9Sstevel@tonic-gate mail((e->u)->name, BADPROJID, ERR_CANTEXECAT); 2140*7c478bd9Sstevel@tonic-gate exit(1); 2141*7c478bd9Sstevel@tonic-gate } 2142*7c478bd9Sstevel@tonic-gate } 2143*7c478bd9Sstevel@tonic-gate } 2144*7c478bd9Sstevel@tonic-gate 2145*7c478bd9Sstevel@tonic-gate /* 2146*7c478bd9Sstevel@tonic-gate * Put process in a new session, and create a new task. 2147*7c478bd9Sstevel@tonic-gate */ 2148*7c478bd9Sstevel@tonic-gate if (setsid() < 0) { 2149*7c478bd9Sstevel@tonic-gate msg("setsid failed with errno = %d. job failed (%s)" 2150*7c478bd9Sstevel@tonic-gate " for user %s", errno, e->cmd, e->u->name); 2151*7c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) 2152*7c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 2153*7c478bd9Sstevel@tonic-gate exit(1); 2154*7c478bd9Sstevel@tonic-gate } 2155*7c478bd9Sstevel@tonic-gate 2156*7c478bd9Sstevel@tonic-gate /* 2157*7c478bd9Sstevel@tonic-gate * set correct user identification and check his account 2158*7c478bd9Sstevel@tonic-gate */ 2159*7c478bd9Sstevel@tonic-gate r = set_user_cred(e->u, pproj); 2160*7c478bd9Sstevel@tonic-gate if (r == VUC_EXPIRED) { 2161*7c478bd9Sstevel@tonic-gate msg("user (%s) account is expired", e->u->name); 2162*7c478bd9Sstevel@tonic-gate audit_cron_user_acct_expired(e->u->name); 2163*7c478bd9Sstevel@tonic-gate clean_out_user(e->u); 2164*7c478bd9Sstevel@tonic-gate exit(1); 2165*7c478bd9Sstevel@tonic-gate } 2166*7c478bd9Sstevel@tonic-gate if (r == VUC_NEW_AUTH) { 2167*7c478bd9Sstevel@tonic-gate msg("user (%s) password has expired", e->u->name); 2168*7c478bd9Sstevel@tonic-gate audit_cron_user_acct_expired(e->u->name); 2169*7c478bd9Sstevel@tonic-gate clean_out_user(e->u); 2170*7c478bd9Sstevel@tonic-gate exit(1); 2171*7c478bd9Sstevel@tonic-gate } 2172*7c478bd9Sstevel@tonic-gate if (r != VUC_OK) { 2173*7c478bd9Sstevel@tonic-gate msg("bad user (%s)", e->u->name); 2174*7c478bd9Sstevel@tonic-gate audit_cron_bad_user(e->u->name); 2175*7c478bd9Sstevel@tonic-gate clean_out_user(e->u); 2176*7c478bd9Sstevel@tonic-gate exit(1); 2177*7c478bd9Sstevel@tonic-gate } 2178*7c478bd9Sstevel@tonic-gate /* 2179*7c478bd9Sstevel@tonic-gate * check user and initialize the supplementary group access list. 2180*7c478bd9Sstevel@tonic-gate * bugid 1230784: deleted from parent to avoid cron hang. Now 2181*7c478bd9Sstevel@tonic-gate * only child handles the call. 2182*7c478bd9Sstevel@tonic-gate */ 2183*7c478bd9Sstevel@tonic-gate 2184*7c478bd9Sstevel@tonic-gate if (verify_user_cred(e->u) != VUC_OK || 2185*7c478bd9Sstevel@tonic-gate setgid(e->u->gid) == -1 || 2186*7c478bd9Sstevel@tonic-gate initgroups(e->u->name, e->u->gid) == -1) { 2187*7c478bd9Sstevel@tonic-gate msg("bad user (%s) or setgid failed (%s)", 2188*7c478bd9Sstevel@tonic-gate e->u->name, e->u->name); 2189*7c478bd9Sstevel@tonic-gate audit_cron_bad_user(e->u->name); 2190*7c478bd9Sstevel@tonic-gate clean_out_user(e->u); 2191*7c478bd9Sstevel@tonic-gate exit(1); 2192*7c478bd9Sstevel@tonic-gate } 2193*7c478bd9Sstevel@tonic-gate 2194*7c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) { 2195*7c478bd9Sstevel@tonic-gate r = audit_cron_session(e->u->name, NULL, 2196*7c478bd9Sstevel@tonic-gate e->u->uid, e->u->gid, 2197*7c478bd9Sstevel@tonic-gate at_cmdfile); 2198*7c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 2199*7c478bd9Sstevel@tonic-gate } else { 2200*7c478bd9Sstevel@tonic-gate r = audit_cron_session(e->u->name, CRONDIR, 2201*7c478bd9Sstevel@tonic-gate e->u->uid, e->u->gid, 2202*7c478bd9Sstevel@tonic-gate NULL); 2203*7c478bd9Sstevel@tonic-gate } 2204*7c478bd9Sstevel@tonic-gate if (r != 0) { 2205*7c478bd9Sstevel@tonic-gate msg("cron audit problem. job failed (%s) for user %s", 2206*7c478bd9Sstevel@tonic-gate e->cmd, e->u->name); 2207*7c478bd9Sstevel@tonic-gate exit(1); 2208*7c478bd9Sstevel@tonic-gate } 2209*7c478bd9Sstevel@tonic-gate 2210*7c478bd9Sstevel@tonic-gate audit_cron_new_job(e->cmd, e->etype, (void *)e); 2211*7c478bd9Sstevel@tonic-gate 2212*7c478bd9Sstevel@tonic-gate if (setuid(e->u->uid) == -1) { 2213*7c478bd9Sstevel@tonic-gate msg("setuid failed (%s)", e->u->name); 2214*7c478bd9Sstevel@tonic-gate clean_out_user(e->u); 2215*7c478bd9Sstevel@tonic-gate exit(1); 2216*7c478bd9Sstevel@tonic-gate } 2217*7c478bd9Sstevel@tonic-gate 2218*7c478bd9Sstevel@tonic-gate if (e->etype == CRONEVENT) { 2219*7c478bd9Sstevel@tonic-gate /* check for standard input to command */ 2220*7c478bd9Sstevel@tonic-gate if (e->of.ct.input != NULL) { 2221*7c478bd9Sstevel@tonic-gate if ((tmpfile = strdup(TMPINFILE)) == NULL) { 2222*7c478bd9Sstevel@tonic-gate mail((e->u)->name, MALLOCERR, 2223*7c478bd9Sstevel@tonic-gate ERR_CANTEXECCRON); 2224*7c478bd9Sstevel@tonic-gate exit(1); 2225*7c478bd9Sstevel@tonic-gate } 2226*7c478bd9Sstevel@tonic-gate if ((fd = mkstemp(tmpfile)) == -1 || 2227*7c478bd9Sstevel@tonic-gate (fptr = fdopen(fd, "w")) == NULL) { 2228*7c478bd9Sstevel@tonic-gate mail((e->u)->name, NOSTDIN, 2229*7c478bd9Sstevel@tonic-gate ERR_CANTEXECCRON); 2230*7c478bd9Sstevel@tonic-gate cron_unlink(tmpfile); 2231*7c478bd9Sstevel@tonic-gate free(tmpfile); 2232*7c478bd9Sstevel@tonic-gate exit(1); 2233*7c478bd9Sstevel@tonic-gate } 2234*7c478bd9Sstevel@tonic-gate if ((fwrite(e->of.ct.input, sizeof (char), 2235*7c478bd9Sstevel@tonic-gate strlen(e->of.ct.input), fptr)) != 2236*7c478bd9Sstevel@tonic-gate strlen(e->of.ct.input)) { 2237*7c478bd9Sstevel@tonic-gate mail((e->u)->name, NOSTDIN, ERR_CANTEXECCRON); 2238*7c478bd9Sstevel@tonic-gate cron_unlink(tmpfile); 2239*7c478bd9Sstevel@tonic-gate free(tmpfile); 2240*7c478bd9Sstevel@tonic-gate (void) close(fd); 2241*7c478bd9Sstevel@tonic-gate (void) fclose(fptr); 2242*7c478bd9Sstevel@tonic-gate exit(1); 2243*7c478bd9Sstevel@tonic-gate } 2244*7c478bd9Sstevel@tonic-gate if (fseek(fptr, (off_t)0, SEEK_SET) != -1) { 2245*7c478bd9Sstevel@tonic-gate if (fd != 0) { 2246*7c478bd9Sstevel@tonic-gate (void) dup2(fd, 0); 2247*7c478bd9Sstevel@tonic-gate (void) close(fd); 2248*7c478bd9Sstevel@tonic-gate } 2249*7c478bd9Sstevel@tonic-gate } 2250*7c478bd9Sstevel@tonic-gate cron_unlink(tmpfile); 2251*7c478bd9Sstevel@tonic-gate free(tmpfile); 2252*7c478bd9Sstevel@tonic-gate (void) fclose(fptr); 2253*7c478bd9Sstevel@tonic-gate } else if ((fd = open("/dev/null", O_RDONLY)) > 0) { 2254*7c478bd9Sstevel@tonic-gate (void) dup2(fd, 0); 2255*7c478bd9Sstevel@tonic-gate (void) close(fd); 2256*7c478bd9Sstevel@tonic-gate } 2257*7c478bd9Sstevel@tonic-gate } 2258*7c478bd9Sstevel@tonic-gate 2259*7c478bd9Sstevel@tonic-gate /* redirect stdout and stderr for the shell */ 2260*7c478bd9Sstevel@tonic-gate if ((fd = open(rp->outfile, O_WRONLY|O_CREAT|O_EXCL, OUTMODE)) == 1) 2261*7c478bd9Sstevel@tonic-gate fd = open("/dev/null", O_WRONLY); 2262*7c478bd9Sstevel@tonic-gate 2263*7c478bd9Sstevel@tonic-gate if (fd >= 0 && fd != 1) 2264*7c478bd9Sstevel@tonic-gate (void) dup2(fd, 1); 2265*7c478bd9Sstevel@tonic-gate 2266*7c478bd9Sstevel@tonic-gate if (fd >= 0 && fd != 2) { 2267*7c478bd9Sstevel@tonic-gate (void) dup2(fd, 2); 2268*7c478bd9Sstevel@tonic-gate if (fd != 1) 2269*7c478bd9Sstevel@tonic-gate (void) close(fd); 2270*7c478bd9Sstevel@tonic-gate } 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate (void) strlcat(homedir, (e->u)->home, sizeof (homedir)); 2273*7c478bd9Sstevel@tonic-gate (void) strlcat(logname, (e->u)->name, sizeof (logname)); 2274*7c478bd9Sstevel@tonic-gate environ = envinit; 2275*7c478bd9Sstevel@tonic-gate if (chdir((e->u)->home) == -1) { 2276*7c478bd9Sstevel@tonic-gate mail((e->u)->name, CANTCDHOME, 2277*7c478bd9Sstevel@tonic-gate e->etype == CRONEVENT ? ERR_CANTEXECCRON : 2278*7c478bd9Sstevel@tonic-gate ERR_CANTEXECAT); 2279*7c478bd9Sstevel@tonic-gate exit(1); 2280*7c478bd9Sstevel@tonic-gate } 2281*7c478bd9Sstevel@tonic-gate #ifdef TESTING 2282*7c478bd9Sstevel@tonic-gate exit(1); 2283*7c478bd9Sstevel@tonic-gate #endif 2284*7c478bd9Sstevel@tonic-gate /* 2285*7c478bd9Sstevel@tonic-gate * make sure that all file descriptors EXCEPT 0, 1 and 2 2286*7c478bd9Sstevel@tonic-gate * will be closed. 2287*7c478bd9Sstevel@tonic-gate */ 2288*7c478bd9Sstevel@tonic-gate closefrom(3); 2289*7c478bd9Sstevel@tonic-gate 2290*7c478bd9Sstevel@tonic-gate if ((e->u)->uid != 0) 2291*7c478bd9Sstevel@tonic-gate (void) nice(qp->nice); 2292*7c478bd9Sstevel@tonic-gate if (e->etype == CRONEVENT) 2293*7c478bd9Sstevel@tonic-gate (void) execl(SHELL, "sh", "-c", e->cmd, 0); 2294*7c478bd9Sstevel@tonic-gate else /* type == ATEVENT */ 2295*7c478bd9Sstevel@tonic-gate (void) execl(SHELL, "sh", 0); 2296*7c478bd9Sstevel@tonic-gate mail((e->u)->name, CANTEXECSH, 2297*7c478bd9Sstevel@tonic-gate e->etype == CRONEVENT ? ERR_CANTEXECCRON : ERR_CANTEXECAT); 2298*7c478bd9Sstevel@tonic-gate exit(1); 2299*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 2300*7c478bd9Sstevel@tonic-gate } 2301*7c478bd9Sstevel@tonic-gate 2302*7c478bd9Sstevel@tonic-gate static int 2303*7c478bd9Sstevel@tonic-gate idle(long t) 2304*7c478bd9Sstevel@tonic-gate { 2305*7c478bd9Sstevel@tonic-gate time_t now; 2306*7c478bd9Sstevel@tonic-gate 2307*7c478bd9Sstevel@tonic-gate while (t > 0L) { 2308*7c478bd9Sstevel@tonic-gate 2309*7c478bd9Sstevel@tonic-gate if (msg_wait(t) != 0) { 2310*7c478bd9Sstevel@tonic-gate /* we need to run next job immediately */ 2311*7c478bd9Sstevel@tonic-gate return (0); 2312*7c478bd9Sstevel@tonic-gate } 2313*7c478bd9Sstevel@tonic-gate 2314*7c478bd9Sstevel@tonic-gate reap_child(); 2315*7c478bd9Sstevel@tonic-gate 2316*7c478bd9Sstevel@tonic-gate now = time(NULL); 2317*7c478bd9Sstevel@tonic-gate if (last_time > now) { 2318*7c478bd9Sstevel@tonic-gate /* clock has been reset */ 2319*7c478bd9Sstevel@tonic-gate return (1); 2320*7c478bd9Sstevel@tonic-gate } 2321*7c478bd9Sstevel@tonic-gate 2322*7c478bd9Sstevel@tonic-gate if (next_event == NULL && !el_empty()) { 2323*7c478bd9Sstevel@tonic-gate next_event = (struct event *)el_first(); 2324*7c478bd9Sstevel@tonic-gate } 2325*7c478bd9Sstevel@tonic-gate if (next_event == NULL) 2326*7c478bd9Sstevel@tonic-gate t = INFINITY; 2327*7c478bd9Sstevel@tonic-gate else 2328*7c478bd9Sstevel@tonic-gate t = (long)next_event->time - now; 2329*7c478bd9Sstevel@tonic-gate } 2330*7c478bd9Sstevel@tonic-gate return (0); 2331*7c478bd9Sstevel@tonic-gate } 2332*7c478bd9Sstevel@tonic-gate 2333*7c478bd9Sstevel@tonic-gate /* 2334*7c478bd9Sstevel@tonic-gate * This used to be in the idle(), but moved to the separate function. 2335*7c478bd9Sstevel@tonic-gate * This called from various place when cron needs to reap the 2336*7c478bd9Sstevel@tonic-gate * child. It includes the situation that cron hit maxrun, and needs 2337*7c478bd9Sstevel@tonic-gate * to reschedule the job. 2338*7c478bd9Sstevel@tonic-gate */ 2339*7c478bd9Sstevel@tonic-gate static void 2340*7c478bd9Sstevel@tonic-gate reap_child() 2341*7c478bd9Sstevel@tonic-gate { 2342*7c478bd9Sstevel@tonic-gate pid_t pid; 2343*7c478bd9Sstevel@tonic-gate int prc; 2344*7c478bd9Sstevel@tonic-gate struct runinfo *rp; 2345*7c478bd9Sstevel@tonic-gate 2346*7c478bd9Sstevel@tonic-gate for (;;) { 2347*7c478bd9Sstevel@tonic-gate pid = waitpid((pid_t)-1, &prc, WNOHANG); 2348*7c478bd9Sstevel@tonic-gate if (pid <= 0) 2349*7c478bd9Sstevel@tonic-gate break; 2350*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2351*7c478bd9Sstevel@tonic-gate fprintf(stderr, 2352*7c478bd9Sstevel@tonic-gate "wait returned %x for process %d\n", prc, pid); 2353*7c478bd9Sstevel@tonic-gate #endif 2354*7c478bd9Sstevel@tonic-gate if ((rp = rinfo_get(pid)) == NULL) { 2355*7c478bd9Sstevel@tonic-gate if (miscpid_delete(pid) == 0) { 2356*7c478bd9Sstevel@tonic-gate /* not found in anywhere */ 2357*7c478bd9Sstevel@tonic-gate msg(PIDERR, pid); 2358*7c478bd9Sstevel@tonic-gate } 2359*7c478bd9Sstevel@tonic-gate } else if (rp->que == ZOMB) { 2360*7c478bd9Sstevel@tonic-gate (void) unlink(rp->outfile); 2361*7c478bd9Sstevel@tonic-gate rinfo_free(rp); 2362*7c478bd9Sstevel@tonic-gate } else { 2363*7c478bd9Sstevel@tonic-gate cleanup(rp, prc); 2364*7c478bd9Sstevel@tonic-gate } 2365*7c478bd9Sstevel@tonic-gate } 2366*7c478bd9Sstevel@tonic-gate } 2367*7c478bd9Sstevel@tonic-gate 2368*7c478bd9Sstevel@tonic-gate static void 2369*7c478bd9Sstevel@tonic-gate cleanup(struct runinfo *pr, int rc) 2370*7c478bd9Sstevel@tonic-gate { 2371*7c478bd9Sstevel@tonic-gate int nextfork = 1; 2372*7c478bd9Sstevel@tonic-gate struct usr *p; 2373*7c478bd9Sstevel@tonic-gate struct stat buf; 2374*7c478bd9Sstevel@tonic-gate 2375*7c478bd9Sstevel@tonic-gate logit(ECHAR, pr, rc); 2376*7c478bd9Sstevel@tonic-gate --qt[pr->que].nrun; 2377*7c478bd9Sstevel@tonic-gate p = pr->rusr; 2378*7c478bd9Sstevel@tonic-gate if (pr->que != CRONEVENT) 2379*7c478bd9Sstevel@tonic-gate --p->aruncnt; 2380*7c478bd9Sstevel@tonic-gate else 2381*7c478bd9Sstevel@tonic-gate --p->cruncnt; 2382*7c478bd9Sstevel@tonic-gate 2383*7c478bd9Sstevel@tonic-gate if (!lstat(pr->outfile, &buf)) { 2384*7c478bd9Sstevel@tonic-gate if ((buf.st_mode != S_IFLNK) && 2385*7c478bd9Sstevel@tonic-gate (buf.st_size > 0 || pr->mailwhendone)) { 2386*7c478bd9Sstevel@tonic-gate /* mail user stdout and stderr */ 2387*7c478bd9Sstevel@tonic-gate for (;;) { 2388*7c478bd9Sstevel@tonic-gate if ((pr->pid = fork()) < 0) { 2389*7c478bd9Sstevel@tonic-gate /* 2390*7c478bd9Sstevel@tonic-gate * if fork fails try forever in doubling 2391*7c478bd9Sstevel@tonic-gate * retry times, up to 16 seconds 2392*7c478bd9Sstevel@tonic-gate */ 2393*7c478bd9Sstevel@tonic-gate (void) sleep(nextfork); 2394*7c478bd9Sstevel@tonic-gate if (nextfork < 16) 2395*7c478bd9Sstevel@tonic-gate nextfork += nextfork; 2396*7c478bd9Sstevel@tonic-gate continue; 2397*7c478bd9Sstevel@tonic-gate } else if (pr->pid == 0) { 2398*7c478bd9Sstevel@tonic-gate child_sigreset(); 2399*7c478bd9Sstevel@tonic-gate contract_clear_template(); 2400*7c478bd9Sstevel@tonic-gate 2401*7c478bd9Sstevel@tonic-gate mail_result(p, pr, buf.st_size); 2402*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2403*7c478bd9Sstevel@tonic-gate } else { 2404*7c478bd9Sstevel@tonic-gate contract_abandon_latest(pr->pid); 2405*7c478bd9Sstevel@tonic-gate pr->que = ZOMB; 2406*7c478bd9Sstevel@tonic-gate break; 2407*7c478bd9Sstevel@tonic-gate } 2408*7c478bd9Sstevel@tonic-gate } 2409*7c478bd9Sstevel@tonic-gate } else { 2410*7c478bd9Sstevel@tonic-gate (void) unlink(pr->outfile); 2411*7c478bd9Sstevel@tonic-gate rinfo_free(pr); 2412*7c478bd9Sstevel@tonic-gate } 2413*7c478bd9Sstevel@tonic-gate } else { 2414*7c478bd9Sstevel@tonic-gate rinfo_free(pr); 2415*7c478bd9Sstevel@tonic-gate } 2416*7c478bd9Sstevel@tonic-gate 2417*7c478bd9Sstevel@tonic-gate free_if_unused(p); 2418*7c478bd9Sstevel@tonic-gate } 2419*7c478bd9Sstevel@tonic-gate 2420*7c478bd9Sstevel@tonic-gate /* 2421*7c478bd9Sstevel@tonic-gate * Mail stdout and stderr of a job to user. Get uid for real user and become 2422*7c478bd9Sstevel@tonic-gate * that person. We do this so that mail won't come from root since this 2423*7c478bd9Sstevel@tonic-gate * could be a security hole. If failure, quit - don't send mail as root. 2424*7c478bd9Sstevel@tonic-gate */ 2425*7c478bd9Sstevel@tonic-gate static void 2426*7c478bd9Sstevel@tonic-gate mail_result(struct usr *p, struct runinfo *pr, size_t filesize) 2427*7c478bd9Sstevel@tonic-gate { 2428*7c478bd9Sstevel@tonic-gate struct passwd *ruser_ids; 2429*7c478bd9Sstevel@tonic-gate FILE *mailpipe; 2430*7c478bd9Sstevel@tonic-gate FILE *st; 2431*7c478bd9Sstevel@tonic-gate struct utsname name; 2432*7c478bd9Sstevel@tonic-gate int nbytes; 2433*7c478bd9Sstevel@tonic-gate char iobuf[BUFSIZ]; 2434*7c478bd9Sstevel@tonic-gate char *cmd; 2435*7c478bd9Sstevel@tonic-gate 2436*7c478bd9Sstevel@tonic-gate (void) uname(&name); 2437*7c478bd9Sstevel@tonic-gate if ((ruser_ids = getpwnam(p->name)) == NULL) 2438*7c478bd9Sstevel@tonic-gate exit(0); 2439*7c478bd9Sstevel@tonic-gate (void) setuid(ruser_ids->pw_uid); 2440*7c478bd9Sstevel@tonic-gate 2441*7c478bd9Sstevel@tonic-gate cmd = xmalloc(strlen(MAIL)+strlen(p->name)+2); 2442*7c478bd9Sstevel@tonic-gate (void) sprintf(cmd, "%s %s", MAIL, p->name); 2443*7c478bd9Sstevel@tonic-gate mailpipe = popen(cmd, "w"); 2444*7c478bd9Sstevel@tonic-gate contract_abandon_latest(0); 2445*7c478bd9Sstevel@tonic-gate free(cmd); 2446*7c478bd9Sstevel@tonic-gate if (mailpipe == NULL) 2447*7c478bd9Sstevel@tonic-gate exit(127); 2448*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "To: %s\n", p->name); 2449*7c478bd9Sstevel@tonic-gate if (pr->jobtype == CRONEVENT) { 2450*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, CRONOUT); 2451*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "Your \"cron\" job on %s\n", 2452*7c478bd9Sstevel@tonic-gate name.nodename); 2453*7c478bd9Sstevel@tonic-gate if (pr->jobname != NULL) { 2454*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "%s\n\n", pr->jobname); 2455*7c478bd9Sstevel@tonic-gate } 2456*7c478bd9Sstevel@tonic-gate } else { 2457*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "Subject: Output from \"at\" job\n\n"); 2458*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "Your \"at\" job on %s\n", 2459*7c478bd9Sstevel@tonic-gate name.nodename); 2460*7c478bd9Sstevel@tonic-gate if (pr->jobname != NULL) { 2461*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "\"%s\"\n\n", pr->jobname); 2462*7c478bd9Sstevel@tonic-gate } 2463*7c478bd9Sstevel@tonic-gate } 2464*7c478bd9Sstevel@tonic-gate /* Tmp. file is fopen'ed w/ "r", secure open */ 2465*7c478bd9Sstevel@tonic-gate if (filesize > 0 && 2466*7c478bd9Sstevel@tonic-gate (st = fopen(pr->outfile, "r")) != NULL) { 2467*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, 2468*7c478bd9Sstevel@tonic-gate "produced the following output:\n\n"); 2469*7c478bd9Sstevel@tonic-gate while ((nbytes = fread(iobuf, sizeof (char), BUFSIZ, st)) != 0) 2470*7c478bd9Sstevel@tonic-gate (void) fwrite(iobuf, sizeof (char), nbytes, mailpipe); 2471*7c478bd9Sstevel@tonic-gate (void) fclose(st); 2472*7c478bd9Sstevel@tonic-gate } else { 2473*7c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "completed.\n"); 2474*7c478bd9Sstevel@tonic-gate } 2475*7c478bd9Sstevel@tonic-gate (void) pclose(mailpipe); 2476*7c478bd9Sstevel@tonic-gate exit(0); 2477*7c478bd9Sstevel@tonic-gate } 2478*7c478bd9Sstevel@tonic-gate 2479*7c478bd9Sstevel@tonic-gate static int 2480*7c478bd9Sstevel@tonic-gate msg_wait(long tim) 2481*7c478bd9Sstevel@tonic-gate { 2482*7c478bd9Sstevel@tonic-gate struct message msg; 2483*7c478bd9Sstevel@tonic-gate int cnt; 2484*7c478bd9Sstevel@tonic-gate time_t reftime; 2485*7c478bd9Sstevel@tonic-gate struct pollfd pfd[2]; 2486*7c478bd9Sstevel@tonic-gate int64_t tl; 2487*7c478bd9Sstevel@tonic-gate int timeout; 2488*7c478bd9Sstevel@tonic-gate static int pending_msg; 2489*7c478bd9Sstevel@tonic-gate static time_t pending_reftime; 2490*7c478bd9Sstevel@tonic-gate 2491*7c478bd9Sstevel@tonic-gate if (pending_msg) { 2492*7c478bd9Sstevel@tonic-gate process_msg(&msgbuf, pending_reftime); 2493*7c478bd9Sstevel@tonic-gate pending_msg = 0; 2494*7c478bd9Sstevel@tonic-gate return (0); 2495*7c478bd9Sstevel@tonic-gate } 2496*7c478bd9Sstevel@tonic-gate 2497*7c478bd9Sstevel@tonic-gate /* 2498*7c478bd9Sstevel@tonic-gate * We are opening the signal mask to receive SIGCLD. The notifypipe 2499*7c478bd9Sstevel@tonic-gate * is used to avoid race condition between SIGCLD and poll system 2500*7c478bd9Sstevel@tonic-gate * call. 2501*7c478bd9Sstevel@tonic-gate * If SIGCLD is delivered in poll(), poll will be interrupted, and 2502*7c478bd9Sstevel@tonic-gate * we will return to idle() to reap the dead children. 2503*7c478bd9Sstevel@tonic-gate * If SIGCLD is delivered between sigprocmask() below and poll(), 2504*7c478bd9Sstevel@tonic-gate * there is no way we can detect the SIGCLD because poll() won't 2505*7c478bd9Sstevel@tonic-gate * be interrupted. In such case, the dead children can't be wait'ed 2506*7c478bd9Sstevel@tonic-gate * until poll returns by timeout or a new job. To avoid this race 2507*7c478bd9Sstevel@tonic-gate * condition, child_handler write to the notifypipe, so that 2508*7c478bd9Sstevel@tonic-gate * poll() will be able to return with POLLIN which indicates that 2509*7c478bd9Sstevel@tonic-gate * we have received SIGCLD. 2510*7c478bd9Sstevel@tonic-gate * 2511*7c478bd9Sstevel@tonic-gate * Since the notifypipe is used to just let poll return from 2512*7c478bd9Sstevel@tonic-gate * system call, the data in the pipe won't be read. Therefore, 2513*7c478bd9Sstevel@tonic-gate * any data in the pipe needs to be flushed before opening signal 2514*7c478bd9Sstevel@tonic-gate * mask. 2515*7c478bd9Sstevel@tonic-gate * 2516*7c478bd9Sstevel@tonic-gate * Note that we can probably re-write this code with pselect() 2517*7c478bd9Sstevel@tonic-gate * which can handle this situation easily. 2518*7c478bd9Sstevel@tonic-gate */ 2519*7c478bd9Sstevel@tonic-gate (void) ioctl(notifypipe[0], I_FLUSH, FLUSHW); 2520*7c478bd9Sstevel@tonic-gate 2521*7c478bd9Sstevel@tonic-gate pfd[0].fd = msgfd; 2522*7c478bd9Sstevel@tonic-gate pfd[0].events = POLLIN; 2523*7c478bd9Sstevel@tonic-gate pfd[1].fd = notifypipe[1]; 2524*7c478bd9Sstevel@tonic-gate pfd[1].events = POLLIN; 2525*7c478bd9Sstevel@tonic-gate 2526*7c478bd9Sstevel@tonic-gate #ifdef CRON_MAXSLEEP 2527*7c478bd9Sstevel@tonic-gate /* 2528*7c478bd9Sstevel@tonic-gate * CRON_MAXSLEEP can be defined to have cron periodically wake 2529*7c478bd9Sstevel@tonic-gate * up, so that cron can detect a change of TOD and adjust the 2530*7c478bd9Sstevel@tonic-gate * sleep time accordingly. 2531*7c478bd9Sstevel@tonic-gate */ 2532*7c478bd9Sstevel@tonic-gate tim = (tim > CRON_MAXSLEEP) ? CRON_MAXSLEEP : tim; 2533*7c478bd9Sstevel@tonic-gate #endif 2534*7c478bd9Sstevel@tonic-gate tl = (tim == INFINITY) ? -1ll : (int64_t)tim * 1000; 2535*7c478bd9Sstevel@tonic-gate 2536*7c478bd9Sstevel@tonic-gate accept_sigcld = 1; 2537*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &childmask, NULL); 2538*7c478bd9Sstevel@tonic-gate do { 2539*7c478bd9Sstevel@tonic-gate timeout = (tl > INT_MAX ? INT_MAX : (int)tl); 2540*7c478bd9Sstevel@tonic-gate tl -= timeout; 2541*7c478bd9Sstevel@tonic-gate cnt = poll(pfd, 2, timeout); 2542*7c478bd9Sstevel@tonic-gate if (cnt == -1 && errno != EINTR) { 2543*7c478bd9Sstevel@tonic-gate perror("! poll"); 2544*7c478bd9Sstevel@tonic-gate } 2545*7c478bd9Sstevel@tonic-gate } while (tl > 0 && cnt == 0); 2546*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &childmask, NULL); 2547*7c478bd9Sstevel@tonic-gate accept_sigcld = 0; 2548*7c478bd9Sstevel@tonic-gate 2549*7c478bd9Sstevel@tonic-gate /* 2550*7c478bd9Sstevel@tonic-gate * poll timeout or interrupted. 2551*7c478bd9Sstevel@tonic-gate */ 2552*7c478bd9Sstevel@tonic-gate if (cnt <= 0) 2553*7c478bd9Sstevel@tonic-gate return (0); 2554*7c478bd9Sstevel@tonic-gate 2555*7c478bd9Sstevel@tonic-gate /* 2556*7c478bd9Sstevel@tonic-gate * Not the timeout or new job, but a SIGCLD has been delivered. 2557*7c478bd9Sstevel@tonic-gate */ 2558*7c478bd9Sstevel@tonic-gate if ((pfd[0].revents & POLLIN) == 0) 2559*7c478bd9Sstevel@tonic-gate return (0); 2560*7c478bd9Sstevel@tonic-gate 2561*7c478bd9Sstevel@tonic-gate errno = 0; 2562*7c478bd9Sstevel@tonic-gate if ((cnt = read(msgfd, &msg, sizeof (msg))) != sizeof (msg)) { 2563*7c478bd9Sstevel@tonic-gate if (cnt != -1 || errno != EAGAIN) 2564*7c478bd9Sstevel@tonic-gate perror("! read"); 2565*7c478bd9Sstevel@tonic-gate return (0); 2566*7c478bd9Sstevel@tonic-gate } 2567*7c478bd9Sstevel@tonic-gate reftime = time(NULL); 2568*7c478bd9Sstevel@tonic-gate if (next_event != NULL && reftime >= next_event->time) { 2569*7c478bd9Sstevel@tonic-gate /* 2570*7c478bd9Sstevel@tonic-gate * we need to run the job before reloading crontab. 2571*7c478bd9Sstevel@tonic-gate */ 2572*7c478bd9Sstevel@tonic-gate (void) memcpy(&msgbuf, &msg, sizeof (msg)); 2573*7c478bd9Sstevel@tonic-gate pending_msg = 1; 2574*7c478bd9Sstevel@tonic-gate pending_reftime = reftime; 2575*7c478bd9Sstevel@tonic-gate return (1); 2576*7c478bd9Sstevel@tonic-gate } 2577*7c478bd9Sstevel@tonic-gate process_msg(&msg, reftime); 2578*7c478bd9Sstevel@tonic-gate return (0); 2579*7c478bd9Sstevel@tonic-gate } 2580*7c478bd9Sstevel@tonic-gate 2581*7c478bd9Sstevel@tonic-gate /* 2582*7c478bd9Sstevel@tonic-gate * process the message supplied via pipe. This will be called either 2583*7c478bd9Sstevel@tonic-gate * immediately after cron read the message from pipe, or idle time 2584*7c478bd9Sstevel@tonic-gate * if the message was pending due to the job execution. 2585*7c478bd9Sstevel@tonic-gate */ 2586*7c478bd9Sstevel@tonic-gate static void 2587*7c478bd9Sstevel@tonic-gate process_msg(struct message *pmsg, time_t reftime) 2588*7c478bd9Sstevel@tonic-gate { 2589*7c478bd9Sstevel@tonic-gate if (pmsg->etype == NULL) 2590*7c478bd9Sstevel@tonic-gate return; 2591*7c478bd9Sstevel@tonic-gate 2592*7c478bd9Sstevel@tonic-gate switch (pmsg->etype) { 2593*7c478bd9Sstevel@tonic-gate case AT: 2594*7c478bd9Sstevel@tonic-gate if (pmsg->action == DELETE) 2595*7c478bd9Sstevel@tonic-gate del_atjob(pmsg->fname, pmsg->logname); 2596*7c478bd9Sstevel@tonic-gate else 2597*7c478bd9Sstevel@tonic-gate mod_atjob(pmsg->fname, (time_t)0); 2598*7c478bd9Sstevel@tonic-gate break; 2599*7c478bd9Sstevel@tonic-gate case CRON: 2600*7c478bd9Sstevel@tonic-gate if (pmsg->action == DELETE) 2601*7c478bd9Sstevel@tonic-gate del_ctab(pmsg->fname); 2602*7c478bd9Sstevel@tonic-gate else 2603*7c478bd9Sstevel@tonic-gate mod_ctab(pmsg->fname, reftime); 2604*7c478bd9Sstevel@tonic-gate break; 2605*7c478bd9Sstevel@tonic-gate default: 2606*7c478bd9Sstevel@tonic-gate msg("message received - bad format"); 2607*7c478bd9Sstevel@tonic-gate break; 2608*7c478bd9Sstevel@tonic-gate } 2609*7c478bd9Sstevel@tonic-gate if (next_event != NULL) { 2610*7c478bd9Sstevel@tonic-gate if (next_event->etype == CRONEVENT) 2611*7c478bd9Sstevel@tonic-gate el_add(next_event, next_event->time, 2612*7c478bd9Sstevel@tonic-gate (next_event->u)->ctid); 2613*7c478bd9Sstevel@tonic-gate else /* etype == ATEVENT */ 2614*7c478bd9Sstevel@tonic-gate el_add(next_event, next_event->time, 2615*7c478bd9Sstevel@tonic-gate next_event->of.at.eventid); 2616*7c478bd9Sstevel@tonic-gate next_event = NULL; 2617*7c478bd9Sstevel@tonic-gate } 2618*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 2619*7c478bd9Sstevel@tonic-gate pmsg->etype = NULL; 2620*7c478bd9Sstevel@tonic-gate } 2621*7c478bd9Sstevel@tonic-gate 2622*7c478bd9Sstevel@tonic-gate static struct runinfo * 2623*7c478bd9Sstevel@tonic-gate rinfo_get(pid_t pid) 2624*7c478bd9Sstevel@tonic-gate { 2625*7c478bd9Sstevel@tonic-gate struct runinfo *rp; 2626*7c478bd9Sstevel@tonic-gate 2627*7c478bd9Sstevel@tonic-gate for (rp = rt; rp < rt+MAXRUN; rp++) { 2628*7c478bd9Sstevel@tonic-gate if (rp->pid == pid) 2629*7c478bd9Sstevel@tonic-gate break; 2630*7c478bd9Sstevel@tonic-gate } 2631*7c478bd9Sstevel@tonic-gate if (rp >= rt+MAXRUN) 2632*7c478bd9Sstevel@tonic-gate return (NULL); 2633*7c478bd9Sstevel@tonic-gate else 2634*7c478bd9Sstevel@tonic-gate return (rp); 2635*7c478bd9Sstevel@tonic-gate } 2636*7c478bd9Sstevel@tonic-gate 2637*7c478bd9Sstevel@tonic-gate /* 2638*7c478bd9Sstevel@tonic-gate * Free memory used for output file name and job name in runinfo structure 2639*7c478bd9Sstevel@tonic-gate */ 2640*7c478bd9Sstevel@tonic-gate static void 2641*7c478bd9Sstevel@tonic-gate rinfo_free(struct runinfo *rp) 2642*7c478bd9Sstevel@tonic-gate { 2643*7c478bd9Sstevel@tonic-gate free(rp->outfile); 2644*7c478bd9Sstevel@tonic-gate free(rp->jobname); 2645*7c478bd9Sstevel@tonic-gate rp->outfile = rp->jobname = NULL; 2646*7c478bd9Sstevel@tonic-gate rp->pid = 0; 2647*7c478bd9Sstevel@tonic-gate } 2648*7c478bd9Sstevel@tonic-gate 2649*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2650*7c478bd9Sstevel@tonic-gate static void 2651*7c478bd9Sstevel@tonic-gate thaw_handler(int sig) 2652*7c478bd9Sstevel@tonic-gate { 2653*7c478bd9Sstevel@tonic-gate ; 2654*7c478bd9Sstevel@tonic-gate } 2655*7c478bd9Sstevel@tonic-gate 2656*7c478bd9Sstevel@tonic-gate 2657*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 2658*7c478bd9Sstevel@tonic-gate static void 2659*7c478bd9Sstevel@tonic-gate cronend(int sig) 2660*7c478bd9Sstevel@tonic-gate { 2661*7c478bd9Sstevel@tonic-gate crabort("SIGTERM", REMOVE_FIFO); 2662*7c478bd9Sstevel@tonic-gate } 2663*7c478bd9Sstevel@tonic-gate 2664*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2665*7c478bd9Sstevel@tonic-gate static void 2666*7c478bd9Sstevel@tonic-gate child_handler(int sig) 2667*7c478bd9Sstevel@tonic-gate { 2668*7c478bd9Sstevel@tonic-gate /* 2669*7c478bd9Sstevel@tonic-gate * Just in case someone changes the signal mask. 2670*7c478bd9Sstevel@tonic-gate * we don't want to notify the SIGCLD. 2671*7c478bd9Sstevel@tonic-gate */ 2672*7c478bd9Sstevel@tonic-gate if (accept_sigcld) { 2673*7c478bd9Sstevel@tonic-gate (void) write(notifypipe[0], &sig, 1); 2674*7c478bd9Sstevel@tonic-gate } 2675*7c478bd9Sstevel@tonic-gate } 2676*7c478bd9Sstevel@tonic-gate 2677*7c478bd9Sstevel@tonic-gate static void 2678*7c478bd9Sstevel@tonic-gate child_sigreset(void) 2679*7c478bd9Sstevel@tonic-gate { 2680*7c478bd9Sstevel@tonic-gate (void) signal(SIGCLD, SIG_DFL); 2681*7c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &defmask, NULL); 2682*7c478bd9Sstevel@tonic-gate } 2683*7c478bd9Sstevel@tonic-gate 2684*7c478bd9Sstevel@tonic-gate /* 2685*7c478bd9Sstevel@tonic-gate * crabort() - handle exits out of cron 2686*7c478bd9Sstevel@tonic-gate */ 2687*7c478bd9Sstevel@tonic-gate static void 2688*7c478bd9Sstevel@tonic-gate crabort(char *mssg, int action) 2689*7c478bd9Sstevel@tonic-gate { 2690*7c478bd9Sstevel@tonic-gate int c; 2691*7c478bd9Sstevel@tonic-gate 2692*7c478bd9Sstevel@tonic-gate if (action & REMOVE_FIFO) { 2693*7c478bd9Sstevel@tonic-gate /* FIFO vanishes when cron finishes */ 2694*7c478bd9Sstevel@tonic-gate if (unlink(FIFO) < 0) 2695*7c478bd9Sstevel@tonic-gate perror("cron could not unlink FIFO"); 2696*7c478bd9Sstevel@tonic-gate } 2697*7c478bd9Sstevel@tonic-gate 2698*7c478bd9Sstevel@tonic-gate if (action & CONSOLE_MSG) { 2699*7c478bd9Sstevel@tonic-gate /* write error msg to console */ 2700*7c478bd9Sstevel@tonic-gate if ((c = open(CONSOLE, O_WRONLY)) >= 0) { 2701*7c478bd9Sstevel@tonic-gate (void) write(c, "cron aborted: ", 14); 2702*7c478bd9Sstevel@tonic-gate (void) write(c, mssg, strlen(mssg)); 2703*7c478bd9Sstevel@tonic-gate (void) write(c, "\n", 1); 2704*7c478bd9Sstevel@tonic-gate (void) close(c); 2705*7c478bd9Sstevel@tonic-gate } 2706*7c478bd9Sstevel@tonic-gate } 2707*7c478bd9Sstevel@tonic-gate 2708*7c478bd9Sstevel@tonic-gate /* always log the message */ 2709*7c478bd9Sstevel@tonic-gate msg(mssg); 2710*7c478bd9Sstevel@tonic-gate msg("******* CRON ABORTED ********"); 2711*7c478bd9Sstevel@tonic-gate exit(1); 2712*7c478bd9Sstevel@tonic-gate } 2713*7c478bd9Sstevel@tonic-gate 2714*7c478bd9Sstevel@tonic-gate /* 2715*7c478bd9Sstevel@tonic-gate * msg() - time-stamped error reporting function 2716*7c478bd9Sstevel@tonic-gate */ 2717*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 2718*7c478bd9Sstevel@tonic-gate static void 2719*7c478bd9Sstevel@tonic-gate msg(char *fmt, ...) 2720*7c478bd9Sstevel@tonic-gate { 2721*7c478bd9Sstevel@tonic-gate va_list args; 2722*7c478bd9Sstevel@tonic-gate time_t t; 2723*7c478bd9Sstevel@tonic-gate 2724*7c478bd9Sstevel@tonic-gate t = time(NULL); 2725*7c478bd9Sstevel@tonic-gate 2726*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 2727*7c478bd9Sstevel@tonic-gate 2728*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "! "); 2729*7c478bd9Sstevel@tonic-gate 2730*7c478bd9Sstevel@tonic-gate va_start(args, fmt); 2731*7c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, args); 2732*7c478bd9Sstevel@tonic-gate va_end(args); 2733*7c478bd9Sstevel@tonic-gate 2734*7c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), FORMAT, localtime(&t)); 2735*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " %s\n", timebuf); 2736*7c478bd9Sstevel@tonic-gate 2737*7c478bd9Sstevel@tonic-gate (void) fflush(stderr); 2738*7c478bd9Sstevel@tonic-gate } 2739*7c478bd9Sstevel@tonic-gate 2740*7c478bd9Sstevel@tonic-gate static void 2741*7c478bd9Sstevel@tonic-gate logit(int cc, struct runinfo *rp, int rc) 2742*7c478bd9Sstevel@tonic-gate { 2743*7c478bd9Sstevel@tonic-gate time_t t; 2744*7c478bd9Sstevel@tonic-gate int ret; 2745*7c478bd9Sstevel@tonic-gate 2746*7c478bd9Sstevel@tonic-gate if (!log) 2747*7c478bd9Sstevel@tonic-gate return; 2748*7c478bd9Sstevel@tonic-gate 2749*7c478bd9Sstevel@tonic-gate t = time(NULL); 2750*7c478bd9Sstevel@tonic-gate if (cc == BCHAR) 2751*7c478bd9Sstevel@tonic-gate (void) printf("%c CMD: %s\n", cc, next_event->cmd); 2752*7c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), FORMAT, localtime(&t)); 2753*7c478bd9Sstevel@tonic-gate (void) printf("%c %.8s %u %c %s", 2754*7c478bd9Sstevel@tonic-gate cc, (rp->rusr)->name, rp->pid, QUE(rp->que), timebuf); 2755*7c478bd9Sstevel@tonic-gate if ((ret = TSTAT(rc)) != 0) 2756*7c478bd9Sstevel@tonic-gate (void) printf(" ts=%d", ret); 2757*7c478bd9Sstevel@tonic-gate if ((ret = RCODE(rc)) != 0) 2758*7c478bd9Sstevel@tonic-gate (void) printf(" rc=%d", ret); 2759*7c478bd9Sstevel@tonic-gate (void) putchar('\n'); 2760*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 2761*7c478bd9Sstevel@tonic-gate } 2762*7c478bd9Sstevel@tonic-gate 2763*7c478bd9Sstevel@tonic-gate static void 2764*7c478bd9Sstevel@tonic-gate resched(int delay) 2765*7c478bd9Sstevel@tonic-gate { 2766*7c478bd9Sstevel@tonic-gate time_t nt; 2767*7c478bd9Sstevel@tonic-gate 2768*7c478bd9Sstevel@tonic-gate /* run job at a later time */ 2769*7c478bd9Sstevel@tonic-gate nt = next_event->time + delay; 2770*7c478bd9Sstevel@tonic-gate if (next_event->etype == CRONEVENT) { 2771*7c478bd9Sstevel@tonic-gate next_event->time = next_time(next_event, (time_t)0); 2772*7c478bd9Sstevel@tonic-gate if (nt < next_event->time) 2773*7c478bd9Sstevel@tonic-gate next_event->time = nt; 2774*7c478bd9Sstevel@tonic-gate el_add(next_event, next_event->time, (next_event->u)->ctid); 2775*7c478bd9Sstevel@tonic-gate delayed = 1; 2776*7c478bd9Sstevel@tonic-gate msg("rescheduling a cron job"); 2777*7c478bd9Sstevel@tonic-gate return; 2778*7c478bd9Sstevel@tonic-gate } 2779*7c478bd9Sstevel@tonic-gate add_atevent(next_event->u, next_event->cmd, nt, next_event->etype); 2780*7c478bd9Sstevel@tonic-gate msg("rescheduling at job"); 2781*7c478bd9Sstevel@tonic-gate } 2782*7c478bd9Sstevel@tonic-gate 2783*7c478bd9Sstevel@tonic-gate static void 2784*7c478bd9Sstevel@tonic-gate quedefs(int action) 2785*7c478bd9Sstevel@tonic-gate { 2786*7c478bd9Sstevel@tonic-gate int i; 2787*7c478bd9Sstevel@tonic-gate int j; 2788*7c478bd9Sstevel@tonic-gate char qbuf[QBUFSIZ]; 2789*7c478bd9Sstevel@tonic-gate FILE *fd; 2790*7c478bd9Sstevel@tonic-gate 2791*7c478bd9Sstevel@tonic-gate /* set up default queue definitions */ 2792*7c478bd9Sstevel@tonic-gate for (i = 0; i < NQUEUE; i++) { 2793*7c478bd9Sstevel@tonic-gate qt[i].njob = qd.njob; 2794*7c478bd9Sstevel@tonic-gate qt[i].nice = qd.nice; 2795*7c478bd9Sstevel@tonic-gate qt[i].nwait = qd.nwait; 2796*7c478bd9Sstevel@tonic-gate } 2797*7c478bd9Sstevel@tonic-gate if (action == DEFAULT) 2798*7c478bd9Sstevel@tonic-gate return; 2799*7c478bd9Sstevel@tonic-gate if ((fd = fopen(QUEDEFS, "r")) == NULL) { 2800*7c478bd9Sstevel@tonic-gate msg("cannot open quedefs file"); 2801*7c478bd9Sstevel@tonic-gate msg("using default queue definitions"); 2802*7c478bd9Sstevel@tonic-gate return; 2803*7c478bd9Sstevel@tonic-gate } 2804*7c478bd9Sstevel@tonic-gate while (fgets(qbuf, QBUFSIZ, fd) != NULL) { 2805*7c478bd9Sstevel@tonic-gate if ((j = qbuf[0]-'a') < 0 || j >= NQUEUE || qbuf[1] != '.') 2806*7c478bd9Sstevel@tonic-gate continue; 2807*7c478bd9Sstevel@tonic-gate parsqdef(&qbuf[2]); 2808*7c478bd9Sstevel@tonic-gate qt[j].njob = qq.njob; 2809*7c478bd9Sstevel@tonic-gate qt[j].nice = qq.nice; 2810*7c478bd9Sstevel@tonic-gate qt[j].nwait = qq.nwait; 2811*7c478bd9Sstevel@tonic-gate } 2812*7c478bd9Sstevel@tonic-gate (void) fclose(fd); 2813*7c478bd9Sstevel@tonic-gate } 2814*7c478bd9Sstevel@tonic-gate 2815*7c478bd9Sstevel@tonic-gate static void 2816*7c478bd9Sstevel@tonic-gate parsqdef(char *name) 2817*7c478bd9Sstevel@tonic-gate { 2818*7c478bd9Sstevel@tonic-gate int i; 2819*7c478bd9Sstevel@tonic-gate 2820*7c478bd9Sstevel@tonic-gate qq = qd; 2821*7c478bd9Sstevel@tonic-gate while (*name) { 2822*7c478bd9Sstevel@tonic-gate i = 0; 2823*7c478bd9Sstevel@tonic-gate while (isdigit(*name)) { 2824*7c478bd9Sstevel@tonic-gate i *= 10; 2825*7c478bd9Sstevel@tonic-gate i += *name++ - '0'; 2826*7c478bd9Sstevel@tonic-gate } 2827*7c478bd9Sstevel@tonic-gate switch (*name++) { 2828*7c478bd9Sstevel@tonic-gate case JOBF: 2829*7c478bd9Sstevel@tonic-gate qq.njob = i; 2830*7c478bd9Sstevel@tonic-gate break; 2831*7c478bd9Sstevel@tonic-gate case NICEF: 2832*7c478bd9Sstevel@tonic-gate qq.nice = i; 2833*7c478bd9Sstevel@tonic-gate break; 2834*7c478bd9Sstevel@tonic-gate case WAITF: 2835*7c478bd9Sstevel@tonic-gate qq.nwait = i; 2836*7c478bd9Sstevel@tonic-gate break; 2837*7c478bd9Sstevel@tonic-gate } 2838*7c478bd9Sstevel@tonic-gate } 2839*7c478bd9Sstevel@tonic-gate } 2840*7c478bd9Sstevel@tonic-gate 2841*7c478bd9Sstevel@tonic-gate /* 2842*7c478bd9Sstevel@tonic-gate * defaults - read defaults from /etc/default/cron 2843*7c478bd9Sstevel@tonic-gate */ 2844*7c478bd9Sstevel@tonic-gate static void 2845*7c478bd9Sstevel@tonic-gate defaults() 2846*7c478bd9Sstevel@tonic-gate { 2847*7c478bd9Sstevel@tonic-gate int flags; 2848*7c478bd9Sstevel@tonic-gate char *deflog; 2849*7c478bd9Sstevel@tonic-gate char *hz, *tz; 2850*7c478bd9Sstevel@tonic-gate 2851*7c478bd9Sstevel@tonic-gate /* 2852*7c478bd9Sstevel@tonic-gate * get HZ value for environment 2853*7c478bd9Sstevel@tonic-gate */ 2854*7c478bd9Sstevel@tonic-gate if ((hz = getenv("HZ")) == (char *)NULL) 2855*7c478bd9Sstevel@tonic-gate (void) sprintf(hzname, "HZ=%d", HZ); 2856*7c478bd9Sstevel@tonic-gate else 2857*7c478bd9Sstevel@tonic-gate (void) snprintf(hzname, sizeof (hzname), "HZ=%s", hz); 2858*7c478bd9Sstevel@tonic-gate /* 2859*7c478bd9Sstevel@tonic-gate * get TZ value for environment 2860*7c478bd9Sstevel@tonic-gate */ 2861*7c478bd9Sstevel@tonic-gate (void) snprintf(tzone, sizeof (tzone), "TZ=%s", 2862*7c478bd9Sstevel@tonic-gate ((tz = getenv("TZ")) != NULL) ? tz : DEFTZ); 2863*7c478bd9Sstevel@tonic-gate 2864*7c478bd9Sstevel@tonic-gate if (defopen(DEFFILE) == 0) { 2865*7c478bd9Sstevel@tonic-gate /* ignore case */ 2866*7c478bd9Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 2867*7c478bd9Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 2868*7c478bd9Sstevel@tonic-gate (void) defcntl(DC_SETFLAGS, flags); 2869*7c478bd9Sstevel@tonic-gate 2870*7c478bd9Sstevel@tonic-gate if (((deflog = defread("CRONLOG=")) == NULL) || 2871*7c478bd9Sstevel@tonic-gate (*deflog == 'N') || (*deflog == 'n')) 2872*7c478bd9Sstevel@tonic-gate log = 0; 2873*7c478bd9Sstevel@tonic-gate else 2874*7c478bd9Sstevel@tonic-gate log = 1; 2875*7c478bd9Sstevel@tonic-gate /* fix for 1087611 - allow paths to be set in defaults file */ 2876*7c478bd9Sstevel@tonic-gate if ((Def_path = defread("PATH=")) != NULL) { 2877*7c478bd9Sstevel@tonic-gate (void) strlcat(path, Def_path, LINE_MAX); 2878*7c478bd9Sstevel@tonic-gate } else { 2879*7c478bd9Sstevel@tonic-gate (void) strlcpy(path, NONROOTPATH, LINE_MAX); 2880*7c478bd9Sstevel@tonic-gate } 2881*7c478bd9Sstevel@tonic-gate if ((Def_supath = defread("SUPATH=")) != NULL) { 2882*7c478bd9Sstevel@tonic-gate (void) strlcat(supath, Def_supath, LINE_MAX); 2883*7c478bd9Sstevel@tonic-gate } else { 2884*7c478bd9Sstevel@tonic-gate (void) strlcpy(supath, ROOTPATH, LINE_MAX); 2885*7c478bd9Sstevel@tonic-gate } 2886*7c478bd9Sstevel@tonic-gate (void) defopen(NULL); 2887*7c478bd9Sstevel@tonic-gate } 2888*7c478bd9Sstevel@tonic-gate } 2889*7c478bd9Sstevel@tonic-gate 2890*7c478bd9Sstevel@tonic-gate /* 2891*7c478bd9Sstevel@tonic-gate * Determine if a user entry for a job is still ok. The method used here 2892*7c478bd9Sstevel@tonic-gate * is a lot (about 75x) faster than using setgrent() / getgrent() 2893*7c478bd9Sstevel@tonic-gate * endgrent(). It should be safe because we use the sysconf to determine 2894*7c478bd9Sstevel@tonic-gate * the max, and it tolerates the max being 0. 2895*7c478bd9Sstevel@tonic-gate */ 2896*7c478bd9Sstevel@tonic-gate 2897*7c478bd9Sstevel@tonic-gate static int 2898*7c478bd9Sstevel@tonic-gate verify_user_cred(const struct usr *u) 2899*7c478bd9Sstevel@tonic-gate { 2900*7c478bd9Sstevel@tonic-gate struct passwd *pw; 2901*7c478bd9Sstevel@tonic-gate size_t numUsrGrps = 0; 2902*7c478bd9Sstevel@tonic-gate size_t numOrigGrps = 0; 2903*7c478bd9Sstevel@tonic-gate size_t i; 2904*7c478bd9Sstevel@tonic-gate int retval; 2905*7c478bd9Sstevel@tonic-gate 2906*7c478bd9Sstevel@tonic-gate /* 2907*7c478bd9Sstevel@tonic-gate * Maximum number of groups a user may be in concurrently. This 2908*7c478bd9Sstevel@tonic-gate * is a value which we obtain at runtime through a sysconf() 2909*7c478bd9Sstevel@tonic-gate * call. 2910*7c478bd9Sstevel@tonic-gate */ 2911*7c478bd9Sstevel@tonic-gate 2912*7c478bd9Sstevel@tonic-gate static size_t nGroupsMax = (size_t)-1; 2913*7c478bd9Sstevel@tonic-gate 2914*7c478bd9Sstevel@tonic-gate /* 2915*7c478bd9Sstevel@tonic-gate * Arrays for cron user's group list, constructed at startup to 2916*7c478bd9Sstevel@tonic-gate * be nGroupsMax elements long, used for verifying user 2917*7c478bd9Sstevel@tonic-gate * credentials prior to execution. 2918*7c478bd9Sstevel@tonic-gate */ 2919*7c478bd9Sstevel@tonic-gate 2920*7c478bd9Sstevel@tonic-gate static gid_t *UsrGrps; 2921*7c478bd9Sstevel@tonic-gate static gid_t *OrigGrps; 2922*7c478bd9Sstevel@tonic-gate 2923*7c478bd9Sstevel@tonic-gate if (((pw = getpwnam(u->name)) == NULL) || 2924*7c478bd9Sstevel@tonic-gate (pw->pw_uid != u->uid)) { 2925*7c478bd9Sstevel@tonic-gate return (VUC_BADUSER); 2926*7c478bd9Sstevel@tonic-gate } 2927*7c478bd9Sstevel@tonic-gate 2928*7c478bd9Sstevel@tonic-gate /* 2929*7c478bd9Sstevel@tonic-gate * Create the group id lists needed for job credential 2930*7c478bd9Sstevel@tonic-gate * verification. 2931*7c478bd9Sstevel@tonic-gate */ 2932*7c478bd9Sstevel@tonic-gate 2933*7c478bd9Sstevel@tonic-gate if (nGroupsMax == (size_t)-1) { 2934*7c478bd9Sstevel@tonic-gate if ((nGroupsMax = sysconf(_SC_NGROUPS_MAX)) > 0) { 2935*7c478bd9Sstevel@tonic-gate UsrGrps = xcalloc(nGroupsMax, sizeof (gid_t)); 2936*7c478bd9Sstevel@tonic-gate OrigGrps = xcalloc(nGroupsMax, sizeof (gid_t)); 2937*7c478bd9Sstevel@tonic-gate } 2938*7c478bd9Sstevel@tonic-gate 2939*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2940*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "nGroupsMax = %ld\n", nGroupsMax); 2941*7c478bd9Sstevel@tonic-gate #endif 2942*7c478bd9Sstevel@tonic-gate } 2943*7c478bd9Sstevel@tonic-gate 2944*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2945*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred (%s-%d)\n", pw->pw_name, 2946*7c478bd9Sstevel@tonic-gate pw->pw_uid); 2947*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred: pw->pw_gid = %d, " 2948*7c478bd9Sstevel@tonic-gate "u->gid = %d\n", pw->pw_gid, u->gid); 2949*7c478bd9Sstevel@tonic-gate #endif 2950*7c478bd9Sstevel@tonic-gate 2951*7c478bd9Sstevel@tonic-gate retval = (u->gid == pw->pw_gid) ? VUC_OK : VUC_NOTINGROUP; 2952*7c478bd9Sstevel@tonic-gate 2953*7c478bd9Sstevel@tonic-gate if (nGroupsMax > 0) { 2954*7c478bd9Sstevel@tonic-gate numOrigGrps = getgroups(nGroupsMax, OrigGrps); 2955*7c478bd9Sstevel@tonic-gate 2956*7c478bd9Sstevel@tonic-gate (void) initgroups(pw->pw_name, pw->pw_gid); 2957*7c478bd9Sstevel@tonic-gate numUsrGrps = getgroups(nGroupsMax, UsrGrps); 2958*7c478bd9Sstevel@tonic-gate 2959*7c478bd9Sstevel@tonic-gate for (i = 0; i < numUsrGrps; i++) { 2960*7c478bd9Sstevel@tonic-gate if (UsrGrps[i] == u->gid) { 2961*7c478bd9Sstevel@tonic-gate retval = VUC_OK; 2962*7c478bd9Sstevel@tonic-gate break; 2963*7c478bd9Sstevel@tonic-gate } 2964*7c478bd9Sstevel@tonic-gate } 2965*7c478bd9Sstevel@tonic-gate 2966*7c478bd9Sstevel@tonic-gate if (OrigGrps) { 2967*7c478bd9Sstevel@tonic-gate (void) setgroups(numOrigGrps, OrigGrps); 2968*7c478bd9Sstevel@tonic-gate } 2969*7c478bd9Sstevel@tonic-gate } 2970*7c478bd9Sstevel@tonic-gate 2971*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2972*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred: VUC = %d\n", retval); 2973*7c478bd9Sstevel@tonic-gate #endif 2974*7c478bd9Sstevel@tonic-gate 2975*7c478bd9Sstevel@tonic-gate return (retval); 2976*7c478bd9Sstevel@tonic-gate } 2977*7c478bd9Sstevel@tonic-gate 2978*7c478bd9Sstevel@tonic-gate static int 2979*7c478bd9Sstevel@tonic-gate set_user_cred(const struct usr *u, struct project *pproj) 2980*7c478bd9Sstevel@tonic-gate { 2981*7c478bd9Sstevel@tonic-gate static char *progname = "cron"; 2982*7c478bd9Sstevel@tonic-gate int r = 0, rval = 0; 2983*7c478bd9Sstevel@tonic-gate 2984*7c478bd9Sstevel@tonic-gate if ((r = pam_start(progname, u->name, &pam_conv, &pamh)) 2985*7c478bd9Sstevel@tonic-gate != PAM_SUCCESS) { 2986*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2987*7c478bd9Sstevel@tonic-gate msg("pam_start returns %d\n", r); 2988*7c478bd9Sstevel@tonic-gate #endif 2989*7c478bd9Sstevel@tonic-gate rval = VUC_BADUSER; 2990*7c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 2991*7c478bd9Sstevel@tonic-gate } 2992*7c478bd9Sstevel@tonic-gate 2993*7c478bd9Sstevel@tonic-gate r = pam_acct_mgmt(pamh, 0); 2994*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 2995*7c478bd9Sstevel@tonic-gate msg("pam_acc_mgmt returns %d\n", r); 2996*7c478bd9Sstevel@tonic-gate #endif 2997*7c478bd9Sstevel@tonic-gate if (r == PAM_ACCT_EXPIRED) { 2998*7c478bd9Sstevel@tonic-gate rval = VUC_EXPIRED; 2999*7c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 3000*7c478bd9Sstevel@tonic-gate } 3001*7c478bd9Sstevel@tonic-gate if (r == PAM_NEW_AUTHTOK_REQD) { 3002*7c478bd9Sstevel@tonic-gate rval = VUC_NEW_AUTH; 3003*7c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 3004*7c478bd9Sstevel@tonic-gate } 3005*7c478bd9Sstevel@tonic-gate if (r != PAM_SUCCESS) { 3006*7c478bd9Sstevel@tonic-gate rval = VUC_BADUSER; 3007*7c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 3008*7c478bd9Sstevel@tonic-gate } 3009*7c478bd9Sstevel@tonic-gate 3010*7c478bd9Sstevel@tonic-gate if (pproj != NULL) { 3011*7c478bd9Sstevel@tonic-gate size_t sz = sizeof (PROJECT) + strlen(pproj->pj_name); 3012*7c478bd9Sstevel@tonic-gate char *buf = alloca(sz); 3013*7c478bd9Sstevel@tonic-gate 3014*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sz, PROJECT "%s", pproj->pj_name); 3015*7c478bd9Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_RESOURCE, buf); 3016*7c478bd9Sstevel@tonic-gate } 3017*7c478bd9Sstevel@tonic-gate 3018*7c478bd9Sstevel@tonic-gate r = pam_setcred(pamh, PAM_ESTABLISH_CRED); 3019*7c478bd9Sstevel@tonic-gate if (r != PAM_SUCCESS) 3020*7c478bd9Sstevel@tonic-gate rval = VUC_BADUSER; 3021*7c478bd9Sstevel@tonic-gate 3022*7c478bd9Sstevel@tonic-gate set_eser_cred_exit: 3023*7c478bd9Sstevel@tonic-gate (void) pam_end(pamh, r); 3024*7c478bd9Sstevel@tonic-gate return (rval); 3025*7c478bd9Sstevel@tonic-gate } 3026*7c478bd9Sstevel@tonic-gate 3027*7c478bd9Sstevel@tonic-gate static void 3028*7c478bd9Sstevel@tonic-gate clean_out_user(struct usr *u) 3029*7c478bd9Sstevel@tonic-gate { 3030*7c478bd9Sstevel@tonic-gate if (next_event->u == u) { 3031*7c478bd9Sstevel@tonic-gate next_event = NULL; 3032*7c478bd9Sstevel@tonic-gate } 3033*7c478bd9Sstevel@tonic-gate 3034*7c478bd9Sstevel@tonic-gate clean_out_ctab(u); 3035*7c478bd9Sstevel@tonic-gate clean_out_atjobs(u); 3036*7c478bd9Sstevel@tonic-gate free_if_unused(u); 3037*7c478bd9Sstevel@tonic-gate } 3038*7c478bd9Sstevel@tonic-gate 3039*7c478bd9Sstevel@tonic-gate static void 3040*7c478bd9Sstevel@tonic-gate clean_out_atjobs(struct usr *u) 3041*7c478bd9Sstevel@tonic-gate { 3042*7c478bd9Sstevel@tonic-gate struct event *ev, *pv; 3043*7c478bd9Sstevel@tonic-gate 3044*7c478bd9Sstevel@tonic-gate for (pv = NULL, ev = u->atevents; 3045*7c478bd9Sstevel@tonic-gate ev != NULL; 3046*7c478bd9Sstevel@tonic-gate pv = ev, ev = ev->link, free(pv)) { 3047*7c478bd9Sstevel@tonic-gate el_remove(ev->of.at.eventid, 1); 3048*7c478bd9Sstevel@tonic-gate if (cwd == AT) 3049*7c478bd9Sstevel@tonic-gate cron_unlink(ev->cmd); 3050*7c478bd9Sstevel@tonic-gate else { 3051*7c478bd9Sstevel@tonic-gate char buf[PATH_MAX]; 3052*7c478bd9Sstevel@tonic-gate if (strlen(ATDIR) + strlen(ev->cmd) + 2 3053*7c478bd9Sstevel@tonic-gate < PATH_MAX) { 3054*7c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%s/%s", ATDIR, ev->cmd); 3055*7c478bd9Sstevel@tonic-gate cron_unlink(buf); 3056*7c478bd9Sstevel@tonic-gate } 3057*7c478bd9Sstevel@tonic-gate } 3058*7c478bd9Sstevel@tonic-gate free(ev->cmd); 3059*7c478bd9Sstevel@tonic-gate } 3060*7c478bd9Sstevel@tonic-gate 3061*7c478bd9Sstevel@tonic-gate u->atevents = NULL; 3062*7c478bd9Sstevel@tonic-gate } 3063*7c478bd9Sstevel@tonic-gate 3064*7c478bd9Sstevel@tonic-gate static void 3065*7c478bd9Sstevel@tonic-gate clean_out_ctab(struct usr *u) 3066*7c478bd9Sstevel@tonic-gate { 3067*7c478bd9Sstevel@tonic-gate rm_ctevents(u); 3068*7c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0); 3069*7c478bd9Sstevel@tonic-gate u->ctid = 0; 3070*7c478bd9Sstevel@tonic-gate u->ctexists = 0; 3071*7c478bd9Sstevel@tonic-gate } 3072*7c478bd9Sstevel@tonic-gate 3073*7c478bd9Sstevel@tonic-gate static void 3074*7c478bd9Sstevel@tonic-gate cron_unlink(char *name) 3075*7c478bd9Sstevel@tonic-gate { 3076*7c478bd9Sstevel@tonic-gate int r; 3077*7c478bd9Sstevel@tonic-gate 3078*7c478bd9Sstevel@tonic-gate r = unlink(name); 3079*7c478bd9Sstevel@tonic-gate if (r == 0 || (r == -1 && errno == ENOENT)) { 3080*7c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(name, NULL); 3081*7c478bd9Sstevel@tonic-gate } 3082*7c478bd9Sstevel@tonic-gate } 3083*7c478bd9Sstevel@tonic-gate 3084*7c478bd9Sstevel@tonic-gate static void 3085*7c478bd9Sstevel@tonic-gate create_anc_ctab(struct event *e) 3086*7c478bd9Sstevel@tonic-gate { 3087*7c478bd9Sstevel@tonic-gate if (audit_cron_create_anc_file(e->u->name, 3088*7c478bd9Sstevel@tonic-gate (cwd == CRON) ? NULL:CRONDIR, 3089*7c478bd9Sstevel@tonic-gate e->u->name, 3090*7c478bd9Sstevel@tonic-gate e->u->uid) == -1) { 3091*7c478bd9Sstevel@tonic-gate process_anc_files(CRON_ANC_DELETE); 3092*7c478bd9Sstevel@tonic-gate crabort("cannot create ancillary files for crontabs", 3093*7c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG); 3094*7c478bd9Sstevel@tonic-gate } 3095*7c478bd9Sstevel@tonic-gate } 3096*7c478bd9Sstevel@tonic-gate 3097*7c478bd9Sstevel@tonic-gate static void 3098*7c478bd9Sstevel@tonic-gate delete_anc_ctab(struct event *e) 3099*7c478bd9Sstevel@tonic-gate { 3100*7c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(e->u->name, 3101*7c478bd9Sstevel@tonic-gate (cwd == CRON) ? NULL:CRONDIR); 3102*7c478bd9Sstevel@tonic-gate } 3103*7c478bd9Sstevel@tonic-gate 3104*7c478bd9Sstevel@tonic-gate static void 3105*7c478bd9Sstevel@tonic-gate create_anc_atjob(struct event *e) 3106*7c478bd9Sstevel@tonic-gate { 3107*7c478bd9Sstevel@tonic-gate if (!e->of.at.exists) 3108*7c478bd9Sstevel@tonic-gate return; 3109*7c478bd9Sstevel@tonic-gate 3110*7c478bd9Sstevel@tonic-gate if (audit_cron_create_anc_file(e->cmd, 3111*7c478bd9Sstevel@tonic-gate (cwd == AT) ? NULL:ATDIR, 3112*7c478bd9Sstevel@tonic-gate e->u->name, 3113*7c478bd9Sstevel@tonic-gate e->u->uid) == -1) { 3114*7c478bd9Sstevel@tonic-gate process_anc_files(CRON_ANC_DELETE); 3115*7c478bd9Sstevel@tonic-gate crabort("cannot create ancillary files for atjobs", 3116*7c478bd9Sstevel@tonic-gate REMOVE_FIFO|CONSOLE_MSG); 3117*7c478bd9Sstevel@tonic-gate } 3118*7c478bd9Sstevel@tonic-gate } 3119*7c478bd9Sstevel@tonic-gate 3120*7c478bd9Sstevel@tonic-gate static void 3121*7c478bd9Sstevel@tonic-gate delete_anc_atjob(struct event *e) 3122*7c478bd9Sstevel@tonic-gate { 3123*7c478bd9Sstevel@tonic-gate if (!e->of.at.exists) 3124*7c478bd9Sstevel@tonic-gate return; 3125*7c478bd9Sstevel@tonic-gate 3126*7c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(e->cmd, 3127*7c478bd9Sstevel@tonic-gate (cwd == AT) ? NULL:ATDIR); 3128*7c478bd9Sstevel@tonic-gate } 3129*7c478bd9Sstevel@tonic-gate 3130*7c478bd9Sstevel@tonic-gate 3131*7c478bd9Sstevel@tonic-gate static void 3132*7c478bd9Sstevel@tonic-gate process_anc_files(int del) 3133*7c478bd9Sstevel@tonic-gate { 3134*7c478bd9Sstevel@tonic-gate struct usr *u = uhead; 3135*7c478bd9Sstevel@tonic-gate struct event *e; 3136*7c478bd9Sstevel@tonic-gate 3137*7c478bd9Sstevel@tonic-gate if (!audit_cron_mode()) 3138*7c478bd9Sstevel@tonic-gate return; 3139*7c478bd9Sstevel@tonic-gate 3140*7c478bd9Sstevel@tonic-gate for (;;) { 3141*7c478bd9Sstevel@tonic-gate if (u->ctexists && u->ctevents != NULL) { 3142*7c478bd9Sstevel@tonic-gate e = u->ctevents; 3143*7c478bd9Sstevel@tonic-gate for (;;) { 3144*7c478bd9Sstevel@tonic-gate if (del) 3145*7c478bd9Sstevel@tonic-gate delete_anc_ctab(e); 3146*7c478bd9Sstevel@tonic-gate else 3147*7c478bd9Sstevel@tonic-gate create_anc_ctab(e); 3148*7c478bd9Sstevel@tonic-gate if ((e = e->link) == NULL) 3149*7c478bd9Sstevel@tonic-gate break; 3150*7c478bd9Sstevel@tonic-gate } 3151*7c478bd9Sstevel@tonic-gate } 3152*7c478bd9Sstevel@tonic-gate 3153*7c478bd9Sstevel@tonic-gate if (u->atevents != NULL) { 3154*7c478bd9Sstevel@tonic-gate e = u->atevents; 3155*7c478bd9Sstevel@tonic-gate for (;;) { 3156*7c478bd9Sstevel@tonic-gate if (del) 3157*7c478bd9Sstevel@tonic-gate delete_anc_atjob(e); 3158*7c478bd9Sstevel@tonic-gate else 3159*7c478bd9Sstevel@tonic-gate create_anc_atjob(e); 3160*7c478bd9Sstevel@tonic-gate if ((e = e->link) == NULL) 3161*7c478bd9Sstevel@tonic-gate break; 3162*7c478bd9Sstevel@tonic-gate } 3163*7c478bd9Sstevel@tonic-gate } 3164*7c478bd9Sstevel@tonic-gate 3165*7c478bd9Sstevel@tonic-gate if ((u = u->nextusr) == NULL) 3166*7c478bd9Sstevel@tonic-gate break; 3167*7c478bd9Sstevel@tonic-gate } 3168*7c478bd9Sstevel@tonic-gate } 3169*7c478bd9Sstevel@tonic-gate 3170*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 3171*7c478bd9Sstevel@tonic-gate static int 3172*7c478bd9Sstevel@tonic-gate cron_conv(int num_msg, struct pam_message **msgs, 3173*7c478bd9Sstevel@tonic-gate struct pam_response **response, void *appdata_ptr) 3174*7c478bd9Sstevel@tonic-gate { 3175*7c478bd9Sstevel@tonic-gate struct pam_message **m = msgs; 3176*7c478bd9Sstevel@tonic-gate int i; 3177*7c478bd9Sstevel@tonic-gate 3178*7c478bd9Sstevel@tonic-gate for (i = 0; i < num_msg; i++) { 3179*7c478bd9Sstevel@tonic-gate switch (m[i]->msg_style) { 3180*7c478bd9Sstevel@tonic-gate case PAM_ERROR_MSG: 3181*7c478bd9Sstevel@tonic-gate case PAM_TEXT_INFO: 3182*7c478bd9Sstevel@tonic-gate if (m[i]->msg != NULL) { 3183*7c478bd9Sstevel@tonic-gate (void) msg("%s\n", m[i]->msg); 3184*7c478bd9Sstevel@tonic-gate } 3185*7c478bd9Sstevel@tonic-gate break; 3186*7c478bd9Sstevel@tonic-gate 3187*7c478bd9Sstevel@tonic-gate default: 3188*7c478bd9Sstevel@tonic-gate break; 3189*7c478bd9Sstevel@tonic-gate } 3190*7c478bd9Sstevel@tonic-gate } 3191*7c478bd9Sstevel@tonic-gate return (0); 3192*7c478bd9Sstevel@tonic-gate } 3193*7c478bd9Sstevel@tonic-gate 3194*7c478bd9Sstevel@tonic-gate /* 3195*7c478bd9Sstevel@tonic-gate * Cron creates process for other than job. Mail process is the 3196*7c478bd9Sstevel@tonic-gate * one which rinfo does not cover. Therefore, miscpid will keep 3197*7c478bd9Sstevel@tonic-gate * track of the pids executed from cron. Otherwise, we will see 3198*7c478bd9Sstevel@tonic-gate * "unexpected pid returned.." messages appear in the log file. 3199*7c478bd9Sstevel@tonic-gate */ 3200*7c478bd9Sstevel@tonic-gate static void 3201*7c478bd9Sstevel@tonic-gate miscpid_insert(pid_t pid) 3202*7c478bd9Sstevel@tonic-gate { 3203*7c478bd9Sstevel@tonic-gate struct miscpid *mp; 3204*7c478bd9Sstevel@tonic-gate 3205*7c478bd9Sstevel@tonic-gate mp = xmalloc(sizeof (*mp)); 3206*7c478bd9Sstevel@tonic-gate mp->pid = pid; 3207*7c478bd9Sstevel@tonic-gate mp->next = miscpid_head; 3208*7c478bd9Sstevel@tonic-gate miscpid_head = mp; 3209*7c478bd9Sstevel@tonic-gate } 3210*7c478bd9Sstevel@tonic-gate 3211*7c478bd9Sstevel@tonic-gate static int 3212*7c478bd9Sstevel@tonic-gate miscpid_delete(pid_t pid) 3213*7c478bd9Sstevel@tonic-gate { 3214*7c478bd9Sstevel@tonic-gate struct miscpid *mp, *omp; 3215*7c478bd9Sstevel@tonic-gate int found = 0; 3216*7c478bd9Sstevel@tonic-gate 3217*7c478bd9Sstevel@tonic-gate omp = NULL; 3218*7c478bd9Sstevel@tonic-gate for (mp = miscpid_head; mp != NULL; mp = mp->next) { 3219*7c478bd9Sstevel@tonic-gate if (mp->pid == pid) { 3220*7c478bd9Sstevel@tonic-gate found = 1; 3221*7c478bd9Sstevel@tonic-gate break; 3222*7c478bd9Sstevel@tonic-gate } 3223*7c478bd9Sstevel@tonic-gate omp = mp; 3224*7c478bd9Sstevel@tonic-gate } 3225*7c478bd9Sstevel@tonic-gate if (found) { 3226*7c478bd9Sstevel@tonic-gate if (omp != NULL) 3227*7c478bd9Sstevel@tonic-gate omp->next = mp->next; 3228*7c478bd9Sstevel@tonic-gate else 3229*7c478bd9Sstevel@tonic-gate miscpid_head = NULL; 3230*7c478bd9Sstevel@tonic-gate free(mp); 3231*7c478bd9Sstevel@tonic-gate } 3232*7c478bd9Sstevel@tonic-gate return (found); 3233*7c478bd9Sstevel@tonic-gate } 3234*7c478bd9Sstevel@tonic-gate 3235*7c478bd9Sstevel@tonic-gate /* 3236*7c478bd9Sstevel@tonic-gate * Establish contract terms such that all children are in abandoned 3237*7c478bd9Sstevel@tonic-gate * process contracts. 3238*7c478bd9Sstevel@tonic-gate */ 3239*7c478bd9Sstevel@tonic-gate static int 3240*7c478bd9Sstevel@tonic-gate contract_set_template() 3241*7c478bd9Sstevel@tonic-gate { 3242*7c478bd9Sstevel@tonic-gate int fd; 3243*7c478bd9Sstevel@tonic-gate 3244*7c478bd9Sstevel@tonic-gate if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) < 0) 3245*7c478bd9Sstevel@tonic-gate crabort("cannot open process contract template", 3246*7c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 3247*7c478bd9Sstevel@tonic-gate 3248*7c478bd9Sstevel@tonic-gate if (ct_pr_tmpl_set_param(fd, 0) || 3249*7c478bd9Sstevel@tonic-gate ct_tmpl_set_informative(fd, 0) || 3250*7c478bd9Sstevel@tonic-gate ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR)) 3251*7c478bd9Sstevel@tonic-gate crabort("cannot establish contract template terms", 3252*7c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 3253*7c478bd9Sstevel@tonic-gate 3254*7c478bd9Sstevel@tonic-gate if (ct_tmpl_activate(fd)) 3255*7c478bd9Sstevel@tonic-gate crabort("cannot activate contract template", 3256*7c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 3257*7c478bd9Sstevel@tonic-gate 3258*7c478bd9Sstevel@tonic-gate (void) close(fd); 3259*7c478bd9Sstevel@tonic-gate } 3260*7c478bd9Sstevel@tonic-gate 3261*7c478bd9Sstevel@tonic-gate /* 3262*7c478bd9Sstevel@tonic-gate * Clear active process contract template. 3263*7c478bd9Sstevel@tonic-gate */ 3264*7c478bd9Sstevel@tonic-gate static int 3265*7c478bd9Sstevel@tonic-gate contract_clear_template() 3266*7c478bd9Sstevel@tonic-gate { 3267*7c478bd9Sstevel@tonic-gate int fd; 3268*7c478bd9Sstevel@tonic-gate 3269*7c478bd9Sstevel@tonic-gate if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) < 0) 3270*7c478bd9Sstevel@tonic-gate crabort("cannot open process contract template", 3271*7c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 3272*7c478bd9Sstevel@tonic-gate 3273*7c478bd9Sstevel@tonic-gate if (ct_tmpl_clear(fd)) 3274*7c478bd9Sstevel@tonic-gate crabort("cannot clear contract template", 3275*7c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 3276*7c478bd9Sstevel@tonic-gate 3277*7c478bd9Sstevel@tonic-gate (void) close(fd); 3278*7c478bd9Sstevel@tonic-gate } 3279*7c478bd9Sstevel@tonic-gate 3280*7c478bd9Sstevel@tonic-gate /* 3281*7c478bd9Sstevel@tonic-gate * Abandon latest process contract unconditionally. If we have leaked [some 3282*7c478bd9Sstevel@tonic-gate * critical amount], exit such that the kernel reaps our contracts. 3283*7c478bd9Sstevel@tonic-gate */ 3284*7c478bd9Sstevel@tonic-gate static void 3285*7c478bd9Sstevel@tonic-gate contract_abandon_latest(pid_t pid) 3286*7c478bd9Sstevel@tonic-gate { 3287*7c478bd9Sstevel@tonic-gate int r; 3288*7c478bd9Sstevel@tonic-gate ctid_t id; 3289*7c478bd9Sstevel@tonic-gate static uint_t cts_lost; 3290*7c478bd9Sstevel@tonic-gate 3291*7c478bd9Sstevel@tonic-gate if (cts_lost > MAX_LOST_CONTRACTS) 3292*7c478bd9Sstevel@tonic-gate crabort("repeated failure to abandon contracts", 3293*7c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 3294*7c478bd9Sstevel@tonic-gate 3295*7c478bd9Sstevel@tonic-gate if (r = contract_latest(&id)) { 3296*7c478bd9Sstevel@tonic-gate if (pid == 0) 3297*7c478bd9Sstevel@tonic-gate msg("could not obtain latest contract from " 3298*7c478bd9Sstevel@tonic-gate "popen(3C): %s", strerror(r)); 3299*7c478bd9Sstevel@tonic-gate else 3300*7c478bd9Sstevel@tonic-gate msg("could not obtain latest contract for " 3301*7c478bd9Sstevel@tonic-gate "PID %ld: %s", pid, strerror(r)); 3302*7c478bd9Sstevel@tonic-gate cts_lost++; 3303*7c478bd9Sstevel@tonic-gate return; 3304*7c478bd9Sstevel@tonic-gate } 3305*7c478bd9Sstevel@tonic-gate 3306*7c478bd9Sstevel@tonic-gate if (r = contract_abandon_id(id)) { 3307*7c478bd9Sstevel@tonic-gate msg("could not abandon latest contract %ld: %s", id, 3308*7c478bd9Sstevel@tonic-gate strerror(r)); 3309*7c478bd9Sstevel@tonic-gate cts_lost++; 3310*7c478bd9Sstevel@tonic-gate return; 3311*7c478bd9Sstevel@tonic-gate } 3312*7c478bd9Sstevel@tonic-gate } 3313