17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54c4c9110Sbasabi * Common Development and Distribution License (the "License"). 64c4c9110Sbasabi * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2263d5d94cSjc * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 277c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* Copyright (c) 1987, 1988 Microsoft Corporation */ 307c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #ifdef lint 337c478bd9Sstevel@tonic-gate /* make lint happy */ 347c478bd9Sstevel@tonic-gate #define __EXTENSIONS__ 357c478bd9Sstevel@tonic-gate #endif 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/contract/process.h> 387c478bd9Sstevel@tonic-gate #include <sys/ctfs.h> 397c478bd9Sstevel@tonic-gate #include <sys/param.h> 407c478bd9Sstevel@tonic-gate #include <sys/resource.h> 417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 427c478bd9Sstevel@tonic-gate #include <sys/task.h> 437c478bd9Sstevel@tonic-gate #include <sys/time.h> 447c478bd9Sstevel@tonic-gate #include <sys/types.h> 457c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 467c478bd9Sstevel@tonic-gate #include <sys/wait.h> 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include <security/pam_appl.h> 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate #include <alloca.h> 517c478bd9Sstevel@tonic-gate #include <ctype.h> 527c478bd9Sstevel@tonic-gate #include <deflt.h> 537c478bd9Sstevel@tonic-gate #include <dirent.h> 547c478bd9Sstevel@tonic-gate #include <errno.h> 557c478bd9Sstevel@tonic-gate #include <fcntl.h> 567c478bd9Sstevel@tonic-gate #include <grp.h> 577c478bd9Sstevel@tonic-gate #include <libcontract.h> 587c478bd9Sstevel@tonic-gate #include <libcontract_priv.h> 597c478bd9Sstevel@tonic-gate #include <limits.h> 607c478bd9Sstevel@tonic-gate #include <locale.h> 617c478bd9Sstevel@tonic-gate #include <poll.h> 627c478bd9Sstevel@tonic-gate #include <project.h> 637c478bd9Sstevel@tonic-gate #include <pwd.h> 647c478bd9Sstevel@tonic-gate #include <signal.h> 657c478bd9Sstevel@tonic-gate #include <stdarg.h> 667c478bd9Sstevel@tonic-gate #include <stdio.h> 677c478bd9Sstevel@tonic-gate #include <stdlib.h> 687c478bd9Sstevel@tonic-gate #include <string.h> 697c478bd9Sstevel@tonic-gate #include <stropts.h> 707c478bd9Sstevel@tonic-gate #include <time.h> 717c478bd9Sstevel@tonic-gate #include <unistd.h> 72*5b08e637SChris Gerhard #include <libzoneinfo.h> 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate #include "cron.h" 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * #define DEBUG 787c478bd9Sstevel@tonic-gate */ 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate #define MAIL "/usr/bin/mail" /* mail program to use */ 817c478bd9Sstevel@tonic-gate #define CONSOLE "/dev/console" /* where messages go when cron dies */ 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate #define TMPINFILE "/tmp/crinXXXXXX" /* file to put stdin in for cmd */ 847c478bd9Sstevel@tonic-gate #define TMPDIR "/tmp" 857c478bd9Sstevel@tonic-gate #define PFX "crout" 867c478bd9Sstevel@tonic-gate #define TMPOUTFILE "/tmp/croutXXXXXX" /* file to place stdout, stderr */ 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate #define INMODE 00400 /* mode for stdin file */ 897c478bd9Sstevel@tonic-gate #define OUTMODE 00600 /* mode for stdout file */ 907c478bd9Sstevel@tonic-gate #define ISUID S_ISUID /* mode for verifing at jobs */ 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate #define INFINITY 2147483647L /* upper bound on time */ 937c478bd9Sstevel@tonic-gate #define CUSHION 180L 947c478bd9Sstevel@tonic-gate #define ZOMB 100 /* proc slot used for mailing output */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate #define JOBF 'j' 977c478bd9Sstevel@tonic-gate #define NICEF 'n' 987c478bd9Sstevel@tonic-gate #define USERF 'u' 997c478bd9Sstevel@tonic-gate #define WAITF 'w' 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate #define BCHAR '>' 1027c478bd9Sstevel@tonic-gate #define ECHAR '<' 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate #define DEFAULT 0 1057c478bd9Sstevel@tonic-gate #define LOAD 1 1067c478bd9Sstevel@tonic-gate #define QBUFSIZ 80 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* Defined actions for crabort() routine */ 1097c478bd9Sstevel@tonic-gate #define NO_ACTION 000 1107c478bd9Sstevel@tonic-gate #define REMOVE_FIFO 001 1117c478bd9Sstevel@tonic-gate #define CONSOLE_MSG 002 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate #define BADCD "can't change directory to the crontab directory." 1147c478bd9Sstevel@tonic-gate #define NOREADDIR "can't read the crontab directory." 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate #define BADJOBOPEN "unable to read your at job." 1177c478bd9Sstevel@tonic-gate #define BADSHELL "because your login shell \ 1187c478bd9Sstevel@tonic-gate isn't /usr/bin/sh, you can't use cron." 1197c478bd9Sstevel@tonic-gate 1204c4c9110Sbasabi #define BADSTAT "can't access your crontab or at-job file. Resubmit it." 1217c478bd9Sstevel@tonic-gate #define BADPROJID "can't set project id for your job." 122*5b08e637SChris Gerhard #define CANTCDHOME "can't change directory to %s.\ 1237c478bd9Sstevel@tonic-gate \nYour commands will not be executed." 124*5b08e637SChris Gerhard #define CANTEXECSH "unable to exec the shell, %s, for one of your \ 125*5b08e637SChris Gerhard commands." 126*5b08e637SChris Gerhard #define CANT_STR_LEN (sizeof (CANTEXECSH) > sizeof (CANTCDHOME) ? \ 127*5b08e637SChris Gerhard sizeof (CANTEXECSH) : sizeof (CANTCDHOME)) 1287c478bd9Sstevel@tonic-gate #define NOREAD "can't read your crontab file. Resubmit it." 1294c4c9110Sbasabi #define BADTYPE "crontab or at-job file is not a regular file.\n" 1307c478bd9Sstevel@tonic-gate #define NOSTDIN "unable to create a standard input file for \ 1317c478bd9Sstevel@tonic-gate one of your crontab commands. \ 1327c478bd9Sstevel@tonic-gate \nThat command was not executed." 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate #define NOTALLOWED "you are not authorized to use cron. Sorry." 1357c478bd9Sstevel@tonic-gate #define STDERRMSG "\n\n********************************************\ 1367c478bd9Sstevel@tonic-gate *****\nCron: The previous message is the \ 1377c478bd9Sstevel@tonic-gate standard output and standard error \ 1387c478bd9Sstevel@tonic-gate \nof one of your cron commands.\n" 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate #define STDOUTERR "one of your commands generated output or errors, \ 1417c478bd9Sstevel@tonic-gate but cron was unable to mail you this output.\ 1427c478bd9Sstevel@tonic-gate \nRemember to redirect standard output and standard \ 1437c478bd9Sstevel@tonic-gate error for each of your commands." 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate #define CLOCK_DRIFT "clock time drifted backwards after event!\n" 1467c478bd9Sstevel@tonic-gate #define PIDERR "unexpected pid returned %d (ignored)" 1477c478bd9Sstevel@tonic-gate #define CRONTABERR "Subject: Your crontab file has an error in it\n\n" 1487c478bd9Sstevel@tonic-gate #define CRONOUT "Subject: Output from \"cron\" command\n\n" 1497c478bd9Sstevel@tonic-gate #define MALLOCERR "out of space, cannot create new string\n" 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate #define DIDFORK didfork 1527c478bd9Sstevel@tonic-gate #define NOFORK !didfork 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate #define MAILBUFLEN (8*1024) 1557c478bd9Sstevel@tonic-gate #define LINELIMIT 80 1567c478bd9Sstevel@tonic-gate #define MAILBINITFREE (MAILBUFLEN - (sizeof (cte_intro) - 1) \ 1577c478bd9Sstevel@tonic-gate - (sizeof (cte_trail1) - 1) - (sizeof (cte_trail2) - 1) - 1) 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate #define ERR_CRONTABENT 0 /* error in crontab file entry */ 1607c478bd9Sstevel@tonic-gate #define ERR_UNIXERR 1 /* error in some system call */ 1617c478bd9Sstevel@tonic-gate #define ERR_CANTEXECCRON 2 /* error setting up "cron" job environment */ 1627c478bd9Sstevel@tonic-gate #define ERR_CANTEXECAT 3 /* error setting up "at" job environment */ 1634c4c9110Sbasabi #define ERR_NOTREG 4 /* error not a regular file */ 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate #define PROJECT "project=" 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate #define MAX_LOST_CONTRACTS 2048 /* reset if this many failed abandons */ 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate #define FORMAT "%a %b %e %H:%M:%S %Y" 1707c478bd9Sstevel@tonic-gate static char timebuf[80]; 1717c478bd9Sstevel@tonic-gate 172*5b08e637SChris Gerhard struct shared { 173*5b08e637SChris Gerhard int count; /* usage count */ 174*5b08e637SChris Gerhard void (*free)(void *obj); /* routine that will free obj */ 175*5b08e637SChris Gerhard void *obj; /* object */ 176*5b08e637SChris Gerhard }; 177*5b08e637SChris Gerhard 1787c478bd9Sstevel@tonic-gate struct event { 1797c478bd9Sstevel@tonic-gate time_t time; /* time of the event */ 1807c478bd9Sstevel@tonic-gate short etype; /* what type of event; 0=cron, 1=at */ 1817c478bd9Sstevel@tonic-gate char *cmd; /* command for cron, job name for at */ 1827c478bd9Sstevel@tonic-gate struct usr *u; /* ptr to the owner (usr) of this event */ 1837c478bd9Sstevel@tonic-gate struct event *link; /* ptr to another event for this user */ 1847c478bd9Sstevel@tonic-gate union { 1857c478bd9Sstevel@tonic-gate struct { /* for crontab events */ 1867c478bd9Sstevel@tonic-gate char *minute; /* (these */ 1877c478bd9Sstevel@tonic-gate char *hour; /* fields */ 1887c478bd9Sstevel@tonic-gate char *daymon; /* are */ 1897c478bd9Sstevel@tonic-gate char *month; /* from */ 1907c478bd9Sstevel@tonic-gate char *dayweek; /* crontab) */ 1917c478bd9Sstevel@tonic-gate char *input; /* ptr to stdin */ 192*5b08e637SChris Gerhard struct shared *tz; /* timezone of this event */ 193*5b08e637SChris Gerhard struct shared *home; /* directory for this event */ 194*5b08e637SChris Gerhard struct shared *shell; /* shell for this event */ 1957c478bd9Sstevel@tonic-gate } ct; 1967c478bd9Sstevel@tonic-gate struct { /* for at events */ 1977c478bd9Sstevel@tonic-gate short exists; /* for revising at events */ 1987c478bd9Sstevel@tonic-gate int eventid; /* for el_remove-ing at events */ 1997c478bd9Sstevel@tonic-gate } at; 2007c478bd9Sstevel@tonic-gate } of; 2017c478bd9Sstevel@tonic-gate }; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate struct usr { 2047c478bd9Sstevel@tonic-gate char *name; /* name of user (e.g. "root") */ 2057c478bd9Sstevel@tonic-gate char *home; /* home directory for user */ 2067c478bd9Sstevel@tonic-gate uid_t uid; /* user id */ 2077c478bd9Sstevel@tonic-gate gid_t gid; /* group id */ 2087c478bd9Sstevel@tonic-gate int aruncnt; /* counter for running jobs per uid */ 2097c478bd9Sstevel@tonic-gate int cruncnt; /* counter for running cron jobs per uid */ 2107c478bd9Sstevel@tonic-gate int ctid; /* for el_remove-ing crontab events */ 2117c478bd9Sstevel@tonic-gate short ctexists; /* for revising crontab events */ 2127c478bd9Sstevel@tonic-gate struct event *ctevents; /* list of this usr's crontab events */ 2137c478bd9Sstevel@tonic-gate struct event *atevents; /* list of this usr's at events */ 2147c478bd9Sstevel@tonic-gate struct usr *nextusr; 2157c478bd9Sstevel@tonic-gate }; /* ptr to next user */ 2167c478bd9Sstevel@tonic-gate 2177c478bd9Sstevel@tonic-gate static struct queue 2187c478bd9Sstevel@tonic-gate { 2197c478bd9Sstevel@tonic-gate int njob; /* limit */ 2207c478bd9Sstevel@tonic-gate int nice; /* nice for execution */ 2217c478bd9Sstevel@tonic-gate int nwait; /* wait time to next execution attempt */ 2227c478bd9Sstevel@tonic-gate int nrun; /* number running */ 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate qd = {100, 2, 60}, /* default values for queue defs */ 2257c478bd9Sstevel@tonic-gate qt[NQUEUE]; 2267c478bd9Sstevel@tonic-gate static struct queue qq; 2277c478bd9Sstevel@tonic-gate 2289f163834Sbasabi static struct runinfo 2297c478bd9Sstevel@tonic-gate { 2307c478bd9Sstevel@tonic-gate pid_t pid; 2317c478bd9Sstevel@tonic-gate short que; 2327c478bd9Sstevel@tonic-gate struct usr *rusr; /* pointer to usr struct */ 2337c478bd9Sstevel@tonic-gate char *outfile; /* file where stdout & stderr are trapped */ 2347c478bd9Sstevel@tonic-gate short jobtype; /* what type of event: 0=cron, 1=at */ 2357c478bd9Sstevel@tonic-gate char *jobname; /* command for "cron", jobname for "at" */ 2367c478bd9Sstevel@tonic-gate int mailwhendone; /* 1 = send mail even if no ouptut */ 2379f163834Sbasabi struct runinfo *next; 2389f163834Sbasabi } *rthead; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate static struct miscpid { 2417c478bd9Sstevel@tonic-gate pid_t pid; 2427c478bd9Sstevel@tonic-gate struct miscpid *next; 2437c478bd9Sstevel@tonic-gate } *miscpid_head; 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate static pid_t cron_pid; /* own pid */ 2467c478bd9Sstevel@tonic-gate static char didfork = 0; /* flag to see if I'm process group leader */ 2477c478bd9Sstevel@tonic-gate static int msgfd; /* file descriptor for fifo queue */ 2487c478bd9Sstevel@tonic-gate static int ecid = 1; /* event class id for el_remove(); MUST be set to 1 */ 2497c478bd9Sstevel@tonic-gate static int delayed; /* is job being rescheduled or did it run first time */ 2507c478bd9Sstevel@tonic-gate static int cwd; /* current working directory */ 2517c478bd9Sstevel@tonic-gate static struct event *next_event; /* the next event to execute */ 2527c478bd9Sstevel@tonic-gate static struct usr *uhead; /* ptr to the list of users */ 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* Variables for error handling at reading crontabs. */ 2557c478bd9Sstevel@tonic-gate static char cte_intro[] = "Line(s) with errors:\n\n"; 2567c478bd9Sstevel@tonic-gate static char cte_trail1[] = "\nMax number of errors encountered."; 2577c478bd9Sstevel@tonic-gate static char cte_trail2[] = " Evaluation of crontab aborted.\n"; 2587c478bd9Sstevel@tonic-gate static int cte_free = MAILBINITFREE; /* Free buffer space */ 2597c478bd9Sstevel@tonic-gate static char *cte_text = NULL; /* Text buffer pointer */ 2607c478bd9Sstevel@tonic-gate static char *cte_lp; /* Next free line in cte_text */ 2617c478bd9Sstevel@tonic-gate static int cte_nvalid; /* Valid lines found */ 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate /* user's default environment for the shell */ 2647c478bd9Sstevel@tonic-gate #define ROOTPATH "PATH=/usr/sbin:/usr/bin" 2657c478bd9Sstevel@tonic-gate #define NONROOTPATH "PATH=/usr/bin:" 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate static char *Def_supath = NULL; 2687c478bd9Sstevel@tonic-gate static char *Def_path = NULL; 2697c478bd9Sstevel@tonic-gate static char path[LINE_MAX] = "PATH="; 2707c478bd9Sstevel@tonic-gate static char supath[LINE_MAX] = "PATH="; 271*5b08e637SChris Gerhard static char homedir[LINE_MAX] = ENV_HOME; 2727c478bd9Sstevel@tonic-gate static char logname[LINE_MAX] = "LOGNAME="; 273*5b08e637SChris Gerhard static char tzone[LINE_MAX] = ENV_TZ; 2747c478bd9Sstevel@tonic-gate static char *envinit[] = { 2757c478bd9Sstevel@tonic-gate homedir, 2767c478bd9Sstevel@tonic-gate logname, 2777c478bd9Sstevel@tonic-gate ROOTPATH, 2787c478bd9Sstevel@tonic-gate "SHELL=/usr/bin/sh", 2797c478bd9Sstevel@tonic-gate tzone, 2807c478bd9Sstevel@tonic-gate NULL 2817c478bd9Sstevel@tonic-gate }; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate extern char **environ; 2847c478bd9Sstevel@tonic-gate 2857c478bd9Sstevel@tonic-gate #define DEFTZ "GMT" 2867c478bd9Sstevel@tonic-gate static int log = 0; 2877c478bd9Sstevel@tonic-gate static char hzname[10]; 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate static void cronend(int); 2907c478bd9Sstevel@tonic-gate static void thaw_handler(int); 2917c478bd9Sstevel@tonic-gate static void child_handler(int); 2927c478bd9Sstevel@tonic-gate static void child_sigreset(void); 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate static void mod_ctab(char *, time_t); 2957c478bd9Sstevel@tonic-gate static void mod_atjob(char *, time_t); 2967c478bd9Sstevel@tonic-gate static void add_atevent(struct usr *, char *, time_t, int); 2977c478bd9Sstevel@tonic-gate static void rm_ctevents(struct usr *); 2987c478bd9Sstevel@tonic-gate static void cleanup(struct runinfo *rn, int r); 2997c478bd9Sstevel@tonic-gate static void crabort(char *, int); 3007c478bd9Sstevel@tonic-gate static void msg(char *fmt, ...); 301e2553d68SSerge Dussud static void ignore_msg(char *, char *, struct event *); 3027c478bd9Sstevel@tonic-gate static void logit(int, struct runinfo *, int); 3037c478bd9Sstevel@tonic-gate static void parsqdef(char *); 3047c478bd9Sstevel@tonic-gate static void defaults(); 3057c478bd9Sstevel@tonic-gate static void initialize(int); 3067c478bd9Sstevel@tonic-gate static void quedefs(int); 3077c478bd9Sstevel@tonic-gate static int idle(long); 3087c478bd9Sstevel@tonic-gate static struct usr *find_usr(char *); 3097c478bd9Sstevel@tonic-gate static int ex(struct event *e); 3104c4c9110Sbasabi static void read_dirs(int); 3117c478bd9Sstevel@tonic-gate static void mail(char *, char *, int); 3127c478bd9Sstevel@tonic-gate static char *next_field(int, int); 3137c478bd9Sstevel@tonic-gate static void readcron(struct usr *, time_t); 3147c478bd9Sstevel@tonic-gate static int next_ge(int, char *); 3157c478bd9Sstevel@tonic-gate static void free_if_unused(struct usr *); 3167c478bd9Sstevel@tonic-gate static void del_atjob(char *, char *); 3177c478bd9Sstevel@tonic-gate static void del_ctab(char *); 3187c478bd9Sstevel@tonic-gate static void resched(int); 3197c478bd9Sstevel@tonic-gate static int msg_wait(long); 3207c478bd9Sstevel@tonic-gate static struct runinfo *rinfo_get(pid_t); 3217c478bd9Sstevel@tonic-gate static void rinfo_free(struct runinfo *rp); 3227c478bd9Sstevel@tonic-gate static void mail_result(struct usr *p, struct runinfo *pr, size_t filesize); 3237c478bd9Sstevel@tonic-gate static time_t next_time(struct event *, time_t); 3247c478bd9Sstevel@tonic-gate static time_t get_switching_time(int, time_t); 3257c478bd9Sstevel@tonic-gate static time_t xmktime(struct tm *); 3267c478bd9Sstevel@tonic-gate static void process_msg(struct message *, time_t); 3277c478bd9Sstevel@tonic-gate static void reap_child(void); 3287c478bd9Sstevel@tonic-gate static void miscpid_insert(pid_t); 3297c478bd9Sstevel@tonic-gate static int miscpid_delete(pid_t); 330032624d5Sbasabi static void contract_set_template(void); 331032624d5Sbasabi static void contract_clear_template(void); 3327c478bd9Sstevel@tonic-gate static void contract_abandon_latest(pid_t); 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate static void cte_init(void); 3357c478bd9Sstevel@tonic-gate static void cte_add(int, char *); 3367c478bd9Sstevel@tonic-gate static void cte_valid(void); 3377c478bd9Sstevel@tonic-gate static int cte_istoomany(void); 3387c478bd9Sstevel@tonic-gate static void cte_sendmail(char *); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate static int set_user_cred(const struct usr *, struct project *); 3417c478bd9Sstevel@tonic-gate 342*5b08e637SChris Gerhard static struct shared *create_shared_str(char *str); 343*5b08e637SChris Gerhard static struct shared *dup_shared(struct shared *obj); 344*5b08e637SChris Gerhard static void rel_shared(struct shared *obj); 345*5b08e637SChris Gerhard static void *get_obj(struct shared *obj); 3467c478bd9Sstevel@tonic-gate /* 3477c478bd9Sstevel@tonic-gate * last_time is set immediately prior to exection of an event (via ex()) 3487c478bd9Sstevel@tonic-gate * to indicate the last time an event was executed. This was (surely) 3497c478bd9Sstevel@tonic-gate * it's original intended use. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate static time_t last_time, init_time, t_old; 352e2553d68SSerge Dussud static int reset_needed; /* set to 1 when cron(1M) needs to re-initialize */ 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate static int accept_sigcld, notifypipe[2]; 3557c478bd9Sstevel@tonic-gate static sigset_t defmask, childmask; 3567c478bd9Sstevel@tonic-gate 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * BSM hooks 3597c478bd9Sstevel@tonic-gate */ 3607c478bd9Sstevel@tonic-gate extern int audit_cron_session(char *, char *, uid_t, gid_t, char *); 3617c478bd9Sstevel@tonic-gate extern void audit_cron_new_job(char *, int, void *); 3627c478bd9Sstevel@tonic-gate extern void audit_cron_bad_user(char *); 3637c478bd9Sstevel@tonic-gate extern void audit_cron_user_acct_expired(char *); 3647c478bd9Sstevel@tonic-gate extern int audit_cron_create_anc_file(char *, char *, char *, uid_t); 3657c478bd9Sstevel@tonic-gate extern int audit_cron_delete_anc_file(char *, char *); 3667c478bd9Sstevel@tonic-gate extern int audit_cron_is_anc_name(char *); 3677c478bd9Sstevel@tonic-gate extern int audit_cron_mode(); 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate static int cron_conv(int, struct pam_message **, 3707c478bd9Sstevel@tonic-gate struct pam_response **, void *); 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate static struct pam_conv pam_conv = {cron_conv, NULL}; 3737c478bd9Sstevel@tonic-gate static pam_handle_t *pamh; /* Authentication handle */ 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate /* 3767c478bd9Sstevel@tonic-gate * Function to help check a user's credentials. 3777c478bd9Sstevel@tonic-gate */ 3787c478bd9Sstevel@tonic-gate 3794c4c9110Sbasabi static int verify_user_cred(struct usr *u); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * Values returned by verify_user_cred and set_user_cred: 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate #define VUC_OK 0 3867c478bd9Sstevel@tonic-gate #define VUC_BADUSER 1 3877c478bd9Sstevel@tonic-gate #define VUC_NOTINGROUP 2 3887c478bd9Sstevel@tonic-gate #define VUC_EXPIRED 3 3897c478bd9Sstevel@tonic-gate #define VUC_NEW_AUTH 4 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * Modes of process_anc_files function 3937c478bd9Sstevel@tonic-gate */ 3947c478bd9Sstevel@tonic-gate #define CRON_ANC_DELETE 1 3957c478bd9Sstevel@tonic-gate #define CRON_ANC_CREATE 0 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Functions to remove a user or job completely from the running database. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate static void clean_out_atjobs(struct usr *u); 4017c478bd9Sstevel@tonic-gate static void clean_out_ctab(struct usr *u); 4027c478bd9Sstevel@tonic-gate static void clean_out_user(struct usr *u); 4037c478bd9Sstevel@tonic-gate static void cron_unlink(char *name); 4047c478bd9Sstevel@tonic-gate static void process_anc_files(int); 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* 4077c478bd9Sstevel@tonic-gate * functions in elm.c 4087c478bd9Sstevel@tonic-gate */ 4097c478bd9Sstevel@tonic-gate extern void el_init(int, time_t, time_t, int); 410e2553d68SSerge Dussud extern int el_add(void *, time_t, int); 4117c478bd9Sstevel@tonic-gate extern void el_remove(int, int); 4127c478bd9Sstevel@tonic-gate extern int el_empty(void); 4137c478bd9Sstevel@tonic-gate extern void *el_first(void); 4147c478bd9Sstevel@tonic-gate extern void el_delete(void); 4157c478bd9Sstevel@tonic-gate 4164c4c9110Sbasabi static int valid_entry(char *, int); 4174c4c9110Sbasabi static struct usr *create_ulist(char *, int); 4184c4c9110Sbasabi static void init_cronevent(char *, int); 4194c4c9110Sbasabi static void init_atevent(char *, time_t, int, int); 4204c4c9110Sbasabi static void update_atevent(struct usr *, char *, time_t, int); 4214c4c9110Sbasabi 4227c478bd9Sstevel@tonic-gate int 4237c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate time_t t; 4267c478bd9Sstevel@tonic-gate time_t ne_time; /* amt of time until next event execution */ 4277c478bd9Sstevel@tonic-gate time_t newtime, lastmtime = 0L; 4287c478bd9Sstevel@tonic-gate struct usr *u; 4297c478bd9Sstevel@tonic-gate struct event *e, *e2, *eprev; 4307c478bd9Sstevel@tonic-gate struct stat buf; 4317c478bd9Sstevel@tonic-gate pid_t rfork; 4327c478bd9Sstevel@tonic-gate struct sigaction act; 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate /* 435e2553d68SSerge Dussud * reset_needed is set to 1 whenever el_add() finds out that a cron 436e2553d68SSerge Dussud * job is scheduled to be run before the time when cron(1M) daemon 437e2553d68SSerge Dussud * initialized. 438e2553d68SSerge Dussud * Other cases where a reset is needed is when ex() finds that the 439e2553d68SSerge Dussud * event to be executed is being run at the wrong time, or when idle() 440e2553d68SSerge Dussud * determines that time was reset. 4417c478bd9Sstevel@tonic-gate * We immediately return to the top of the while (TRUE) loop in 442e2553d68SSerge Dussud * main() where the event list is cleared and rebuilt, and reset_needed 4437c478bd9Sstevel@tonic-gate * is set back to 0. 4447c478bd9Sstevel@tonic-gate */ 445e2553d68SSerge Dussud reset_needed = 0; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * Only the privileged user can run this command. 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate if (getuid() != 0) 4517c478bd9Sstevel@tonic-gate crabort(NOTALLOWED, 0); 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate begin: 4547c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 4557c478bd9Sstevel@tonic-gate /* fork unless 'nofork' is specified */ 4567c478bd9Sstevel@tonic-gate if ((argc <= 1) || (strcmp(argv[1], "nofork"))) { 4577c478bd9Sstevel@tonic-gate if (rfork = fork()) { 4587c478bd9Sstevel@tonic-gate if (rfork == (pid_t)-1) { 4597c478bd9Sstevel@tonic-gate (void) sleep(30); 4607c478bd9Sstevel@tonic-gate goto begin; 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate return (0); 4637c478bd9Sstevel@tonic-gate } 4647c478bd9Sstevel@tonic-gate didfork++; 4657c478bd9Sstevel@tonic-gate (void) setpgrp(); /* detach cron from console */ 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate (void) umask(022); 4697c478bd9Sstevel@tonic-gate (void) signal(SIGHUP, SIG_IGN); 4707c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_IGN); 4717c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_IGN); 4727c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, cronend); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate defaults(); 4757c478bd9Sstevel@tonic-gate initialize(1); 4767c478bd9Sstevel@tonic-gate quedefs(DEFAULT); /* load default queue definitions */ 4777c478bd9Sstevel@tonic-gate cron_pid = getpid(); 4787c478bd9Sstevel@tonic-gate msg("*** cron started *** pid = %d", cron_pid); 4797c478bd9Sstevel@tonic-gate (void) sigset(SIGTHAW, thaw_handler); 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * setup SIGCLD handler/mask 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate act.sa_handler = child_handler; 4847c478bd9Sstevel@tonic-gate act.sa_flags = 0; 4857c478bd9Sstevel@tonic-gate (void) sigemptyset(&act.sa_mask); 4867c478bd9Sstevel@tonic-gate (void) sigaddset(&act.sa_mask, SIGCLD); 4877c478bd9Sstevel@tonic-gate (void) sigaction(SIGCLD, &act, NULL); 4887c478bd9Sstevel@tonic-gate (void) sigemptyset(&childmask); 4897c478bd9Sstevel@tonic-gate (void) sigaddset(&childmask, SIGCLD); 4907c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &childmask, &defmask); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate if (pipe(notifypipe) != 0) { 4937c478bd9Sstevel@tonic-gate crabort("cannot create pipe", REMOVE_FIFO|CONSOLE_MSG); 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate /* 4967c478bd9Sstevel@tonic-gate * will set O_NONBLOCK, so that the write() from child_handler 4977c478bd9Sstevel@tonic-gate * never be blocked. 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate (void) fcntl(notifypipe[0], F_SETFL, O_WRONLY|O_NONBLOCK); 5007c478bd9Sstevel@tonic-gate 501e2553d68SSerge Dussud t_old = init_time; 5027c478bd9Sstevel@tonic-gate last_time = t_old; 5037c478bd9Sstevel@tonic-gate for (;;) { /* MAIN LOOP */ 5047c478bd9Sstevel@tonic-gate t = time(NULL); 505e2553d68SSerge Dussud if ((t_old > t) || (t-last_time > CUSHION) || reset_needed) { 506e2553d68SSerge Dussud reset_needed = 0; 5077c478bd9Sstevel@tonic-gate /* the time was set backwards or forward */ 508e2553d68SSerge Dussud msg("time was reset, re-initializing"); 5097c478bd9Sstevel@tonic-gate el_delete(); 5107c478bd9Sstevel@tonic-gate u = uhead; 5117c478bd9Sstevel@tonic-gate while (u != NULL) { 5127c478bd9Sstevel@tonic-gate rm_ctevents(u); 5137c478bd9Sstevel@tonic-gate e = u->atevents; 5147c478bd9Sstevel@tonic-gate while (e != NULL) { 5157c478bd9Sstevel@tonic-gate free(e->cmd); 5167c478bd9Sstevel@tonic-gate e2 = e->link; 5177c478bd9Sstevel@tonic-gate free(e); 5187c478bd9Sstevel@tonic-gate e = e2; 5197c478bd9Sstevel@tonic-gate } 5207c478bd9Sstevel@tonic-gate u->atevents = NULL; 5217c478bd9Sstevel@tonic-gate u = u->nextusr; 5227c478bd9Sstevel@tonic-gate } 5237c478bd9Sstevel@tonic-gate (void) close(msgfd); 5247c478bd9Sstevel@tonic-gate initialize(0); 5257c478bd9Sstevel@tonic-gate t = time(NULL); 5267c478bd9Sstevel@tonic-gate last_time = t; 527e2553d68SSerge Dussud /* 528e2553d68SSerge Dussud * reset_needed might have been set in the functions 529e2553d68SSerge Dussud * call path from initialize() 530e2553d68SSerge Dussud */ 531e2553d68SSerge Dussud if (reset_needed) { 532e2553d68SSerge Dussud continue; 533e2553d68SSerge Dussud } 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate t_old = t; 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if (next_event == NULL && !el_empty()) { 5387c478bd9Sstevel@tonic-gate next_event = (struct event *)el_first(); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate if (next_event == NULL) { 5417c478bd9Sstevel@tonic-gate ne_time = INFINITY; 5427c478bd9Sstevel@tonic-gate } else { 5437c478bd9Sstevel@tonic-gate ne_time = next_event->time - t; 5447c478bd9Sstevel@tonic-gate #ifdef DEBUG 5457c478bd9Sstevel@tonic-gate cftime(timebuf, "%C", &next_event->time); 5467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "next_time=%ld %s\n", 5474c4c9110Sbasabi next_event->time, timebuf); 5487c478bd9Sstevel@tonic-gate #endif 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate if (ne_time > 0) { 551e2553d68SSerge Dussud /* 552e2553d68SSerge Dussud * reset_needed may be set in the functions call path 553e2553d68SSerge Dussud * from idle() 554e2553d68SSerge Dussud */ 555e2553d68SSerge Dussud if (idle(ne_time) || reset_needed) { 556e2553d68SSerge Dussud reset_needed = 1; 5577c478bd9Sstevel@tonic-gate continue; 558e2553d68SSerge Dussud } 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate if (stat(QUEDEFS, &buf)) { 5627c478bd9Sstevel@tonic-gate msg("cannot stat QUEDEFS file"); 5637c478bd9Sstevel@tonic-gate } else if (lastmtime != buf.st_mtime) { 5647c478bd9Sstevel@tonic-gate quedefs(LOAD); 5657c478bd9Sstevel@tonic-gate lastmtime = buf.st_mtime; 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate last_time = next_event->time; /* save execution time */ 5697c478bd9Sstevel@tonic-gate 570e2553d68SSerge Dussud /* 571e2553d68SSerge Dussud * reset_needed may be set in the functions call path 572e2553d68SSerge Dussud * from ex() 573e2553d68SSerge Dussud */ 574e2553d68SSerge Dussud if (ex(next_event) || reset_needed) { 575e2553d68SSerge Dussud reset_needed = 1; 5767c478bd9Sstevel@tonic-gate continue; 577e2553d68SSerge Dussud } 5787c478bd9Sstevel@tonic-gate 5797c478bd9Sstevel@tonic-gate switch (next_event->etype) { 5807c478bd9Sstevel@tonic-gate case CRONEVENT: 5817c478bd9Sstevel@tonic-gate /* add cronevent back into the main event list */ 5827c478bd9Sstevel@tonic-gate if (delayed) { 5837c478bd9Sstevel@tonic-gate delayed = 0; 5847c478bd9Sstevel@tonic-gate break; 5857c478bd9Sstevel@tonic-gate } 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate /* 5887c478bd9Sstevel@tonic-gate * check if time(0)< last_time. if so, then the 5897c478bd9Sstevel@tonic-gate * system clock has gone backwards. to prevent this 5907c478bd9Sstevel@tonic-gate * job from being started twice, we reschedule this 5917c478bd9Sstevel@tonic-gate * job for the >>next time after last_time<<, and 5927c478bd9Sstevel@tonic-gate * then set next_event->time to this. note that 5937c478bd9Sstevel@tonic-gate * crontab's resolution is 1 minute. 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate if (last_time > time(NULL)) { 5977c478bd9Sstevel@tonic-gate msg(CLOCK_DRIFT); 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * bump up to next 30 second 6007c478bd9Sstevel@tonic-gate * increment 6017c478bd9Sstevel@tonic-gate * 1 <= newtime <= 30 6027c478bd9Sstevel@tonic-gate */ 6037c478bd9Sstevel@tonic-gate newtime = 30 - (last_time % 30); 6047c478bd9Sstevel@tonic-gate newtime += last_time; 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate /* 6077c478bd9Sstevel@tonic-gate * get the next scheduled event, 6087c478bd9Sstevel@tonic-gate * not the one that we just 6097c478bd9Sstevel@tonic-gate * kicked off! 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate next_event->time = 6124c4c9110Sbasabi next_time(next_event, newtime); 6137c478bd9Sstevel@tonic-gate t_old = time(NULL); 6147c478bd9Sstevel@tonic-gate } else { 6157c478bd9Sstevel@tonic-gate next_event->time = 6164c4c9110Sbasabi next_time(next_event, (time_t)0); 6177c478bd9Sstevel@tonic-gate } 6187c478bd9Sstevel@tonic-gate #ifdef DEBUG 6197c478bd9Sstevel@tonic-gate cftime(timebuf, "%C", &next_event->time); 6207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6214c4c9110Sbasabi "pushing back cron event %s at %ld (%s)\n", 6224c4c9110Sbasabi next_event->cmd, next_event->time, timebuf); 6237c478bd9Sstevel@tonic-gate #endif 6247c478bd9Sstevel@tonic-gate 625e2553d68SSerge Dussud switch (el_add(next_event, next_event->time, 626e2553d68SSerge Dussud (next_event->u)->ctid)) { 627e2553d68SSerge Dussud case -1: 628e2553d68SSerge Dussud ignore_msg("main", "cron", next_event); 629e2553d68SSerge Dussud break; 630e2553d68SSerge Dussud case -2: /* event time lower than init time */ 631e2553d68SSerge Dussud reset_needed = 1; 632e2553d68SSerge Dussud break; 633e2553d68SSerge Dussud } 6347c478bd9Sstevel@tonic-gate break; 6357c478bd9Sstevel@tonic-gate default: 6367c478bd9Sstevel@tonic-gate /* remove at or batch job from system */ 6377c478bd9Sstevel@tonic-gate if (delayed) { 6387c478bd9Sstevel@tonic-gate delayed = 0; 6397c478bd9Sstevel@tonic-gate break; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate eprev = NULL; 6427c478bd9Sstevel@tonic-gate e = (next_event->u)->atevents; 6437c478bd9Sstevel@tonic-gate while (e != NULL) { 6447c478bd9Sstevel@tonic-gate if (e == next_event) { 6457c478bd9Sstevel@tonic-gate if (eprev == NULL) 6467c478bd9Sstevel@tonic-gate (e->u)->atevents = e->link; 6477c478bd9Sstevel@tonic-gate else 6487c478bd9Sstevel@tonic-gate eprev->link = e->link; 6497c478bd9Sstevel@tonic-gate free(e->cmd); 6507c478bd9Sstevel@tonic-gate free(e); 6517c478bd9Sstevel@tonic-gate break; 6527c478bd9Sstevel@tonic-gate } else { 6537c478bd9Sstevel@tonic-gate eprev = e; 6547c478bd9Sstevel@tonic-gate e = e->link; 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate break; 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate next_event = NULL; 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 6637c478bd9Sstevel@tonic-gate } 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate static void 6667c478bd9Sstevel@tonic-gate initialize(int firstpass) 6677c478bd9Sstevel@tonic-gate { 6687c478bd9Sstevel@tonic-gate #ifdef DEBUG 6697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "in initialize\n"); 6707c478bd9Sstevel@tonic-gate #endif 6717c478bd9Sstevel@tonic-gate if (firstpass) { 6727c478bd9Sstevel@tonic-gate /* for mail(1), make sure messages come from root */ 6737c478bd9Sstevel@tonic-gate if (putenv("LOGNAME=root") != 0) { 6747c478bd9Sstevel@tonic-gate crabort("cannot expand env variable", 6754c4c9110Sbasabi REMOVE_FIFO|CONSOLE_MSG); 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate if (access(FIFO, R_OK) == -1) { 6787c478bd9Sstevel@tonic-gate if (errno == ENOENT) { 6797c478bd9Sstevel@tonic-gate if (mknod(FIFO, S_IFIFO|0600, 0) != 0) 6807c478bd9Sstevel@tonic-gate crabort("cannot create fifo queue", 6814c4c9110Sbasabi REMOVE_FIFO|CONSOLE_MSG); 6827c478bd9Sstevel@tonic-gate } else { 6837c478bd9Sstevel@tonic-gate if (NOFORK) { 6847c478bd9Sstevel@tonic-gate /* didn't fork... init(1M) is waiting */ 6857c478bd9Sstevel@tonic-gate (void) sleep(60); 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate perror("FIFO"); 6887c478bd9Sstevel@tonic-gate crabort("cannot access fifo queue", 6894c4c9110Sbasabi REMOVE_FIFO|CONSOLE_MSG); 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate } else { 6927c478bd9Sstevel@tonic-gate if (NOFORK) { 6937c478bd9Sstevel@tonic-gate /* didn't fork... init(1M) is waiting */ 6947c478bd9Sstevel@tonic-gate (void) sleep(60); 6957c478bd9Sstevel@tonic-gate /* 6967c478bd9Sstevel@tonic-gate * the wait is painful, but we don't want 6977c478bd9Sstevel@tonic-gate * init respawning this quickly 6987c478bd9Sstevel@tonic-gate */ 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate crabort("cannot start cron; FIFO exists", CONSOLE_MSG); 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate 7047c478bd9Sstevel@tonic-gate if ((msgfd = open(FIFO, O_RDWR)) < 0) { 7057c478bd9Sstevel@tonic-gate perror("! open"); 7067c478bd9Sstevel@tonic-gate crabort("cannot open fifo queue", REMOVE_FIFO|CONSOLE_MSG); 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 709e2553d68SSerge Dussud init_time = time(NULL); 710e2553d68SSerge Dussud el_init(8, init_time, (time_t)(60*60*24), 10); 711e2553d68SSerge Dussud 712*5b08e637SChris Gerhard init_time = time(NULL); 713*5b08e637SChris Gerhard el_init(8, init_time, (time_t)(60*60*24), 10); 714*5b08e637SChris Gerhard 7157c478bd9Sstevel@tonic-gate /* 7167c478bd9Sstevel@tonic-gate * read directories, create users list, and add events to the 7177c478bd9Sstevel@tonic-gate * main event list. Only zero user list on firstpass. 7187c478bd9Sstevel@tonic-gate */ 7197c478bd9Sstevel@tonic-gate if (firstpass) 7207c478bd9Sstevel@tonic-gate uhead = NULL; 7214c4c9110Sbasabi read_dirs(firstpass); 7227c478bd9Sstevel@tonic-gate next_event = NULL; 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate if (!firstpass) 7257c478bd9Sstevel@tonic-gate return; 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate /* stdout is log file */ 7287c478bd9Sstevel@tonic-gate if (freopen(ACCTFILE, "a", stdout) == NULL) 7297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "cannot open %s\n", ACCTFILE); 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate /* log should be root-only */ 7327c478bd9Sstevel@tonic-gate (void) fchmod(1, S_IRUSR|S_IWUSR); 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate /* stderr also goes to ACCTFILE */ 7357c478bd9Sstevel@tonic-gate (void) close(fileno(stderr)); 7367c478bd9Sstevel@tonic-gate (void) dup(1); 7377c478bd9Sstevel@tonic-gate /* null for stdin */ 7387c478bd9Sstevel@tonic-gate (void) freopen("/dev/null", "r", stdin); 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate contract_set_template(); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate static void 7444c4c9110Sbasabi read_dirs(int first) 7457c478bd9Sstevel@tonic-gate { 7464c4c9110Sbasabi DIR *dir; 7474c4c9110Sbasabi struct dirent *dp; 7484c4c9110Sbasabi char *ptr; 7494c4c9110Sbasabi int jobtype; 7504c4c9110Sbasabi time_t tim; 7514c4c9110Sbasabi 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate if (chdir(CRONDIR) == -1) 7547c478bd9Sstevel@tonic-gate crabort(BADCD, REMOVE_FIFO|CONSOLE_MSG); 7557c478bd9Sstevel@tonic-gate cwd = CRON; 7567c478bd9Sstevel@tonic-gate if ((dir = opendir(".")) == NULL) 7577c478bd9Sstevel@tonic-gate crabort(NOREADDIR, REMOVE_FIFO|CONSOLE_MSG); 7584c4c9110Sbasabi while ((dp = readdir(dir)) != NULL) { 7594c4c9110Sbasabi if (!valid_entry(dp->d_name, CRONEVENT)) 7604c4c9110Sbasabi continue; 7614c4c9110Sbasabi init_cronevent(dp->d_name, first); 7624c4c9110Sbasabi } 7637c478bd9Sstevel@tonic-gate (void) closedir(dir); 7644c4c9110Sbasabi 7657c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == -1) { 7667c478bd9Sstevel@tonic-gate msg("cannot chdir to at directory"); 7677c478bd9Sstevel@tonic-gate return; 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate if ((dir = opendir(".")) == NULL) { 7707c478bd9Sstevel@tonic-gate msg("cannot read at at directory"); 7717c478bd9Sstevel@tonic-gate return; 7727c478bd9Sstevel@tonic-gate } 7734c4c9110Sbasabi cwd = AT; 7744c4c9110Sbasabi while ((dp = readdir(dir)) != NULL) { 7754c4c9110Sbasabi if (!valid_entry(dp->d_name, ATEVENT)) 7764c4c9110Sbasabi continue; 7774c4c9110Sbasabi ptr = dp->d_name; 7784c4c9110Sbasabi if (((tim = num(&ptr)) == 0) || (*ptr != '.')) 7794c4c9110Sbasabi continue; 7804c4c9110Sbasabi ptr++; 7814c4c9110Sbasabi if (!isalpha(*ptr)) 7824c4c9110Sbasabi continue; 7834c4c9110Sbasabi jobtype = *ptr - 'a'; 7844c4c9110Sbasabi if (jobtype >= NQUEUE) { 7854c4c9110Sbasabi cron_unlink(dp->d_name); 7864c4c9110Sbasabi continue; 7874c4c9110Sbasabi } 7884c4c9110Sbasabi init_atevent(dp->d_name, tim, jobtype, first); 7894c4c9110Sbasabi } 7907c478bd9Sstevel@tonic-gate (void) closedir(dir); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7934c4c9110Sbasabi static int 7944c4c9110Sbasabi valid_entry(char *name, int type) 7957c478bd9Sstevel@tonic-gate { 7964c4c9110Sbasabi struct stat buf; 7977c478bd9Sstevel@tonic-gate 7984c4c9110Sbasabi if (strcmp(name, ".") == 0 || 7994c4c9110Sbasabi strcmp(name, "..") == 0) 8004c4c9110Sbasabi return (0); 8014c4c9110Sbasabi 8024c4c9110Sbasabi /* skip over ancillary file names */ 8034c4c9110Sbasabi if (audit_cron_is_anc_name(name)) 8044c4c9110Sbasabi return (0); 8054c4c9110Sbasabi 8064c4c9110Sbasabi if (stat(name, &buf)) { 8074c4c9110Sbasabi mail(name, BADSTAT, ERR_UNIXERR); 8084c4c9110Sbasabi cron_unlink(name); 8094c4c9110Sbasabi return (0); 8104c4c9110Sbasabi } 8114c4c9110Sbasabi if (!S_ISREG(buf.st_mode)) { 8124c4c9110Sbasabi mail(name, BADTYPE, ERR_NOTREG); 8134c4c9110Sbasabi cron_unlink(name); 8144c4c9110Sbasabi return (0); 8154c4c9110Sbasabi } 8164c4c9110Sbasabi if (type == ATEVENT) { 8174c4c9110Sbasabi if (!(buf.st_mode & ISUID)) { 8184c4c9110Sbasabi cron_unlink(name); 8194c4c9110Sbasabi return (0); 8204c4c9110Sbasabi } 8214c4c9110Sbasabi } 8224c4c9110Sbasabi return (1); 8234c4c9110Sbasabi } 8244c4c9110Sbasabi 8254c4c9110Sbasabi struct usr * 8264c4c9110Sbasabi create_ulist(char *name, int type) 8274c4c9110Sbasabi { 8284c4c9110Sbasabi struct usr *u; 8294c4c9110Sbasabi 8304c4c9110Sbasabi u = xmalloc(sizeof (struct usr)); 8314c4c9110Sbasabi u->name = xmalloc(strlen(name) + 1); 8324c4c9110Sbasabi (void) strcpy(u->name, name); 8334c4c9110Sbasabi u->home = NULL; 8344c4c9110Sbasabi if (type == CRONEVENT) { 8354c4c9110Sbasabi u->ctexists = TRUE; 8364c4c9110Sbasabi u->ctid = ecid++; 8374c4c9110Sbasabi } else { 8384c4c9110Sbasabi u->ctexists = FALSE; 8394c4c9110Sbasabi u->ctid = 0; 8404c4c9110Sbasabi } 8414c4c9110Sbasabi u->ctevents = NULL; 8424c4c9110Sbasabi u->atevents = NULL; 8434c4c9110Sbasabi u->aruncnt = 0; 8444c4c9110Sbasabi u->cruncnt = 0; 8454c4c9110Sbasabi u->nextusr = uhead; 8464c4c9110Sbasabi uhead = u; 8474c4c9110Sbasabi return (u); 8484c4c9110Sbasabi } 8494c4c9110Sbasabi 8504c4c9110Sbasabi void 8514c4c9110Sbasabi init_cronevent(char *name, int first) 8524c4c9110Sbasabi { 8534c4c9110Sbasabi struct usr *u; 8544c4c9110Sbasabi 8554c4c9110Sbasabi if (first) { 8564c4c9110Sbasabi u = create_ulist(name, CRONEVENT); 8574c4c9110Sbasabi readcron(u, 0); 8584c4c9110Sbasabi } else { 8594c4c9110Sbasabi if ((u = find_usr(name)) == NULL) { 8604c4c9110Sbasabi u = create_ulist(name, CRONEVENT); 8614c4c9110Sbasabi readcron(u, 0); 8624c4c9110Sbasabi } else { 8634c4c9110Sbasabi u->ctexists = TRUE; 8644c4c9110Sbasabi rm_ctevents(u); 8654c4c9110Sbasabi el_remove(u->ctid, 0); 8664c4c9110Sbasabi readcron(u, 0); 8674c4c9110Sbasabi } 8684c4c9110Sbasabi } 8694c4c9110Sbasabi } 8704c4c9110Sbasabi 8714c4c9110Sbasabi void 8724c4c9110Sbasabi init_atevent(char *name, time_t tim, int jobtype, int first) 8734c4c9110Sbasabi { 8744c4c9110Sbasabi struct usr *u; 8754c4c9110Sbasabi 8764c4c9110Sbasabi if (first) { 8774c4c9110Sbasabi u = create_ulist(name, ATEVENT); 8784c4c9110Sbasabi add_atevent(u, name, tim, jobtype); 8794c4c9110Sbasabi } else { 8804c4c9110Sbasabi if ((u = find_usr(name)) == NULL) { 8814c4c9110Sbasabi u = create_ulist(name, ATEVENT); 8824c4c9110Sbasabi add_atevent(u, name, tim, jobtype); 8834c4c9110Sbasabi } else { 8844c4c9110Sbasabi update_atevent(u, name, tim, jobtype); 8857c478bd9Sstevel@tonic-gate } 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate } 8887c478bd9Sstevel@tonic-gate 8897c478bd9Sstevel@tonic-gate static void 8907c478bd9Sstevel@tonic-gate mod_ctab(char *name, time_t reftime) 8917c478bd9Sstevel@tonic-gate { 8927c478bd9Sstevel@tonic-gate struct passwd *pw; 8937c478bd9Sstevel@tonic-gate struct stat buf; 8947c478bd9Sstevel@tonic-gate struct usr *u; 895*5b08e637SChris Gerhard char namebuf[LINE_MAX]; 8967c478bd9Sstevel@tonic-gate char *pname; 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* skip over ancillary file names */ 8997c478bd9Sstevel@tonic-gate if (audit_cron_is_anc_name(name)) 9007c478bd9Sstevel@tonic-gate return; 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate if ((pw = getpwnam(name)) == NULL) { 9037c478bd9Sstevel@tonic-gate msg("No such user as %s - cron entries not created", name); 9047c478bd9Sstevel@tonic-gate return; 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate if (cwd != CRON) { 9077c478bd9Sstevel@tonic-gate if (snprintf(namebuf, sizeof (namebuf), "%s/%s", 9084c4c9110Sbasabi CRONDIR, name) >= sizeof (namebuf)) { 9097c478bd9Sstevel@tonic-gate msg("Too long path name %s - cron entries not created", 9104c4c9110Sbasabi namebuf); 9117c478bd9Sstevel@tonic-gate return; 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate pname = namebuf; 9147c478bd9Sstevel@tonic-gate } else { 9157c478bd9Sstevel@tonic-gate pname = name; 9167c478bd9Sstevel@tonic-gate } 9177c478bd9Sstevel@tonic-gate /* 9187c478bd9Sstevel@tonic-gate * a warning message is given by the crontab command so there is 9197c478bd9Sstevel@tonic-gate * no need to give one here...... use this code if you only want 9207c478bd9Sstevel@tonic-gate * users with a login shell of /usr/bin/sh to use cron 9217c478bd9Sstevel@tonic-gate */ 9227c478bd9Sstevel@tonic-gate #ifdef BOURNESHELLONLY 9237c478bd9Sstevel@tonic-gate if ((strcmp(pw->pw_shell, "") != 0) && 9247c478bd9Sstevel@tonic-gate (strcmp(pw->pw_shell, SHELL) != 0)) { 9257c478bd9Sstevel@tonic-gate mail(name, BADSHELL, ERR_CANTEXECCRON); 9267c478bd9Sstevel@tonic-gate cron_unlink(pname); 9277c478bd9Sstevel@tonic-gate return; 9287c478bd9Sstevel@tonic-gate } 9297c478bd9Sstevel@tonic-gate #endif 9307c478bd9Sstevel@tonic-gate if (stat(pname, &buf)) { 9317c478bd9Sstevel@tonic-gate mail(name, BADSTAT, ERR_UNIXERR); 9327c478bd9Sstevel@tonic-gate cron_unlink(pname); 9337c478bd9Sstevel@tonic-gate return; 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate if (!S_ISREG(buf.st_mode)) { 9367c478bd9Sstevel@tonic-gate mail(name, BADTYPE, ERR_CRONTABENT); 9377c478bd9Sstevel@tonic-gate return; 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate if ((u = find_usr(name)) == NULL) { 9407c478bd9Sstevel@tonic-gate #ifdef DEBUG 9417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "new user (%s) with a crontab\n", name); 9427c478bd9Sstevel@tonic-gate #endif 9434c4c9110Sbasabi u = create_ulist(name, CRONEVENT); 9444c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1); 9457c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir); 9467c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 9477c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 9487c478bd9Sstevel@tonic-gate readcron(u, reftime); 9497c478bd9Sstevel@tonic-gate } else { 9507c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 9517c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 952d9f27107Sbasabi if (u->home != NULL) { 953d9f27107Sbasabi if (strcmp(u->home, pw->pw_dir) != 0) { 954d9f27107Sbasabi free(u->home); 955d9f27107Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1); 956d9f27107Sbasabi (void) strcpy(u->home, pw->pw_dir); 957d9f27107Sbasabi } 958d9f27107Sbasabi } else { 9594c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1); 9607c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate u->ctexists = TRUE; 9637c478bd9Sstevel@tonic-gate if (u->ctid == 0) { 9647c478bd9Sstevel@tonic-gate #ifdef DEBUG 9657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s now has a crontab\n", 9667c478bd9Sstevel@tonic-gate u->name); 9677c478bd9Sstevel@tonic-gate #endif 9687c478bd9Sstevel@tonic-gate /* user didnt have a crontab last time */ 9697c478bd9Sstevel@tonic-gate u->ctid = ecid++; 9707c478bd9Sstevel@tonic-gate u->ctevents = NULL; 9717c478bd9Sstevel@tonic-gate readcron(u, reftime); 9727c478bd9Sstevel@tonic-gate return; 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate #ifdef DEBUG 9757c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s has revised his crontab\n", u->name); 9767c478bd9Sstevel@tonic-gate #endif 9777c478bd9Sstevel@tonic-gate rm_ctevents(u); 9787c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0); 9797c478bd9Sstevel@tonic-gate readcron(u, reftime); 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate /* ARGSUSED */ 9847c478bd9Sstevel@tonic-gate static void 9857c478bd9Sstevel@tonic-gate mod_atjob(char *name, time_t reftime) 9867c478bd9Sstevel@tonic-gate { 9877c478bd9Sstevel@tonic-gate char *ptr; 9887c478bd9Sstevel@tonic-gate time_t tim; 9897c478bd9Sstevel@tonic-gate struct passwd *pw; 9907c478bd9Sstevel@tonic-gate struct stat buf; 9917c478bd9Sstevel@tonic-gate struct usr *u; 9927c478bd9Sstevel@tonic-gate char namebuf[PATH_MAX]; 9937c478bd9Sstevel@tonic-gate char *pname; 9947c478bd9Sstevel@tonic-gate int jobtype; 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate ptr = name; 9977c478bd9Sstevel@tonic-gate if (((tim = num(&ptr)) == 0) || (*ptr != '.')) 9987c478bd9Sstevel@tonic-gate return; 9997c478bd9Sstevel@tonic-gate ptr++; 10007c478bd9Sstevel@tonic-gate if (!isalpha(*ptr)) 10017c478bd9Sstevel@tonic-gate return; 10027c478bd9Sstevel@tonic-gate jobtype = *ptr - 'a'; 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate /* check for audit ancillary file */ 10057c478bd9Sstevel@tonic-gate if (audit_cron_is_anc_name(name)) 10067c478bd9Sstevel@tonic-gate return; 10077c478bd9Sstevel@tonic-gate 10087c478bd9Sstevel@tonic-gate if (cwd != AT) { 10097c478bd9Sstevel@tonic-gate if (snprintf(namebuf, sizeof (namebuf), "%s/%s", ATDIR, name) 10107c478bd9Sstevel@tonic-gate >= sizeof (namebuf)) { 10117c478bd9Sstevel@tonic-gate return; 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate pname = namebuf; 10147c478bd9Sstevel@tonic-gate } else { 10157c478bd9Sstevel@tonic-gate pname = name; 10167c478bd9Sstevel@tonic-gate } 10177c478bd9Sstevel@tonic-gate if (stat(pname, &buf) || jobtype >= NQUEUE) { 10187c478bd9Sstevel@tonic-gate cron_unlink(pname); 10197c478bd9Sstevel@tonic-gate return; 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate if (!(buf.st_mode & ISUID) || !S_ISREG(buf.st_mode)) { 10227c478bd9Sstevel@tonic-gate cron_unlink(pname); 10237c478bd9Sstevel@tonic-gate return; 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate if ((pw = getpwuid(buf.st_uid)) == NULL) { 10267c478bd9Sstevel@tonic-gate cron_unlink(pname); 10277c478bd9Sstevel@tonic-gate return; 10287c478bd9Sstevel@tonic-gate } 10297c478bd9Sstevel@tonic-gate /* 10307c478bd9Sstevel@tonic-gate * a warning message is given by the at command so there is no 10317c478bd9Sstevel@tonic-gate * need to give one here......use this code if you only want 10327c478bd9Sstevel@tonic-gate * users with a login shell of /usr/bin/sh to use cron 10337c478bd9Sstevel@tonic-gate */ 10347c478bd9Sstevel@tonic-gate #ifdef BOURNESHELLONLY 10357c478bd9Sstevel@tonic-gate if ((strcmp(pw->pw_shell, "") != 0) && 10367c478bd9Sstevel@tonic-gate (strcmp(pw->pw_shell, SHELL) != 0)) { 10377c478bd9Sstevel@tonic-gate mail(pw->pw_name, BADSHELL, ERR_CANTEXECAT); 10387c478bd9Sstevel@tonic-gate cron_unlink(pname); 10397c478bd9Sstevel@tonic-gate return; 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate #endif 10427c478bd9Sstevel@tonic-gate if ((u = find_usr(pw->pw_name)) == NULL) { 10437c478bd9Sstevel@tonic-gate #ifdef DEBUG 10447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "new user (%s) with an at job = %s\n", 10454c4c9110Sbasabi pw->pw_name, name); 10467c478bd9Sstevel@tonic-gate #endif 10474c4c9110Sbasabi u = create_ulist(pw->pw_name, ATEVENT); 10484c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1); 10497c478bd9Sstevel@tonic-gate (void) strcpy(u->home, pw->pw_dir); 10507c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 10517c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 10527c478bd9Sstevel@tonic-gate add_atevent(u, name, tim, jobtype); 10537c478bd9Sstevel@tonic-gate } else { 10547c478bd9Sstevel@tonic-gate u->uid = pw->pw_uid; 10557c478bd9Sstevel@tonic-gate u->gid = pw->pw_gid; 10564c4c9110Sbasabi free(u->home); 10574c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1); 10584c4c9110Sbasabi (void) strcpy(u->home, pw->pw_dir); 10594c4c9110Sbasabi update_atevent(u, name, tim, jobtype); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate } 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate static void 10647c478bd9Sstevel@tonic-gate add_atevent(struct usr *u, char *job, time_t tim, int jobtype) 10657c478bd9Sstevel@tonic-gate { 10667c478bd9Sstevel@tonic-gate struct event *e; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate e = xmalloc(sizeof (struct event)); 10697c478bd9Sstevel@tonic-gate e->etype = jobtype; 10704c4c9110Sbasabi e->cmd = xmalloc(strlen(job) + 1); 10717c478bd9Sstevel@tonic-gate (void) strcpy(e->cmd, job); 10727c478bd9Sstevel@tonic-gate e->u = u; 10737c478bd9Sstevel@tonic-gate e->link = u->atevents; 10747c478bd9Sstevel@tonic-gate u->atevents = e; 10757c478bd9Sstevel@tonic-gate e->of.at.exists = TRUE; 10767c478bd9Sstevel@tonic-gate e->of.at.eventid = ecid++; 10777c478bd9Sstevel@tonic-gate if (tim < init_time) /* old job */ 10787c478bd9Sstevel@tonic-gate e->time = init_time; 10797c478bd9Sstevel@tonic-gate else 10807c478bd9Sstevel@tonic-gate e->time = tim; 10817c478bd9Sstevel@tonic-gate #ifdef DEBUG 10827c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "add_atevent: user=%s, job=%s, time=%ld\n", 10834c4c9110Sbasabi u->name, e->cmd, e->time); 10847c478bd9Sstevel@tonic-gate #endif 1085e2553d68SSerge Dussud if (el_add(e, e->time, e->of.at.eventid) < 0) { 1086e2553d68SSerge Dussud ignore_msg("add_atevent", "at", e); 1087e2553d68SSerge Dussud } 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate 10904c4c9110Sbasabi void 10914c4c9110Sbasabi update_atevent(struct usr *u, char *name, time_t tim, int jobtype) 10924c4c9110Sbasabi { 10934c4c9110Sbasabi struct event *e; 10944c4c9110Sbasabi 10954c4c9110Sbasabi e = u->atevents; 10964c4c9110Sbasabi while (e != NULL) { 10974c4c9110Sbasabi if (strcmp(e->cmd, name) == 0) { 10984c4c9110Sbasabi e->of.at.exists = TRUE; 10994c4c9110Sbasabi break; 11004c4c9110Sbasabi } else { 11014c4c9110Sbasabi e = e->link; 11024c4c9110Sbasabi } 11034c4c9110Sbasabi } 11044c4c9110Sbasabi if (e == NULL) { 11054c4c9110Sbasabi #ifdef DEBUG 11064c4c9110Sbasabi (void) fprintf(stderr, "%s has a new at job = %s\n", 11074c4c9110Sbasabi u->name, name); 11084c4c9110Sbasabi #endif 11094c4c9110Sbasabi add_atevent(u, name, tim, jobtype); 11104c4c9110Sbasabi } 11114c4c9110Sbasabi } 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate static char line[CTLINESIZE]; /* holds a line from a crontab file */ 11147c478bd9Sstevel@tonic-gate static int cursor; /* cursor for the above line */ 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate static void 11177c478bd9Sstevel@tonic-gate readcron(struct usr *u, time_t reftime) 11187c478bd9Sstevel@tonic-gate { 11197c478bd9Sstevel@tonic-gate /* 11207c478bd9Sstevel@tonic-gate * readcron reads in a crontab file for a user (u). The list of 11217c478bd9Sstevel@tonic-gate * events for user u is built, and u->events is made to point to 11227c478bd9Sstevel@tonic-gate * this list. Each event is also entered into the main event 11237c478bd9Sstevel@tonic-gate * list. 11247c478bd9Sstevel@tonic-gate */ 11257c478bd9Sstevel@tonic-gate FILE *cf; /* cf will be a user's crontab file */ 11267c478bd9Sstevel@tonic-gate struct event *e; 11277c478bd9Sstevel@tonic-gate int start; 11287c478bd9Sstevel@tonic-gate unsigned int i; 11297c478bd9Sstevel@tonic-gate char namebuf[PATH_MAX]; 11307c478bd9Sstevel@tonic-gate char *pname; 1131*5b08e637SChris Gerhard struct shared *tz = NULL; 1132*5b08e637SChris Gerhard struct shared *home = NULL; 1133*5b08e637SChris Gerhard struct shared *shell = NULL; 11347c478bd9Sstevel@tonic-gate int lineno = 0; 11357c478bd9Sstevel@tonic-gate 11367c478bd9Sstevel@tonic-gate /* read the crontab file */ 11377c478bd9Sstevel@tonic-gate cte_init(); /* Init error handling */ 11387c478bd9Sstevel@tonic-gate if (cwd != CRON) { 11397c478bd9Sstevel@tonic-gate if (snprintf(namebuf, sizeof (namebuf), "%s/%s", 11407c478bd9Sstevel@tonic-gate CRONDIR, u->name) >= sizeof (namebuf)) { 11417c478bd9Sstevel@tonic-gate return; 11427c478bd9Sstevel@tonic-gate } 11437c478bd9Sstevel@tonic-gate pname = namebuf; 11447c478bd9Sstevel@tonic-gate } else { 11457c478bd9Sstevel@tonic-gate pname = u->name; 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate if ((cf = fopen(pname, "r")) == NULL) { 11487c478bd9Sstevel@tonic-gate mail(u->name, NOREAD, ERR_UNIXERR); 11497c478bd9Sstevel@tonic-gate return; 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate while (fgets(line, CTLINESIZE, cf) != NULL) { 1152*5b08e637SChris Gerhard char *tmp; 11537c478bd9Sstevel@tonic-gate /* process a line of a crontab file */ 11547c478bd9Sstevel@tonic-gate lineno++; 11557c478bd9Sstevel@tonic-gate if (cte_istoomany()) 11567c478bd9Sstevel@tonic-gate break; 11577c478bd9Sstevel@tonic-gate cursor = 0; 11587c478bd9Sstevel@tonic-gate while (line[cursor] == ' ' || line[cursor] == '\t') 11597c478bd9Sstevel@tonic-gate cursor++; 11607c478bd9Sstevel@tonic-gate if (line[cursor] == '#' || line[cursor] == '\n') 11617c478bd9Sstevel@tonic-gate continue; 1162*5b08e637SChris Gerhard 1163*5b08e637SChris Gerhard if (strncmp(&line[cursor], ENV_TZ, 1164*5b08e637SChris Gerhard strlen(ENV_TZ)) == 0) { 1165*5b08e637SChris Gerhard if ((tmp = strchr(&line[cursor], '\n')) != NULL) { 1166*5b08e637SChris Gerhard *tmp = NULL; 1167*5b08e637SChris Gerhard } 1168*5b08e637SChris Gerhard 1169*5b08e637SChris Gerhard if (!isvalid_tz(&line[cursor + strlen(ENV_TZ)], NULL, 1170*5b08e637SChris Gerhard _VTZ_ALL)) { 1171*5b08e637SChris Gerhard cte_add(lineno, line); 1172*5b08e637SChris Gerhard break; 1173*5b08e637SChris Gerhard } 1174*5b08e637SChris Gerhard if (tz == NULL || strcmp(&line[cursor], get_obj(tz))) { 1175*5b08e637SChris Gerhard rel_shared(tz); 1176*5b08e637SChris Gerhard tz = create_shared_str(&line[cursor]); 1177*5b08e637SChris Gerhard } 1178*5b08e637SChris Gerhard continue; 1179*5b08e637SChris Gerhard } 1180*5b08e637SChris Gerhard 1181*5b08e637SChris Gerhard if (strncmp(&line[cursor], ENV_HOME, 1182*5b08e637SChris Gerhard strlen(ENV_HOME)) == 0) { 1183*5b08e637SChris Gerhard if ((tmp = strchr(&line[cursor], '\n')) != NULL) { 1184*5b08e637SChris Gerhard *tmp = NULL; 1185*5b08e637SChris Gerhard } 1186*5b08e637SChris Gerhard if (home == NULL || 1187*5b08e637SChris Gerhard strcmp(&line[cursor], get_obj(home))) { 1188*5b08e637SChris Gerhard rel_shared(home); 1189*5b08e637SChris Gerhard home = create_shared_str( 1190*5b08e637SChris Gerhard &line[cursor + strlen(ENV_HOME)]); 1191*5b08e637SChris Gerhard } 1192*5b08e637SChris Gerhard continue; 1193*5b08e637SChris Gerhard } 1194*5b08e637SChris Gerhard 1195*5b08e637SChris Gerhard if (strncmp(&line[cursor], ENV_SHELL, 1196*5b08e637SChris Gerhard strlen(ENV_SHELL)) == 0) { 1197*5b08e637SChris Gerhard if ((tmp = strchr(&line[cursor], '\n')) != NULL) { 1198*5b08e637SChris Gerhard *tmp = NULL; 1199*5b08e637SChris Gerhard } 1200*5b08e637SChris Gerhard if (shell == NULL || 1201*5b08e637SChris Gerhard strcmp(&line[cursor], get_obj(shell))) { 1202*5b08e637SChris Gerhard rel_shared(shell); 1203*5b08e637SChris Gerhard shell = create_shared_str(&line[cursor]); 1204*5b08e637SChris Gerhard } 1205*5b08e637SChris Gerhard continue; 1206*5b08e637SChris Gerhard } 1207*5b08e637SChris Gerhard 12087c478bd9Sstevel@tonic-gate e = xmalloc(sizeof (struct event)); 12097c478bd9Sstevel@tonic-gate e->etype = CRONEVENT; 12107c478bd9Sstevel@tonic-gate if (!(((e->of.ct.minute = next_field(0, 59)) != NULL) && 12117c478bd9Sstevel@tonic-gate ((e->of.ct.hour = next_field(0, 23)) != NULL) && 12127c478bd9Sstevel@tonic-gate ((e->of.ct.daymon = next_field(1, 31)) != NULL) && 12137c478bd9Sstevel@tonic-gate ((e->of.ct.month = next_field(1, 12)) != NULL) && 12147c478bd9Sstevel@tonic-gate ((e->of.ct.dayweek = next_field(0, 6)) != NULL))) { 12157c478bd9Sstevel@tonic-gate free(e); 12167c478bd9Sstevel@tonic-gate cte_add(lineno, line); 12177c478bd9Sstevel@tonic-gate continue; 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate while (line[cursor] == ' ' || line[cursor] == '\t') 12207c478bd9Sstevel@tonic-gate cursor++; 12217c478bd9Sstevel@tonic-gate if (line[cursor] == '\n' || line[cursor] == '\0') 12227c478bd9Sstevel@tonic-gate continue; 12237c478bd9Sstevel@tonic-gate /* get the command to execute */ 12247c478bd9Sstevel@tonic-gate start = cursor; 12257c478bd9Sstevel@tonic-gate again: 12267c478bd9Sstevel@tonic-gate while ((line[cursor] != '%') && 12277c478bd9Sstevel@tonic-gate (line[cursor] != '\n') && 12287c478bd9Sstevel@tonic-gate (line[cursor] != '\0') && 12297c478bd9Sstevel@tonic-gate (line[cursor] != '\\')) 12307c478bd9Sstevel@tonic-gate cursor++; 12317c478bd9Sstevel@tonic-gate if (line[cursor] == '\\') { 12327c478bd9Sstevel@tonic-gate cursor += 2; 12337c478bd9Sstevel@tonic-gate goto again; 12347c478bd9Sstevel@tonic-gate } 12354c4c9110Sbasabi e->cmd = xmalloc(cursor-start + 1); 12364c4c9110Sbasabi (void) strncpy(e->cmd, line + start, cursor-start); 12377c478bd9Sstevel@tonic-gate e->cmd[cursor-start] = '\0'; 12387c478bd9Sstevel@tonic-gate /* see if there is any standard input */ 12397c478bd9Sstevel@tonic-gate if (line[cursor] == '%') { 12404c4c9110Sbasabi e->of.ct.input = xmalloc(strlen(line)-cursor + 1); 12414c4c9110Sbasabi (void) strcpy(e->of.ct.input, line + cursor + 1); 12427c478bd9Sstevel@tonic-gate for (i = 0; i < strlen(e->of.ct.input); i++) { 12437c478bd9Sstevel@tonic-gate if (e->of.ct.input[i] == '%') 12447c478bd9Sstevel@tonic-gate e->of.ct.input[i] = '\n'; 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate } else { 12477c478bd9Sstevel@tonic-gate e->of.ct.input = NULL; 12487c478bd9Sstevel@tonic-gate } 1249*5b08e637SChris Gerhard /* set the timezone of this entry */ 1250*5b08e637SChris Gerhard e->of.ct.tz = dup_shared(tz); 1251*5b08e637SChris Gerhard /* set the shell of this entry */ 1252*5b08e637SChris Gerhard e->of.ct.shell = dup_shared(shell); 1253*5b08e637SChris Gerhard /* set the home of this entry */ 1254*5b08e637SChris Gerhard e->of.ct.home = dup_shared(home); 12557c478bd9Sstevel@tonic-gate /* have the event point to it's owner */ 12567c478bd9Sstevel@tonic-gate e->u = u; 12577c478bd9Sstevel@tonic-gate /* insert this event at the front of this user's event list */ 12587c478bd9Sstevel@tonic-gate e->link = u->ctevents; 12597c478bd9Sstevel@tonic-gate u->ctevents = e; 12607c478bd9Sstevel@tonic-gate /* set the time for the first occurance of this event */ 12617c478bd9Sstevel@tonic-gate e->time = next_time(e, reftime); 12627c478bd9Sstevel@tonic-gate /* finally, add this event to the main event list */ 1263e2553d68SSerge Dussud switch (el_add(e, e->time, u->ctid)) { 1264e2553d68SSerge Dussud case -1: 1265e2553d68SSerge Dussud ignore_msg("readcron", "cron", e); 1266e2553d68SSerge Dussud break; 1267e2553d68SSerge Dussud case -2: /* event time lower than init time */ 1268e2553d68SSerge Dussud reset_needed = 1; 1269e2553d68SSerge Dussud break; 1270e2553d68SSerge Dussud } 12717c478bd9Sstevel@tonic-gate cte_valid(); 12727c478bd9Sstevel@tonic-gate #ifdef DEBUG 12737c478bd9Sstevel@tonic-gate cftime(timebuf, "%C", &e->time); 12747c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "inserting cron event %s at %ld (%s)\n", 12754c4c9110Sbasabi e->cmd, e->time, timebuf); 12767c478bd9Sstevel@tonic-gate #endif 12777c478bd9Sstevel@tonic-gate } 12787c478bd9Sstevel@tonic-gate cte_sendmail(u->name); /* mail errors if any to user */ 12797c478bd9Sstevel@tonic-gate (void) fclose(cf); 1280*5b08e637SChris Gerhard rel_shared(tz); 1281*5b08e637SChris Gerhard rel_shared(shell); 1282*5b08e637SChris Gerhard rel_shared(home); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate 12857c478bd9Sstevel@tonic-gate /* 12867c478bd9Sstevel@tonic-gate * Below are the functions for handling of errors in crontabs. Concept is to 12877c478bd9Sstevel@tonic-gate * collect faulty lines and send one email at the end of the crontab 12887c478bd9Sstevel@tonic-gate * evaluation. If there are erroneous lines only ((cte_nvalid == 0), evaluation 12897c478bd9Sstevel@tonic-gate * of crontab is aborted. Otherwise reading of crontab is continued to the end 12907c478bd9Sstevel@tonic-gate * of the file but no further error logging appears. 12917c478bd9Sstevel@tonic-gate */ 12927c478bd9Sstevel@tonic-gate static void 12937c478bd9Sstevel@tonic-gate cte_init() 12947c478bd9Sstevel@tonic-gate { 12957c478bd9Sstevel@tonic-gate if (cte_text == NULL) 12967c478bd9Sstevel@tonic-gate cte_text = xmalloc(MAILBUFLEN); 12977c478bd9Sstevel@tonic-gate (void) strlcpy(cte_text, cte_intro, MAILBUFLEN); 12987c478bd9Sstevel@tonic-gate cte_lp = cte_text + sizeof (cte_intro) - 1; 12997c478bd9Sstevel@tonic-gate cte_free = MAILBINITFREE; 13007c478bd9Sstevel@tonic-gate cte_nvalid = 0; 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate static void 13047c478bd9Sstevel@tonic-gate cte_add(int lineno, char *ctline) 13057c478bd9Sstevel@tonic-gate { 13067c478bd9Sstevel@tonic-gate int len; 13077c478bd9Sstevel@tonic-gate char *p; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (cte_free >= LINELIMIT) { 13107c478bd9Sstevel@tonic-gate (void) sprintf(cte_lp, "%4d: ", lineno); 13117c478bd9Sstevel@tonic-gate (void) strlcat(cte_lp, ctline, LINELIMIT - 1); 13127c478bd9Sstevel@tonic-gate len = strlen(cte_lp); 13137c478bd9Sstevel@tonic-gate if (cte_lp[len - 1] != '\n') { 13147c478bd9Sstevel@tonic-gate cte_lp[len++] = '\n'; 13157c478bd9Sstevel@tonic-gate cte_lp[len] = '\0'; 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate for (p = cte_lp; *p; p++) { 13187c478bd9Sstevel@tonic-gate if (isprint(*p) || *p == '\n' || *p == '\t') 13197c478bd9Sstevel@tonic-gate continue; 13207c478bd9Sstevel@tonic-gate *p = '.'; 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate cte_lp += len; 13237c478bd9Sstevel@tonic-gate cte_free -= len; 13247c478bd9Sstevel@tonic-gate if (cte_free < LINELIMIT) { 13257c478bd9Sstevel@tonic-gate size_t buflen = MAILBUFLEN - (cte_lp - cte_text); 13267c478bd9Sstevel@tonic-gate (void) strlcpy(cte_lp, cte_trail1, buflen); 13277c478bd9Sstevel@tonic-gate if (cte_nvalid == 0) 13287c478bd9Sstevel@tonic-gate (void) strlcat(cte_lp, cte_trail2, buflen); 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate } 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate static void 13347c478bd9Sstevel@tonic-gate cte_valid() 13357c478bd9Sstevel@tonic-gate { 13367c478bd9Sstevel@tonic-gate cte_nvalid++; 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate 13397c478bd9Sstevel@tonic-gate static int 13407c478bd9Sstevel@tonic-gate cte_istoomany() 13417c478bd9Sstevel@tonic-gate { 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * Return TRUE only if all lines are faulty. So evaluation of 13447c478bd9Sstevel@tonic-gate * a crontab is not aborted if at least one valid line was found. 13457c478bd9Sstevel@tonic-gate */ 13467c478bd9Sstevel@tonic-gate return (cte_nvalid == 0 && cte_free < LINELIMIT); 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate static void 13507c478bd9Sstevel@tonic-gate cte_sendmail(char *username) 13517c478bd9Sstevel@tonic-gate { 13527c478bd9Sstevel@tonic-gate if (cte_free < MAILBINITFREE) 13537c478bd9Sstevel@tonic-gate mail(username, cte_text, ERR_CRONTABENT); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate /* 13577c478bd9Sstevel@tonic-gate * Send mail with error message to a user 13587c478bd9Sstevel@tonic-gate */ 13597c478bd9Sstevel@tonic-gate static void 13607c478bd9Sstevel@tonic-gate mail(char *usrname, char *mesg, int format) 13617c478bd9Sstevel@tonic-gate { 13627c478bd9Sstevel@tonic-gate /* mail mails a user a message. */ 13637c478bd9Sstevel@tonic-gate FILE *pipe; 13647c478bd9Sstevel@tonic-gate char *temp; 13657c478bd9Sstevel@tonic-gate struct passwd *ruser_ids; 13667c478bd9Sstevel@tonic-gate pid_t fork_val; 13677c478bd9Sstevel@tonic-gate int saveerrno = errno; 13687c478bd9Sstevel@tonic-gate struct utsname name; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate #ifdef TESTING 13717c478bd9Sstevel@tonic-gate return; 13727c478bd9Sstevel@tonic-gate #endif 13737c478bd9Sstevel@tonic-gate (void) uname(&name); 13747c478bd9Sstevel@tonic-gate if ((fork_val = fork()) == (pid_t)-1) { 13757c478bd9Sstevel@tonic-gate msg("cron cannot fork\n"); 13767c478bd9Sstevel@tonic-gate return; 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate if (fork_val == 0) { 13797c478bd9Sstevel@tonic-gate child_sigreset(); 13807c478bd9Sstevel@tonic-gate contract_clear_template(); 13817c478bd9Sstevel@tonic-gate if ((ruser_ids = getpwnam(usrname)) == NULL) 13827c478bd9Sstevel@tonic-gate exit(0); 13837c478bd9Sstevel@tonic-gate (void) setuid(ruser_ids->pw_uid); 13844c4c9110Sbasabi temp = xmalloc(strlen(MAIL) + strlen(usrname) + 2); 13857c478bd9Sstevel@tonic-gate (void) sprintf(temp, "%s %s", MAIL, usrname); 13867c478bd9Sstevel@tonic-gate pipe = popen(temp, "w"); 13877c478bd9Sstevel@tonic-gate if (pipe != NULL) { 13887c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "To: %s\n", usrname); 13897c478bd9Sstevel@tonic-gate switch (format) { 13907c478bd9Sstevel@tonic-gate case ERR_CRONTABENT: 13917c478bd9Sstevel@tonic-gate (void) fprintf(pipe, CRONTABERR); 13927c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Your \"crontab\" on %s\n", 13937c478bd9Sstevel@tonic-gate name.nodename); 13947c478bd9Sstevel@tonic-gate (void) fprintf(pipe, mesg); 13957c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 13967c478bd9Sstevel@tonic-gate "\nEntries or crontab have been ignored\n"); 13977c478bd9Sstevel@tonic-gate break; 13987c478bd9Sstevel@tonic-gate case ERR_UNIXERR: 13997c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Subject: %s\n\n", mesg); 14007c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 14017c478bd9Sstevel@tonic-gate "The error on %s was \"%s\"\n", 14027c478bd9Sstevel@tonic-gate name.nodename, errmsg(saveerrno)); 14037c478bd9Sstevel@tonic-gate break; 14047c478bd9Sstevel@tonic-gate 14057c478bd9Sstevel@tonic-gate case ERR_CANTEXECCRON: 14067c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 14077c478bd9Sstevel@tonic-gate "Subject: Couldn't run your \"cron\" job\n\n"); 14087c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 14097c478bd9Sstevel@tonic-gate "Your \"cron\" job on %s ", name.nodename); 14107c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "couldn't be run\n"); 14117c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "%s\n", mesg); 14127c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 14137c478bd9Sstevel@tonic-gate "The error was \"%s\"\n", errmsg(saveerrno)); 14147c478bd9Sstevel@tonic-gate break; 14157c478bd9Sstevel@tonic-gate 14167c478bd9Sstevel@tonic-gate case ERR_CANTEXECAT: 14177c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 14187c478bd9Sstevel@tonic-gate "Subject: Couldn't run your \"at\" job\n\n"); 14197c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "Your \"at\" job on %s ", 14207c478bd9Sstevel@tonic-gate name.nodename); 14217c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "couldn't be run\n"); 14227c478bd9Sstevel@tonic-gate (void) fprintf(pipe, "%s\n", mesg); 14237c478bd9Sstevel@tonic-gate (void) fprintf(pipe, 14247c478bd9Sstevel@tonic-gate "The error was \"%s\"\n", errmsg(saveerrno)); 14257c478bd9Sstevel@tonic-gate break; 14267c478bd9Sstevel@tonic-gate 14277c478bd9Sstevel@tonic-gate default: 14287c478bd9Sstevel@tonic-gate break; 14297c478bd9Sstevel@tonic-gate } 14307c478bd9Sstevel@tonic-gate (void) pclose(pipe); 14317c478bd9Sstevel@tonic-gate } 14327c478bd9Sstevel@tonic-gate free(temp); 14337c478bd9Sstevel@tonic-gate exit(0); 14347c478bd9Sstevel@tonic-gate } 14357c478bd9Sstevel@tonic-gate 14367c478bd9Sstevel@tonic-gate contract_abandon_latest(fork_val); 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate if (cron_pid == getpid()) { 14397c478bd9Sstevel@tonic-gate miscpid_insert(fork_val); 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate } 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate static char * 14447c478bd9Sstevel@tonic-gate next_field(int lower, int upper) 14457c478bd9Sstevel@tonic-gate { 14467c478bd9Sstevel@tonic-gate /* 14477c478bd9Sstevel@tonic-gate * next_field returns a pointer to a string which holds the next 14487c478bd9Sstevel@tonic-gate * field of a line of a crontab file. 14497c478bd9Sstevel@tonic-gate * if (numbers in this field are out of range (lower..upper), 14507c478bd9Sstevel@tonic-gate * or there is a syntax error) then 14517c478bd9Sstevel@tonic-gate * NULL is returned, and a mail message is sent to the 14527c478bd9Sstevel@tonic-gate * user telling him which line the error was in. 14537c478bd9Sstevel@tonic-gate */ 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate char *s; 14567c478bd9Sstevel@tonic-gate int num, num2, start; 14577c478bd9Sstevel@tonic-gate 14587c478bd9Sstevel@tonic-gate while ((line[cursor] == ' ') || (line[cursor] == '\t')) 14597c478bd9Sstevel@tonic-gate cursor++; 14607c478bd9Sstevel@tonic-gate start = cursor; 14617c478bd9Sstevel@tonic-gate if (line[cursor] == '\0') { 14627c478bd9Sstevel@tonic-gate return (NULL); 14637c478bd9Sstevel@tonic-gate } 14647c478bd9Sstevel@tonic-gate if (line[cursor] == '*') { 14657c478bd9Sstevel@tonic-gate cursor++; 14667c478bd9Sstevel@tonic-gate if ((line[cursor] != ' ') && (line[cursor] != '\t')) 14677c478bd9Sstevel@tonic-gate return (NULL); 14687c478bd9Sstevel@tonic-gate s = xmalloc(2); 14697c478bd9Sstevel@tonic-gate (void) strcpy(s, "*"); 14707c478bd9Sstevel@tonic-gate return (s); 14717c478bd9Sstevel@tonic-gate } 14727c478bd9Sstevel@tonic-gate for (;;) { 14737c478bd9Sstevel@tonic-gate if (!isdigit(line[cursor])) 14747c478bd9Sstevel@tonic-gate return (NULL); 14757c478bd9Sstevel@tonic-gate num = 0; 14767c478bd9Sstevel@tonic-gate do { 14777c478bd9Sstevel@tonic-gate num = num*10 + (line[cursor]-'0'); 14787c478bd9Sstevel@tonic-gate } while (isdigit(line[++cursor])); 14797c478bd9Sstevel@tonic-gate if ((num < lower) || (num > upper)) 14807c478bd9Sstevel@tonic-gate return (NULL); 14817c478bd9Sstevel@tonic-gate if (line[cursor] == '-') { 14827c478bd9Sstevel@tonic-gate if (!isdigit(line[++cursor])) 14837c478bd9Sstevel@tonic-gate return (NULL); 14847c478bd9Sstevel@tonic-gate num2 = 0; 14857c478bd9Sstevel@tonic-gate do { 14867c478bd9Sstevel@tonic-gate num2 = num2*10 + (line[cursor]-'0'); 14877c478bd9Sstevel@tonic-gate } while (isdigit(line[++cursor])); 14887c478bd9Sstevel@tonic-gate if ((num2 < lower) || (num2 > upper)) 14897c478bd9Sstevel@tonic-gate return (NULL); 14907c478bd9Sstevel@tonic-gate } 14917c478bd9Sstevel@tonic-gate if ((line[cursor] == ' ') || (line[cursor] == '\t')) 14927c478bd9Sstevel@tonic-gate break; 14937c478bd9Sstevel@tonic-gate if (line[cursor] == '\0') 14947c478bd9Sstevel@tonic-gate return (NULL); 14957c478bd9Sstevel@tonic-gate if (line[cursor++] != ',') 14967c478bd9Sstevel@tonic-gate return (NULL); 14977c478bd9Sstevel@tonic-gate } 14984c4c9110Sbasabi s = xmalloc(cursor-start + 1); 14994c4c9110Sbasabi (void) strncpy(s, line + start, cursor-start); 15007c478bd9Sstevel@tonic-gate s[cursor-start] = '\0'; 15017c478bd9Sstevel@tonic-gate return (s); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate #define tm_cmp(t1, t2) (\ 15057c478bd9Sstevel@tonic-gate (t1)->tm_year == (t2)->tm_year && \ 15067c478bd9Sstevel@tonic-gate (t1)->tm_mon == (t2)->tm_mon && \ 15077c478bd9Sstevel@tonic-gate (t1)->tm_mday == (t2)->tm_mday && \ 15087c478bd9Sstevel@tonic-gate (t1)->tm_hour == (t2)->tm_hour && \ 15097c478bd9Sstevel@tonic-gate (t1)->tm_min == (t2)->tm_min) 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate #define tm_setup(tp, yr, mon, dy, hr, min, dst) \ 15127c478bd9Sstevel@tonic-gate (tp)->tm_year = yr; \ 15137c478bd9Sstevel@tonic-gate (tp)->tm_mon = mon; \ 15147c478bd9Sstevel@tonic-gate (tp)->tm_mday = dy; \ 15157c478bd9Sstevel@tonic-gate (tp)->tm_hour = hr; \ 15167c478bd9Sstevel@tonic-gate (tp)->tm_min = min; \ 15177c478bd9Sstevel@tonic-gate (tp)->tm_isdst = dst; \ 15187c478bd9Sstevel@tonic-gate (tp)->tm_sec = 0; \ 15197c478bd9Sstevel@tonic-gate (tp)->tm_wday = 0; \ 15207c478bd9Sstevel@tonic-gate (tp)->tm_yday = 0; 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate /* 15237c478bd9Sstevel@tonic-gate * modification for bugid 1104537. the second argument to next_time is 15247c478bd9Sstevel@tonic-gate * now the value of time(2) to be used. if this is 0, then use the 15257c478bd9Sstevel@tonic-gate * current time. otherwise, the second argument is the time from which to 15267c478bd9Sstevel@tonic-gate * calculate things. this is useful to correct situations where you've 15277c478bd9Sstevel@tonic-gate * gone backwards in time (I.e. the system's internal clock is correcting 15287c478bd9Sstevel@tonic-gate * itself backwards). 15297c478bd9Sstevel@tonic-gate */ 15307c478bd9Sstevel@tonic-gate 1531*5b08e637SChris Gerhard 1532*5b08e637SChris Gerhard 15337c478bd9Sstevel@tonic-gate static time_t 1534*5b08e637SChris Gerhard tz_next_time(struct event *e, time_t tflag) 15357c478bd9Sstevel@tonic-gate { 15367c478bd9Sstevel@tonic-gate /* 15377c478bd9Sstevel@tonic-gate * returns the integer time for the next occurance of event e. 15387c478bd9Sstevel@tonic-gate * the following fields have ranges as indicated: 15397c478bd9Sstevel@tonic-gate * PRGM | min hour day of month mon day of week 15407c478bd9Sstevel@tonic-gate * ------|------------------------------------------------------- 15417c478bd9Sstevel@tonic-gate * cron | 0-59 0-23 1-31 1-12 0-6 (0=sunday) 15427c478bd9Sstevel@tonic-gate * time | 0-59 0-23 1-31 0-11 0-6 (0=sunday) 15437c478bd9Sstevel@tonic-gate * NOTE: this routine is hard to understand. 15447c478bd9Sstevel@tonic-gate */ 15457c478bd9Sstevel@tonic-gate 15467c478bd9Sstevel@tonic-gate struct tm *tm, ref_tm, tmp, tmp1, tmp2; 1547*5b08e637SChris Gerhard int tm_mon, tm_mday, tm_wday, wday, m, min, h, hr, carry, day, days; 1548*5b08e637SChris Gerhard int d1, day1, carry1, d2, day2, carry2, daysahead, mon, yr, db, wd; 1549*5b08e637SChris Gerhard int today; 15507c478bd9Sstevel@tonic-gate time_t t, ref_t, t1, t2, zone_start; 15517c478bd9Sstevel@tonic-gate int fallback; 15527c478bd9Sstevel@tonic-gate extern int days_btwn(int, int, int, int, int, int); 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate if (tflag == 0) { 15557c478bd9Sstevel@tonic-gate t = time(NULL); /* original way of doing things */ 15567c478bd9Sstevel@tonic-gate } else { 15577c478bd9Sstevel@tonic-gate t = tflag; 15587c478bd9Sstevel@tonic-gate } 15597c478bd9Sstevel@tonic-gate 15607c478bd9Sstevel@tonic-gate tm = &ref_tm; /* use a local variable and call localtime_r() */ 15617c478bd9Sstevel@tonic-gate ref_t = t; /* keep a copy of the reference time */ 15627c478bd9Sstevel@tonic-gate 15637c478bd9Sstevel@tonic-gate recalc: 15647c478bd9Sstevel@tonic-gate fallback = 0; 15657c478bd9Sstevel@tonic-gate 15667c478bd9Sstevel@tonic-gate (void) localtime_r(&t, tm); 15677c478bd9Sstevel@tonic-gate 15687c478bd9Sstevel@tonic-gate if (daylight) { 15697c478bd9Sstevel@tonic-gate tmp = *tm; 15707c478bd9Sstevel@tonic-gate tmp.tm_isdst = (tm->tm_isdst > 0 ? 0 : 1); 15717c478bd9Sstevel@tonic-gate t1 = xmktime(&tmp); 15727c478bd9Sstevel@tonic-gate /* 15737c478bd9Sstevel@tonic-gate * see if we will have timezone switch over, and clock will 15747c478bd9Sstevel@tonic-gate * fall back. zone_start will hold the time when it happens 15757c478bd9Sstevel@tonic-gate * (ie time of PST -> PDT switch over). 15767c478bd9Sstevel@tonic-gate */ 15777c478bd9Sstevel@tonic-gate if (tm->tm_isdst != tmp.tm_isdst && 15787c478bd9Sstevel@tonic-gate (t1 - t) == (timezone - altzone) && 15797c478bd9Sstevel@tonic-gate tm_cmp(tm, &tmp)) { 15807c478bd9Sstevel@tonic-gate zone_start = get_switching_time(tmp.tm_isdst, t); 15817c478bd9Sstevel@tonic-gate fallback = 1; 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate } 15847c478bd9Sstevel@tonic-gate 15854c4c9110Sbasabi tm_mon = next_ge(tm->tm_mon + 1, e->of.ct.month) - 1; /* 0-11 */ 15867c478bd9Sstevel@tonic-gate tm_mday = next_ge(tm->tm_mday, e->of.ct.daymon); /* 1-31 */ 15877c478bd9Sstevel@tonic-gate tm_wday = next_ge(tm->tm_wday, e->of.ct.dayweek); /* 0-6 */ 15887c478bd9Sstevel@tonic-gate today = TRUE; 15897c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0 && tm->tm_wday != tm_wday) || 15907c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0 && tm->tm_mday != tm_mday) || 15917c478bd9Sstevel@tonic-gate (tm->tm_mday != tm_mday && tm->tm_wday != tm_wday) || 15927c478bd9Sstevel@tonic-gate (tm->tm_mon != tm_mon)) { 15937c478bd9Sstevel@tonic-gate today = FALSE; 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate m = tm->tm_min + (t == ref_t ? 1 : 0); 15967c478bd9Sstevel@tonic-gate if ((tm->tm_hour + 1) <= next_ge(tm->tm_hour, e->of.ct.hour)) { 15977c478bd9Sstevel@tonic-gate m = 0; 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate min = next_ge(m%60, e->of.ct.minute); 16007c478bd9Sstevel@tonic-gate carry = (min < m) ? 1 : 0; 16017c478bd9Sstevel@tonic-gate h = tm->tm_hour + carry; 16027c478bd9Sstevel@tonic-gate hr = next_ge(h%24, e->of.ct.hour); 16037c478bd9Sstevel@tonic-gate carry = (hr < h) ? 1 : 0; 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate if (carry == 0 && today) { 16067c478bd9Sstevel@tonic-gate /* this event must occur today */ 16077c478bd9Sstevel@tonic-gate tm_setup(&tmp, tm->tm_year, tm->tm_mon, tm->tm_mday, 16084c4c9110Sbasabi hr, min, tm->tm_isdst); 16097c478bd9Sstevel@tonic-gate tmp1 = tmp; 16107c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp1)) == (time_t)-1) { 16117c478bd9Sstevel@tonic-gate return (0); 16127c478bd9Sstevel@tonic-gate } 16137c478bd9Sstevel@tonic-gate if (daylight && tmp.tm_isdst != tmp1.tm_isdst) { 16147c478bd9Sstevel@tonic-gate /* In case we are falling back */ 16157c478bd9Sstevel@tonic-gate if (fallback) { 16167c478bd9Sstevel@tonic-gate /* we may need to run the job once more. */ 16177c478bd9Sstevel@tonic-gate t = zone_start; 16187c478bd9Sstevel@tonic-gate goto recalc; 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * In case we are not in falling back period, 16237c478bd9Sstevel@tonic-gate * calculate the time assuming the DST. If the 16247c478bd9Sstevel@tonic-gate * date/time is not altered by mktime, it is the 16257c478bd9Sstevel@tonic-gate * time to execute the job. 16267c478bd9Sstevel@tonic-gate */ 16277c478bd9Sstevel@tonic-gate tmp2 = tmp; 16287c478bd9Sstevel@tonic-gate tmp2.tm_isdst = tmp1.tm_isdst; 16297c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp2)) == (time_t)-1) { 16307c478bd9Sstevel@tonic-gate return (0); 16317c478bd9Sstevel@tonic-gate } 16327c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst == tmp2.tm_isdst && 16337c478bd9Sstevel@tonic-gate tm_cmp(&tmp, &tmp2)) { 16347c478bd9Sstevel@tonic-gate /* 16357c478bd9Sstevel@tonic-gate * We got a valid time. 16367c478bd9Sstevel@tonic-gate */ 16377c478bd9Sstevel@tonic-gate return (t1); 16387c478bd9Sstevel@tonic-gate } else { 16397c478bd9Sstevel@tonic-gate /* 16407c478bd9Sstevel@tonic-gate * If the date does not match even if 16417c478bd9Sstevel@tonic-gate * we assume the alternate timezone, then 16427c478bd9Sstevel@tonic-gate * it must be the invalid time. eg 16437c478bd9Sstevel@tonic-gate * 2am while switching 1:59am to 3am. 16447c478bd9Sstevel@tonic-gate * t1 should point the time before the 16457c478bd9Sstevel@tonic-gate * switching over as we've calculate the 16467c478bd9Sstevel@tonic-gate * time with assuming alternate zone. 16477c478bd9Sstevel@tonic-gate */ 16487c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst != tmp2.tm_isdst) { 16497c478bd9Sstevel@tonic-gate t = get_switching_time(tmp1.tm_isdst, 16504c4c9110Sbasabi t1); 16517c478bd9Sstevel@tonic-gate } else { 16527c478bd9Sstevel@tonic-gate /* does this really happen? */ 16537c478bd9Sstevel@tonic-gate t = get_switching_time(tmp1.tm_isdst, 16544c4c9110Sbasabi t1 - abs(timezone - altzone)); 16557c478bd9Sstevel@tonic-gate } 1656*5b08e637SChris Gerhard if (t == (time_t)-1) { 16577c478bd9Sstevel@tonic-gate return (0); 1658*5b08e637SChris Gerhard } 16597c478bd9Sstevel@tonic-gate } 16607c478bd9Sstevel@tonic-gate goto recalc; 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp1)) { 16637c478bd9Sstevel@tonic-gate /* got valid time */ 16647c478bd9Sstevel@tonic-gate return (t1); 16657c478bd9Sstevel@tonic-gate } else { 16667c478bd9Sstevel@tonic-gate /* 16677c478bd9Sstevel@tonic-gate * This should never happen, but just in 16687c478bd9Sstevel@tonic-gate * case, we fall back to the old code. 16697c478bd9Sstevel@tonic-gate */ 16707c478bd9Sstevel@tonic-gate if (tm->tm_min > min) { 16717c478bd9Sstevel@tonic-gate t += (time_t)(hr-tm->tm_hour-1) * HOUR + 16724c4c9110Sbasabi (time_t)(60-tm->tm_min + min) * MINUTE; 16737c478bd9Sstevel@tonic-gate } else { 16747c478bd9Sstevel@tonic-gate t += (time_t)(hr-tm->tm_hour) * HOUR + 16754c4c9110Sbasabi (time_t)(min-tm->tm_min) * MINUTE; 16767c478bd9Sstevel@tonic-gate } 16777c478bd9Sstevel@tonic-gate t1 = t; 16787c478bd9Sstevel@tonic-gate t -= (time_t)tm->tm_sec; 16797c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp); 16807c478bd9Sstevel@tonic-gate if ((tm->tm_isdst == 0) && (tmp.tm_isdst > 0)) 16817c478bd9Sstevel@tonic-gate t -= (timezone - altzone); 16827c478bd9Sstevel@tonic-gate return ((t <= ref_t) ? t1 : t); 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate } 16857c478bd9Sstevel@tonic-gate 16867c478bd9Sstevel@tonic-gate /* 16877c478bd9Sstevel@tonic-gate * Job won't run today, however if we have a switch over within 16887c478bd9Sstevel@tonic-gate * one hour and we will have one hour time drifting back in this 16897c478bd9Sstevel@tonic-gate * period, we may need to run the job one more time if the job was 16907c478bd9Sstevel@tonic-gate * set to run on this hour of clock. 16917c478bd9Sstevel@tonic-gate */ 16927c478bd9Sstevel@tonic-gate if (fallback) { 16937c478bd9Sstevel@tonic-gate t = zone_start; 16947c478bd9Sstevel@tonic-gate goto recalc; 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate min = next_ge(0, e->of.ct.minute); 16987c478bd9Sstevel@tonic-gate hr = next_ge(0, e->of.ct.hour); 16997c478bd9Sstevel@tonic-gate 17007c478bd9Sstevel@tonic-gate /* 17017c478bd9Sstevel@tonic-gate * calculate the date of the next occurance of this event, which 17027c478bd9Sstevel@tonic-gate * will be on a different day than the current 17037c478bd9Sstevel@tonic-gate */ 17047c478bd9Sstevel@tonic-gate 17057c478bd9Sstevel@tonic-gate /* check monthly day specification */ 17064c4c9110Sbasabi d1 = tm->tm_mday + 1; 17074c4c9110Sbasabi day1 = next_ge((d1-1)%days_in_mon(tm->tm_mon, tm->tm_year) + 1, 17084c4c9110Sbasabi e->of.ct.daymon); 17097c478bd9Sstevel@tonic-gate carry1 = (day1 < d1) ? 1 : 0; 17107c478bd9Sstevel@tonic-gate 17117c478bd9Sstevel@tonic-gate /* check weekly day specification */ 17124c4c9110Sbasabi d2 = tm->tm_wday + 1; 17137c478bd9Sstevel@tonic-gate wday = next_ge(d2%7, e->of.ct.dayweek); 17147c478bd9Sstevel@tonic-gate if (wday < d2) 17157c478bd9Sstevel@tonic-gate daysahead = 7 - d2 + wday; 17167c478bd9Sstevel@tonic-gate else 17177c478bd9Sstevel@tonic-gate daysahead = wday - d2; 17184c4c9110Sbasabi day2 = (d1 + daysahead-1)%days_in_mon(tm->tm_mon, tm->tm_year) + 1; 17197c478bd9Sstevel@tonic-gate carry2 = (day2 < d1) ? 1 : 0; 17207c478bd9Sstevel@tonic-gate 17217c478bd9Sstevel@tonic-gate /* 17227c478bd9Sstevel@tonic-gate * based on their respective specifications, day1, and day2 give 17237c478bd9Sstevel@tonic-gate * the day of the month for the next occurance of this event. 17247c478bd9Sstevel@tonic-gate */ 17257c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0) && 17267c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") != 0)) { 17277c478bd9Sstevel@tonic-gate day1 = day2; 17287c478bd9Sstevel@tonic-gate carry1 = carry2; 17297c478bd9Sstevel@tonic-gate } 17307c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") != 0) && 17317c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0)) { 17327c478bd9Sstevel@tonic-gate day2 = day1; 17337c478bd9Sstevel@tonic-gate carry2 = carry1; 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate 17367c478bd9Sstevel@tonic-gate yr = tm->tm_year; 17377c478bd9Sstevel@tonic-gate if ((carry1 && carry2) || (tm->tm_mon != tm_mon)) { 17387c478bd9Sstevel@tonic-gate /* event does not occur in this month */ 17394c4c9110Sbasabi m = tm->tm_mon + 1; 17404c4c9110Sbasabi mon = next_ge(m%12 + 1, e->of.ct.month) - 1; /* 0..11 */ 17417c478bd9Sstevel@tonic-gate carry = (mon < m) ? 1 : 0; 17427c478bd9Sstevel@tonic-gate yr += carry; 17437c478bd9Sstevel@tonic-gate /* recompute day1 and day2 */ 17447c478bd9Sstevel@tonic-gate day1 = next_ge(1, e->of.ct.daymon); 17457c478bd9Sstevel@tonic-gate db = days_btwn(tm->tm_mon, tm->tm_mday, tm->tm_year, mon, 17464c4c9110Sbasabi 1, yr) + 1; 17474c4c9110Sbasabi wd = (tm->tm_wday + db)%7; 17487c478bd9Sstevel@tonic-gate /* wd is the day of the week of the first of month mon */ 17497c478bd9Sstevel@tonic-gate wday = next_ge(wd, e->of.ct.dayweek); 17507c478bd9Sstevel@tonic-gate if (wday < wd) 17517c478bd9Sstevel@tonic-gate day2 = 1 + 7 - wd + wday; 17527c478bd9Sstevel@tonic-gate else 17537c478bd9Sstevel@tonic-gate day2 = 1 + wday - wd; 17547c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") != 0) && 17557c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") == 0)) 17567c478bd9Sstevel@tonic-gate day2 = day1; 17577c478bd9Sstevel@tonic-gate if ((strcmp(e->of.ct.daymon, "*") == 0) && 17587c478bd9Sstevel@tonic-gate (strcmp(e->of.ct.dayweek, "*") != 0)) 17597c478bd9Sstevel@tonic-gate day1 = day2; 17607c478bd9Sstevel@tonic-gate day = (day1 < day2) ? day1 : day2; 17617c478bd9Sstevel@tonic-gate } else { /* event occurs in this month */ 17627c478bd9Sstevel@tonic-gate mon = tm->tm_mon; 17637c478bd9Sstevel@tonic-gate if (!carry1 && !carry2) 17647c478bd9Sstevel@tonic-gate day = (day1 < day2) ? day1 : day2; 17657c478bd9Sstevel@tonic-gate else if (!carry1) 17667c478bd9Sstevel@tonic-gate day = day1; 17677c478bd9Sstevel@tonic-gate else 17687c478bd9Sstevel@tonic-gate day = day2; 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate /* 17727c478bd9Sstevel@tonic-gate * now that we have the min, hr, day, mon, yr of the next event, 17737c478bd9Sstevel@tonic-gate * figure out what time that turns out to be. 17747c478bd9Sstevel@tonic-gate */ 17757c478bd9Sstevel@tonic-gate tm_setup(&tmp, yr, mon, day, hr, min, -1); 17767c478bd9Sstevel@tonic-gate tmp2 = tmp; 17777c478bd9Sstevel@tonic-gate if ((t1 = xmktime(&tmp2)) == (time_t)-1) { 17787c478bd9Sstevel@tonic-gate return (0); 17797c478bd9Sstevel@tonic-gate } 17807c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp2)) { 17817c478bd9Sstevel@tonic-gate /* 17827c478bd9Sstevel@tonic-gate * mktime returns clock for the current time zone. If the 17837c478bd9Sstevel@tonic-gate * target date was in fallback period, it needs to be adjusted 17847c478bd9Sstevel@tonic-gate * to the time comes first. 17857c478bd9Sstevel@tonic-gate * Suppose, we are at Jan and scheduling job at 1:30am10/26/03. 17867c478bd9Sstevel@tonic-gate * mktime returns the time in PST, but 1:30am in PDT comes 17877c478bd9Sstevel@tonic-gate * first. So reverse the tm_isdst, and see if we have such 17887c478bd9Sstevel@tonic-gate * time/date. 17897c478bd9Sstevel@tonic-gate */ 17907c478bd9Sstevel@tonic-gate if (daylight) { 17917c478bd9Sstevel@tonic-gate int dst = tmp2.tm_isdst; 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate tmp2 = tmp; 17947c478bd9Sstevel@tonic-gate tmp2.tm_isdst = (dst > 0 ? 0 : 1); 17957c478bd9Sstevel@tonic-gate if ((t2 = xmktime(&tmp2)) == (time_t)-1) { 17967c478bd9Sstevel@tonic-gate return (0); 17977c478bd9Sstevel@tonic-gate } 17987c478bd9Sstevel@tonic-gate if (tm_cmp(&tmp, &tmp2)) { 17997c478bd9Sstevel@tonic-gate /* 18007c478bd9Sstevel@tonic-gate * same time/date found in the opposite zone. 18017c478bd9Sstevel@tonic-gate * check the clock to see which comes early. 18027c478bd9Sstevel@tonic-gate */ 18037c478bd9Sstevel@tonic-gate if (t2 > ref_t && t2 < t1) { 18047c478bd9Sstevel@tonic-gate t1 = t2; 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate } 18077c478bd9Sstevel@tonic-gate } 18087c478bd9Sstevel@tonic-gate return (t1); 18097c478bd9Sstevel@tonic-gate } else { 18107c478bd9Sstevel@tonic-gate /* 18117c478bd9Sstevel@tonic-gate * mktime has set different time/date for the given date. 18127c478bd9Sstevel@tonic-gate * This means that the next job is scheduled to be run on the 18137c478bd9Sstevel@tonic-gate * invalid time. There are three possible invalid date/time. 18147c478bd9Sstevel@tonic-gate * 1. Non existing day of the month. such as April 31th. 18157c478bd9Sstevel@tonic-gate * 2. Feb 29th in the non-leap year. 18167c478bd9Sstevel@tonic-gate * 3. Time gap during the DST switch over. 18177c478bd9Sstevel@tonic-gate */ 18187c478bd9Sstevel@tonic-gate d1 = days_in_mon(mon, yr); 18197c478bd9Sstevel@tonic-gate if ((mon != 1 && day > d1) || (mon == 1 && day > 29)) { 18207c478bd9Sstevel@tonic-gate /* 18217c478bd9Sstevel@tonic-gate * see if we have got a specific date which 18227c478bd9Sstevel@tonic-gate * is invalid. 18237c478bd9Sstevel@tonic-gate */ 18247c478bd9Sstevel@tonic-gate if (strcmp(e->of.ct.dayweek, "*") == 0 && 18254c4c9110Sbasabi mon == (next_ge((mon + 1)%12 + 1, 18264c4c9110Sbasabi e->of.ct.month) - 1) && 18277c478bd9Sstevel@tonic-gate day <= next_ge(1, e->of.ct.daymon)) { 18287c478bd9Sstevel@tonic-gate /* job never run */ 18297c478bd9Sstevel@tonic-gate return (0); 18307c478bd9Sstevel@tonic-gate } 18317c478bd9Sstevel@tonic-gate /* 18327c478bd9Sstevel@tonic-gate * Since the day has gone invalid, we need to go to 18337c478bd9Sstevel@tonic-gate * next month, and recalcuate the first occurrence. 18347c478bd9Sstevel@tonic-gate * eg the cron tab such as: 18357c478bd9Sstevel@tonic-gate * 0 0 1,15,31 1,2,3,4,5 * /usr/bin.... 18367c478bd9Sstevel@tonic-gate * 2/31 is invalid, so the next job is 3/1. 18377c478bd9Sstevel@tonic-gate */ 18387c478bd9Sstevel@tonic-gate tmp2 = tmp; 18397c478bd9Sstevel@tonic-gate tmp2.tm_min = 0; 18407c478bd9Sstevel@tonic-gate tmp2.tm_hour = 0; 18417c478bd9Sstevel@tonic-gate tmp2.tm_mday = 1; /* 1st day of the month */ 18427c478bd9Sstevel@tonic-gate if (mon == 11) { 18437c478bd9Sstevel@tonic-gate tmp2.tm_mon = 0; 18447c478bd9Sstevel@tonic-gate tmp2.tm_year = yr + 1; 18457c478bd9Sstevel@tonic-gate } else { 18467c478bd9Sstevel@tonic-gate tmp2.tm_mon = mon + 1; 18477c478bd9Sstevel@tonic-gate } 18487c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp2)) == (time_t)-1) { 18497c478bd9Sstevel@tonic-gate return (0); 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate } else if (mon == 1 && day > d1) { 18527c478bd9Sstevel@tonic-gate /* 18537c478bd9Sstevel@tonic-gate * ie 29th in the non-leap year. Forwarding the 18547c478bd9Sstevel@tonic-gate * clock to Feb 29th 00:00 (March 1st), and recalculate 18557c478bd9Sstevel@tonic-gate * the next time. 18567c478bd9Sstevel@tonic-gate */ 18577c478bd9Sstevel@tonic-gate tmp2 = tmp; 18587c478bd9Sstevel@tonic-gate tmp2.tm_min = 0; 18597c478bd9Sstevel@tonic-gate tmp2.tm_hour = 0; 18607c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp2)) == (time_t)-1) { 18617c478bd9Sstevel@tonic-gate return (0); 18627c478bd9Sstevel@tonic-gate } 18637c478bd9Sstevel@tonic-gate } else if (daylight) { 18647c478bd9Sstevel@tonic-gate /* 18657c478bd9Sstevel@tonic-gate * Non existing time, eg 2am PST during summer time 18667c478bd9Sstevel@tonic-gate * switch. 18677c478bd9Sstevel@tonic-gate * We need to get the correct isdst which we are 18687c478bd9Sstevel@tonic-gate * swithing to, by adding time difference to make sure 18697c478bd9Sstevel@tonic-gate * that t2 is in the zone being switched. 18707c478bd9Sstevel@tonic-gate */ 18717c478bd9Sstevel@tonic-gate t2 = t1; 18727c478bd9Sstevel@tonic-gate t2 += abs(timezone - altzone); 18737c478bd9Sstevel@tonic-gate (void) localtime_r(&t2, &tmp2); 18747c478bd9Sstevel@tonic-gate zone_start = get_switching_time(tmp2.tm_isdst, 18754c4c9110Sbasabi t1 - abs(timezone - altzone)); 18767c478bd9Sstevel@tonic-gate if (zone_start == (time_t)-1) { 18777c478bd9Sstevel@tonic-gate return (0); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate t = zone_start; 18807c478bd9Sstevel@tonic-gate } else { 18817c478bd9Sstevel@tonic-gate /* 18827c478bd9Sstevel@tonic-gate * This should never happen, but fall back to the 18837c478bd9Sstevel@tonic-gate * old code. 18847c478bd9Sstevel@tonic-gate */ 18857c478bd9Sstevel@tonic-gate days = days_btwn(tm->tm_mon, 18864c4c9110Sbasabi tm->tm_mday, tm->tm_year, mon, day, yr); 18877c478bd9Sstevel@tonic-gate t += (time_t)(23-tm->tm_hour)*HOUR 18884c4c9110Sbasabi + (time_t)(60-tm->tm_min)*MINUTE 18894c4c9110Sbasabi + (time_t)hr*HOUR + (time_t)min*MINUTE 18904c4c9110Sbasabi + (time_t)days*DAY; 18917c478bd9Sstevel@tonic-gate t1 = t; 18927c478bd9Sstevel@tonic-gate t -= (time_t)tm->tm_sec; 18937c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp); 18947c478bd9Sstevel@tonic-gate if ((tm->tm_isdst == 0) && (tmp.tm_isdst > 0)) 18957c478bd9Sstevel@tonic-gate t -= (timezone - altzone); 18967c478bd9Sstevel@tonic-gate return (t <= ref_t ? t1 : t); 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate goto recalc; 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 19017c478bd9Sstevel@tonic-gate } 19027c478bd9Sstevel@tonic-gate 1903*5b08e637SChris Gerhard static time_t 1904*5b08e637SChris Gerhard next_time(struct event *e, time_t tflag) 1905*5b08e637SChris Gerhard { 1906*5b08e637SChris Gerhard if (e->of.ct.tz != NULL) { 1907*5b08e637SChris Gerhard time_t ret; 1908*5b08e637SChris Gerhard 1909*5b08e637SChris Gerhard (void) putenv((char *)get_obj(e->of.ct.tz)); 1910*5b08e637SChris Gerhard tzset(); 1911*5b08e637SChris Gerhard ret = tz_next_time(e, tflag); 1912*5b08e637SChris Gerhard (void) putenv(tzone); 1913*5b08e637SChris Gerhard tzset(); 1914*5b08e637SChris Gerhard return (ret); 1915*5b08e637SChris Gerhard } else { 1916*5b08e637SChris Gerhard return (tz_next_time(e, tflag)); 1917*5b08e637SChris Gerhard } 1918*5b08e637SChris Gerhard } 1919*5b08e637SChris Gerhard 19207c478bd9Sstevel@tonic-gate /* 19217c478bd9Sstevel@tonic-gate * This returns TOD in time_t that zone switch will happen, and this 19227c478bd9Sstevel@tonic-gate * will be called when clock fallback is about to happen. 19237c478bd9Sstevel@tonic-gate * (ie 30minutes before the time of PST -> PDT switch. 2:00 AM PST 19247c478bd9Sstevel@tonic-gate * will fall back to 1:00 PDT. So this function will be called only 19257c478bd9Sstevel@tonic-gate * for the time between 1:00 AM PST and 2:00 PST(1:00 PST)). 19267c478bd9Sstevel@tonic-gate * First goes through the common time differences to see if zone 19277c478bd9Sstevel@tonic-gate * switch happens at those minutes later. If not, check every minutes 19287c478bd9Sstevel@tonic-gate * until 6 hours ahead see if it happens(We might have 45minutes 19297c478bd9Sstevel@tonic-gate * fallback). 19307c478bd9Sstevel@tonic-gate */ 19317c478bd9Sstevel@tonic-gate static time_t 19327c478bd9Sstevel@tonic-gate get_switching_time(int to_dst, time_t t_ref) 19337c478bd9Sstevel@tonic-gate { 19347c478bd9Sstevel@tonic-gate time_t t, t1; 19357c478bd9Sstevel@tonic-gate struct tm tmp, tmp1; 19367c478bd9Sstevel@tonic-gate int hints[] = { 60, 120, 30, 90, 0}; /* minutes */ 19377c478bd9Sstevel@tonic-gate int i; 19387c478bd9Sstevel@tonic-gate 19397c478bd9Sstevel@tonic-gate (void) localtime_r(&t_ref, &tmp); 19407c478bd9Sstevel@tonic-gate tmp1 = tmp; 19417c478bd9Sstevel@tonic-gate tmp1.tm_sec = 0; 19427c478bd9Sstevel@tonic-gate tmp1.tm_min = 0; 19437c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp1)) == (time_t)-1) 19447c478bd9Sstevel@tonic-gate return ((time_t)-1); 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate /* fast path */ 19477c478bd9Sstevel@tonic-gate for (i = 0; hints[i] != 0; i++) { 19487c478bd9Sstevel@tonic-gate t1 = t + hints[i] * 60; 19497c478bd9Sstevel@tonic-gate (void) localtime_r(&t1, &tmp1); 19507c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst == to_dst) { 19517c478bd9Sstevel@tonic-gate t1--; 19527c478bd9Sstevel@tonic-gate (void) localtime_r(&t1, &tmp1); 19537c478bd9Sstevel@tonic-gate if (tmp1.tm_isdst != to_dst) { 19547c478bd9Sstevel@tonic-gate return (t1 + 1); 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate } 19587c478bd9Sstevel@tonic-gate 19597c478bd9Sstevel@tonic-gate /* ugly, but don't know other than this. */ 19607c478bd9Sstevel@tonic-gate tmp1 = tmp; 19617c478bd9Sstevel@tonic-gate tmp1.tm_sec = 0; 19627c478bd9Sstevel@tonic-gate if ((t = xmktime(&tmp1)) == (time_t)-1) 19637c478bd9Sstevel@tonic-gate return ((time_t)-1); 19647c478bd9Sstevel@tonic-gate while (t < (t_ref + 6*60*60)) { /* 6 hours should be enough */ 19657c478bd9Sstevel@tonic-gate t += 60; /* at least one minute, I assume */ 19667c478bd9Sstevel@tonic-gate (void) localtime_r(&t, &tmp); 19677c478bd9Sstevel@tonic-gate if (tmp.tm_isdst == to_dst) 19687c478bd9Sstevel@tonic-gate return (t); 19697c478bd9Sstevel@tonic-gate } 19707c478bd9Sstevel@tonic-gate return ((time_t)-1); 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate 19737c478bd9Sstevel@tonic-gate static time_t 19747c478bd9Sstevel@tonic-gate xmktime(struct tm *tmp) 19757c478bd9Sstevel@tonic-gate { 19767c478bd9Sstevel@tonic-gate time_t ret; 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate if ((ret = mktime(tmp)) == (time_t)-1) { 19797c478bd9Sstevel@tonic-gate if (errno == EOVERFLOW) { 19807c478bd9Sstevel@tonic-gate return ((time_t)-1); 19817c478bd9Sstevel@tonic-gate } 19827c478bd9Sstevel@tonic-gate crabort("internal error: mktime failed", 19834c4c9110Sbasabi REMOVE_FIFO|CONSOLE_MSG); 19847c478bd9Sstevel@tonic-gate } 19857c478bd9Sstevel@tonic-gate return (ret); 19867c478bd9Sstevel@tonic-gate } 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate #define DUMMY 100 19897c478bd9Sstevel@tonic-gate 19907c478bd9Sstevel@tonic-gate static int 19917c478bd9Sstevel@tonic-gate next_ge(int current, char *list) 19927c478bd9Sstevel@tonic-gate { 19937c478bd9Sstevel@tonic-gate /* 19947c478bd9Sstevel@tonic-gate * list is a character field as in a crontab file; 19957c478bd9Sstevel@tonic-gate * for example: "40, 20, 50-10" 19967c478bd9Sstevel@tonic-gate * next_ge returns the next number in the list that is 19977c478bd9Sstevel@tonic-gate * greater than or equal to current. if no numbers of list 19987c478bd9Sstevel@tonic-gate * are >= current, the smallest element of list is returned. 19997c478bd9Sstevel@tonic-gate * NOTE: current must be in the appropriate range. 20007c478bd9Sstevel@tonic-gate */ 20017c478bd9Sstevel@tonic-gate 20027c478bd9Sstevel@tonic-gate char *ptr; 20037c478bd9Sstevel@tonic-gate int n, n2, min, min_gt; 20047c478bd9Sstevel@tonic-gate 20057c478bd9Sstevel@tonic-gate if (strcmp(list, "*") == 0) 20067c478bd9Sstevel@tonic-gate return (current); 20077c478bd9Sstevel@tonic-gate ptr = list; 20087c478bd9Sstevel@tonic-gate min = DUMMY; 20097c478bd9Sstevel@tonic-gate min_gt = DUMMY; 20107c478bd9Sstevel@tonic-gate for (;;) { 20117c478bd9Sstevel@tonic-gate if ((n = (int)num(&ptr)) == current) 20127c478bd9Sstevel@tonic-gate return (current); 20137c478bd9Sstevel@tonic-gate if (n < min) 20147c478bd9Sstevel@tonic-gate min = n; 20157c478bd9Sstevel@tonic-gate if ((n > current) && (n < min_gt)) 20167c478bd9Sstevel@tonic-gate min_gt = n; 20177c478bd9Sstevel@tonic-gate if (*ptr == '-') { 20187c478bd9Sstevel@tonic-gate ptr++; 20197c478bd9Sstevel@tonic-gate if ((n2 = (int)num(&ptr)) > n) { 20207c478bd9Sstevel@tonic-gate if ((current > n) && (current <= n2)) 20217c478bd9Sstevel@tonic-gate return (current); 20227c478bd9Sstevel@tonic-gate } else { /* range that wraps around */ 20237c478bd9Sstevel@tonic-gate if (current > n) 20247c478bd9Sstevel@tonic-gate return (current); 20257c478bd9Sstevel@tonic-gate if (current <= n2) 20267c478bd9Sstevel@tonic-gate return (current); 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate if (*ptr == '\0') 20307c478bd9Sstevel@tonic-gate break; 20317c478bd9Sstevel@tonic-gate ptr += 1; 20327c478bd9Sstevel@tonic-gate } 20337c478bd9Sstevel@tonic-gate if (min_gt != DUMMY) 20347c478bd9Sstevel@tonic-gate return (min_gt); 20357c478bd9Sstevel@tonic-gate else 20367c478bd9Sstevel@tonic-gate return (min); 20377c478bd9Sstevel@tonic-gate } 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate static void 20407c478bd9Sstevel@tonic-gate free_if_unused(struct usr *u) 20417c478bd9Sstevel@tonic-gate { 20427c478bd9Sstevel@tonic-gate struct usr *cur, *prev; 20437c478bd9Sstevel@tonic-gate /* 20447c478bd9Sstevel@tonic-gate * To make sure a usr structure is idle we must check that 20457c478bd9Sstevel@tonic-gate * there are no at jobs queued for the user; the user does 20467c478bd9Sstevel@tonic-gate * not have a crontab, and also that there are no running at 20477c478bd9Sstevel@tonic-gate * or cron jobs (since the runinfo structure also has a 20487c478bd9Sstevel@tonic-gate * pointer to the usr structure). 20497c478bd9Sstevel@tonic-gate */ 20507c478bd9Sstevel@tonic-gate if (!u->ctexists && u->atevents == NULL && 20517c478bd9Sstevel@tonic-gate u->cruncnt == 0 && u->aruncnt == 0) { 20527c478bd9Sstevel@tonic-gate #ifdef DEBUG 20537c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s removed from usr list\n", u->name); 20547c478bd9Sstevel@tonic-gate #endif 20557c478bd9Sstevel@tonic-gate for (cur = uhead, prev = NULL; 20564c4c9110Sbasabi cur != u; 20574c4c9110Sbasabi prev = cur, cur = cur->nextusr) { 20587c478bd9Sstevel@tonic-gate if (cur == NULL) { 20597c478bd9Sstevel@tonic-gate return; 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate } 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate if (prev == NULL) 20647c478bd9Sstevel@tonic-gate uhead = u->nextusr; 20657c478bd9Sstevel@tonic-gate else 20667c478bd9Sstevel@tonic-gate prev->nextusr = u->nextusr; 20677c478bd9Sstevel@tonic-gate free(u->name); 20687c478bd9Sstevel@tonic-gate free(u->home); 20697c478bd9Sstevel@tonic-gate free(u); 20707c478bd9Sstevel@tonic-gate } 20717c478bd9Sstevel@tonic-gate } 20727c478bd9Sstevel@tonic-gate 20737c478bd9Sstevel@tonic-gate static void 20747c478bd9Sstevel@tonic-gate del_atjob(char *name, char *usrname) 20757c478bd9Sstevel@tonic-gate { 20767c478bd9Sstevel@tonic-gate 20777c478bd9Sstevel@tonic-gate struct event *e, *eprev; 20787c478bd9Sstevel@tonic-gate struct usr *u; 20797c478bd9Sstevel@tonic-gate 20807c478bd9Sstevel@tonic-gate if ((u = find_usr(usrname)) == NULL) 20817c478bd9Sstevel@tonic-gate return; 20827c478bd9Sstevel@tonic-gate e = u->atevents; 20837c478bd9Sstevel@tonic-gate eprev = NULL; 20847c478bd9Sstevel@tonic-gate while (e != NULL) { 20857c478bd9Sstevel@tonic-gate if (strcmp(name, e->cmd) == 0) { 20867c478bd9Sstevel@tonic-gate if (next_event == e) 20877c478bd9Sstevel@tonic-gate next_event = NULL; 20887c478bd9Sstevel@tonic-gate if (eprev == NULL) 20897c478bd9Sstevel@tonic-gate u->atevents = e->link; 20907c478bd9Sstevel@tonic-gate else 20917c478bd9Sstevel@tonic-gate eprev->link = e->link; 20927c478bd9Sstevel@tonic-gate el_remove(e->of.at.eventid, 1); 20937c478bd9Sstevel@tonic-gate free(e->cmd); 20947c478bd9Sstevel@tonic-gate free(e); 20957c478bd9Sstevel@tonic-gate break; 20967c478bd9Sstevel@tonic-gate } else { 20977c478bd9Sstevel@tonic-gate eprev = e; 20987c478bd9Sstevel@tonic-gate e = e->link; 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate } 21017c478bd9Sstevel@tonic-gate 21027c478bd9Sstevel@tonic-gate free_if_unused(u); 21037c478bd9Sstevel@tonic-gate } 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate static void 21067c478bd9Sstevel@tonic-gate del_ctab(char *name) 21077c478bd9Sstevel@tonic-gate { 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate struct usr *u; 21107c478bd9Sstevel@tonic-gate 21117c478bd9Sstevel@tonic-gate if ((u = find_usr(name)) == NULL) 21127c478bd9Sstevel@tonic-gate return; 21137c478bd9Sstevel@tonic-gate rm_ctevents(u); 21147c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0); 21157c478bd9Sstevel@tonic-gate u->ctid = 0; 21167c478bd9Sstevel@tonic-gate u->ctexists = 0; 21177c478bd9Sstevel@tonic-gate 21187c478bd9Sstevel@tonic-gate free_if_unused(u); 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate static void 21227c478bd9Sstevel@tonic-gate rm_ctevents(struct usr *u) 21237c478bd9Sstevel@tonic-gate { 21247c478bd9Sstevel@tonic-gate struct event *e2, *e3; 21257c478bd9Sstevel@tonic-gate 21267c478bd9Sstevel@tonic-gate /* 21277c478bd9Sstevel@tonic-gate * see if the next event (to be run by cron) is a cronevent 21287c478bd9Sstevel@tonic-gate * owned by this user. 21297c478bd9Sstevel@tonic-gate */ 21307c478bd9Sstevel@tonic-gate 21317c478bd9Sstevel@tonic-gate if ((next_event != NULL) && 21327c478bd9Sstevel@tonic-gate (next_event->etype == CRONEVENT) && 21337c478bd9Sstevel@tonic-gate (next_event->u == u)) { 21347c478bd9Sstevel@tonic-gate next_event = NULL; 21357c478bd9Sstevel@tonic-gate } 21367c478bd9Sstevel@tonic-gate e2 = u->ctevents; 21377c478bd9Sstevel@tonic-gate while (e2 != NULL) { 21387c478bd9Sstevel@tonic-gate free(e2->cmd); 2139*5b08e637SChris Gerhard rel_shared(e2->of.ct.tz); 2140*5b08e637SChris Gerhard rel_shared(e2->of.ct.shell); 2141*5b08e637SChris Gerhard rel_shared(e2->of.ct.home); 21427c478bd9Sstevel@tonic-gate free(e2->of.ct.minute); 21437c478bd9Sstevel@tonic-gate free(e2->of.ct.hour); 21447c478bd9Sstevel@tonic-gate free(e2->of.ct.daymon); 21457c478bd9Sstevel@tonic-gate free(e2->of.ct.month); 21467c478bd9Sstevel@tonic-gate free(e2->of.ct.dayweek); 21477c478bd9Sstevel@tonic-gate if (e2->of.ct.input != NULL) 21487c478bd9Sstevel@tonic-gate free(e2->of.ct.input); 21497c478bd9Sstevel@tonic-gate e3 = e2->link; 21507c478bd9Sstevel@tonic-gate free(e2); 21517c478bd9Sstevel@tonic-gate e2 = e3; 21527c478bd9Sstevel@tonic-gate } 21537c478bd9Sstevel@tonic-gate u->ctevents = NULL; 21547c478bd9Sstevel@tonic-gate } 21557c478bd9Sstevel@tonic-gate 21567c478bd9Sstevel@tonic-gate 21577c478bd9Sstevel@tonic-gate static struct usr * 21587c478bd9Sstevel@tonic-gate find_usr(char *uname) 21597c478bd9Sstevel@tonic-gate { 21607c478bd9Sstevel@tonic-gate struct usr *u; 21617c478bd9Sstevel@tonic-gate 21627c478bd9Sstevel@tonic-gate u = uhead; 21637c478bd9Sstevel@tonic-gate while (u != NULL) { 21647c478bd9Sstevel@tonic-gate if (strcmp(u->name, uname) == 0) 21657c478bd9Sstevel@tonic-gate return (u); 21667c478bd9Sstevel@tonic-gate u = u->nextusr; 21677c478bd9Sstevel@tonic-gate } 21687c478bd9Sstevel@tonic-gate return (NULL); 21697c478bd9Sstevel@tonic-gate } 21707c478bd9Sstevel@tonic-gate 21717c478bd9Sstevel@tonic-gate /* 21727c478bd9Sstevel@tonic-gate * Execute cron command or at/batch job. 21737c478bd9Sstevel@tonic-gate * If ever a premature return is added to this function pay attention to 21747c478bd9Sstevel@tonic-gate * free at_cmdfile and outfile plus jobname buffers of the runinfo structure. 21757c478bd9Sstevel@tonic-gate */ 21767c478bd9Sstevel@tonic-gate static int 21777c478bd9Sstevel@tonic-gate ex(struct event *e) 21787c478bd9Sstevel@tonic-gate { 21797c478bd9Sstevel@tonic-gate int r; 21807c478bd9Sstevel@tonic-gate int fd; 21817c478bd9Sstevel@tonic-gate pid_t rfork; 21827c478bd9Sstevel@tonic-gate FILE *atcmdfp; 21837c478bd9Sstevel@tonic-gate char mailvar[4]; 21847c478bd9Sstevel@tonic-gate char *at_cmdfile = NULL; 21857c478bd9Sstevel@tonic-gate struct stat buf; 21867c478bd9Sstevel@tonic-gate struct queue *qp; 21877c478bd9Sstevel@tonic-gate struct runinfo *rp; 21887c478bd9Sstevel@tonic-gate struct project proj, *pproj = NULL; 2189*5b08e637SChris Gerhard union { 2190*5b08e637SChris Gerhard struct { 2191*5b08e637SChris Gerhard char buf[PROJECT_BUFSZ]; 2192*5b08e637SChris Gerhard char buf2[PROJECT_BUFSZ]; 2193*5b08e637SChris Gerhard } p; 2194*5b08e637SChris Gerhard char error[CANT_STR_LEN + PATH_MAX]; 2195*5b08e637SChris Gerhard } bufs; 21967c478bd9Sstevel@tonic-gate char *tmpfile; 21977c478bd9Sstevel@tonic-gate FILE *fptr; 21987c478bd9Sstevel@tonic-gate time_t dhltime; 21997c478bd9Sstevel@tonic-gate projid_t projid; 22007c478bd9Sstevel@tonic-gate int projflag = 0; 2201*5b08e637SChris Gerhard char *home; 2202*5b08e637SChris Gerhard char *sh; 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate qp = &qt[e->etype]; /* set pointer to queue defs */ 22057c478bd9Sstevel@tonic-gate if (qp->nrun >= qp->njob) { 22064c4c9110Sbasabi msg("%c queue max run limit reached", e->etype + 'a'); 22077c478bd9Sstevel@tonic-gate resched(qp->nwait); 22087c478bd9Sstevel@tonic-gate return (0); 22097c478bd9Sstevel@tonic-gate } 22109f163834Sbasabi rp = rinfo_get(0); /* allocating a new runinfo struct */ 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate 22137c478bd9Sstevel@tonic-gate /* 22147c478bd9Sstevel@tonic-gate * the tempnam() function uses malloc(3C) to allocate space for the 22157c478bd9Sstevel@tonic-gate * constructed file name, and returns a pointer to this area, which 22167c478bd9Sstevel@tonic-gate * is assigned to rp->outfile. Here rp->outfile is not overwritten. 22177c478bd9Sstevel@tonic-gate */ 22187c478bd9Sstevel@tonic-gate 22197c478bd9Sstevel@tonic-gate rp->outfile = tempnam(TMPDIR, PFX); 22207c478bd9Sstevel@tonic-gate rp->jobtype = e->etype; 22217c478bd9Sstevel@tonic-gate if (e->etype == CRONEVENT) { 22224c4c9110Sbasabi rp->jobname = xmalloc(strlen(e->cmd) + 1); 22237c478bd9Sstevel@tonic-gate (void) strcpy(rp->jobname, e->cmd); 22247c478bd9Sstevel@tonic-gate /* "cron" jobs only produce mail if there's output */ 22257c478bd9Sstevel@tonic-gate rp->mailwhendone = 0; 22267c478bd9Sstevel@tonic-gate } else { 22274c4c9110Sbasabi at_cmdfile = xmalloc(strlen(ATDIR) + strlen(e->cmd) + 2); 22287c478bd9Sstevel@tonic-gate (void) sprintf(at_cmdfile, "%s/%s", ATDIR, e->cmd); 22297c478bd9Sstevel@tonic-gate if ((atcmdfp = fopen(at_cmdfile, "r")) == NULL) { 22307c478bd9Sstevel@tonic-gate if (errno == ENAMETOOLONG) { 22317c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == 0) 22327c478bd9Sstevel@tonic-gate cron_unlink(e->cmd); 22337c478bd9Sstevel@tonic-gate } else { 22347c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 22357c478bd9Sstevel@tonic-gate } 22367c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECAT); 22377c478bd9Sstevel@tonic-gate free(at_cmdfile); 22387c478bd9Sstevel@tonic-gate rinfo_free(rp); 22397c478bd9Sstevel@tonic-gate return (0); 22407c478bd9Sstevel@tonic-gate } 22414c4c9110Sbasabi rp->jobname = xmalloc(strlen(at_cmdfile) + 1); 22427c478bd9Sstevel@tonic-gate (void) strcpy(rp->jobname, at_cmdfile); 22437c478bd9Sstevel@tonic-gate 22447c478bd9Sstevel@tonic-gate /* 22457c478bd9Sstevel@tonic-gate * Skip over the first two lines. 22467c478bd9Sstevel@tonic-gate */ 22477c478bd9Sstevel@tonic-gate (void) fscanf(atcmdfp, "%*[^\n]\n"); 22487c478bd9Sstevel@tonic-gate (void) fscanf(atcmdfp, "%*[^\n]\n"); 22497c478bd9Sstevel@tonic-gate if (fscanf(atcmdfp, ": notify by mail: %3s%*[^\n]\n", 22504c4c9110Sbasabi mailvar) == 1) { 22517c478bd9Sstevel@tonic-gate /* 22527c478bd9Sstevel@tonic-gate * Check to see if we should always send mail 22537c478bd9Sstevel@tonic-gate * to the owner. 22547c478bd9Sstevel@tonic-gate */ 22557c478bd9Sstevel@tonic-gate rp->mailwhendone = (strcmp(mailvar, "yes") == 0); 22567c478bd9Sstevel@tonic-gate } else { 22577c478bd9Sstevel@tonic-gate rp->mailwhendone = 0; 22587c478bd9Sstevel@tonic-gate } 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate if (fscanf(atcmdfp, "\n: project: %d\n", &projid) == 1) { 22617c478bd9Sstevel@tonic-gate projflag = 1; 22627c478bd9Sstevel@tonic-gate } 22637c478bd9Sstevel@tonic-gate (void) fclose(atcmdfp); 22647c478bd9Sstevel@tonic-gate } 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate /* 22677c478bd9Sstevel@tonic-gate * we make sure that the system time 22687c478bd9Sstevel@tonic-gate * hasn't drifted backwards. if it has, el_add() is now 22697c478bd9Sstevel@tonic-gate * called, to make sure that the event queue is back in order, 22707c478bd9Sstevel@tonic-gate * and we set the delayed flag. cron will pick up the request 22717c478bd9Sstevel@tonic-gate * later on at the proper time. 22727c478bd9Sstevel@tonic-gate */ 22737c478bd9Sstevel@tonic-gate dhltime = time(NULL); 22747c478bd9Sstevel@tonic-gate if ((dhltime - e->time) < 0) { 22757c478bd9Sstevel@tonic-gate msg("clock time drifted backwards!\n"); 22767c478bd9Sstevel@tonic-gate if (next_event->etype == CRONEVENT) { 22777c478bd9Sstevel@tonic-gate msg("correcting cron event\n"); 22787c478bd9Sstevel@tonic-gate next_event->time = next_time(next_event, dhltime); 2279e2553d68SSerge Dussud switch (el_add(next_event, next_event->time, 2280e2553d68SSerge Dussud (next_event->u)->ctid)) { 2281e2553d68SSerge Dussud case -1: 2282e2553d68SSerge Dussud ignore_msg("ex", "cron", next_event); 2283e2553d68SSerge Dussud break; 2284e2553d68SSerge Dussud case -2: /* event time lower than init time */ 2285e2553d68SSerge Dussud reset_needed = 1; 2286e2553d68SSerge Dussud break; 2287e2553d68SSerge Dussud } 22887c478bd9Sstevel@tonic-gate } else { /* etype == ATEVENT */ 22897c478bd9Sstevel@tonic-gate msg("correcting batch event\n"); 2290e2553d68SSerge Dussud if (el_add(next_event, next_event->time, 2291e2553d68SSerge Dussud next_event->of.at.eventid) < 0) { 2292e2553d68SSerge Dussud ignore_msg("ex", "at", next_event); 2293e2553d68SSerge Dussud } 22947c478bd9Sstevel@tonic-gate } 22957c478bd9Sstevel@tonic-gate delayed++; 22967c478bd9Sstevel@tonic-gate t_old = time(NULL); 22977c478bd9Sstevel@tonic-gate free(at_cmdfile); 22987c478bd9Sstevel@tonic-gate rinfo_free(rp); 22997c478bd9Sstevel@tonic-gate return (0); 23007c478bd9Sstevel@tonic-gate } 23017c478bd9Sstevel@tonic-gate 23027c478bd9Sstevel@tonic-gate if ((rfork = fork()) == (pid_t)-1) { 23037c478bd9Sstevel@tonic-gate reap_child(); 23047c478bd9Sstevel@tonic-gate if ((rfork = fork()) == (pid_t)-1) { 23057c478bd9Sstevel@tonic-gate msg("cannot fork"); 23067c478bd9Sstevel@tonic-gate free(at_cmdfile); 23077c478bd9Sstevel@tonic-gate rinfo_free(rp); 23087c478bd9Sstevel@tonic-gate resched(60); 23097c478bd9Sstevel@tonic-gate (void) sleep(30); 23107c478bd9Sstevel@tonic-gate return (0); 23117c478bd9Sstevel@tonic-gate } 23127c478bd9Sstevel@tonic-gate } 23137c478bd9Sstevel@tonic-gate if (rfork) { /* parent process */ 23147c478bd9Sstevel@tonic-gate contract_abandon_latest(rfork); 23157c478bd9Sstevel@tonic-gate 23167c478bd9Sstevel@tonic-gate ++qp->nrun; 23177c478bd9Sstevel@tonic-gate rp->pid = rfork; 23187c478bd9Sstevel@tonic-gate rp->que = e->etype; 23197c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) 23207c478bd9Sstevel@tonic-gate (e->u)->aruncnt++; 23217c478bd9Sstevel@tonic-gate else 23227c478bd9Sstevel@tonic-gate (e->u)->cruncnt++; 23237c478bd9Sstevel@tonic-gate rp->rusr = (e->u); 23247c478bd9Sstevel@tonic-gate logit(BCHAR, rp, 0); 23257c478bd9Sstevel@tonic-gate free(at_cmdfile); 23267c478bd9Sstevel@tonic-gate 23277c478bd9Sstevel@tonic-gate return (0); 23287c478bd9Sstevel@tonic-gate } 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate child_sigreset(); 23317c478bd9Sstevel@tonic-gate contract_clear_template(); 23327c478bd9Sstevel@tonic-gate 23337c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) { 23347c478bd9Sstevel@tonic-gate /* open jobfile as stdin to shell */ 23357c478bd9Sstevel@tonic-gate if (stat(at_cmdfile, &buf)) { 23367c478bd9Sstevel@tonic-gate if (errno == ENAMETOOLONG) { 23377c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == 0) 23387c478bd9Sstevel@tonic-gate cron_unlink(e->cmd); 23397c478bd9Sstevel@tonic-gate } else 23407c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 23417c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECCRON); 23427c478bd9Sstevel@tonic-gate exit(1); 23437c478bd9Sstevel@tonic-gate } 23447c478bd9Sstevel@tonic-gate if (!(buf.st_mode&ISUID)) { 23457c478bd9Sstevel@tonic-gate /* 23467c478bd9Sstevel@tonic-gate * if setuid bit off, original owner has 23477c478bd9Sstevel@tonic-gate * given this file to someone else 23487c478bd9Sstevel@tonic-gate */ 23497c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 23507c478bd9Sstevel@tonic-gate exit(1); 23517c478bd9Sstevel@tonic-gate } 23527c478bd9Sstevel@tonic-gate if ((fd = open(at_cmdfile, O_RDONLY)) == -1) { 23537c478bd9Sstevel@tonic-gate mail((e->u)->name, BADJOBOPEN, ERR_CANTEXECCRON); 23547c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 23557c478bd9Sstevel@tonic-gate exit(1); 23567c478bd9Sstevel@tonic-gate } 23577c478bd9Sstevel@tonic-gate if (fd != 0) { 23587c478bd9Sstevel@tonic-gate (void) dup2(fd, 0); 23597c478bd9Sstevel@tonic-gate (void) close(fd); 23607c478bd9Sstevel@tonic-gate } 23617c478bd9Sstevel@tonic-gate /* 23627c478bd9Sstevel@tonic-gate * retrieve the project id of the at job and convert it 23637c478bd9Sstevel@tonic-gate * to a project name. fail if it's not a valid project 23647c478bd9Sstevel@tonic-gate * or if the user isn't a member of the project. 23657c478bd9Sstevel@tonic-gate */ 23667c478bd9Sstevel@tonic-gate if (projflag == 1) { 23677c478bd9Sstevel@tonic-gate if ((pproj = getprojbyid(projid, &proj, 2368*5b08e637SChris Gerhard (void *)&bufs.p.buf, 2369*5b08e637SChris Gerhard sizeof (bufs.p.buf))) == NULL || 23707c478bd9Sstevel@tonic-gate !inproj(e->u->name, pproj->pj_name, 2371*5b08e637SChris Gerhard bufs.p.buf2, sizeof (bufs.p.buf2))) { 23727c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 23737c478bd9Sstevel@tonic-gate mail((e->u)->name, BADPROJID, ERR_CANTEXECAT); 23747c478bd9Sstevel@tonic-gate exit(1); 23757c478bd9Sstevel@tonic-gate } 23767c478bd9Sstevel@tonic-gate } 23777c478bd9Sstevel@tonic-gate } 23787c478bd9Sstevel@tonic-gate 23797c478bd9Sstevel@tonic-gate /* 23807c478bd9Sstevel@tonic-gate * Put process in a new session, and create a new task. 23817c478bd9Sstevel@tonic-gate */ 23827c478bd9Sstevel@tonic-gate if (setsid() < 0) { 23837c478bd9Sstevel@tonic-gate msg("setsid failed with errno = %d. job failed (%s)" 23847c478bd9Sstevel@tonic-gate " for user %s", errno, e->cmd, e->u->name); 23857c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) 23867c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 23877c478bd9Sstevel@tonic-gate exit(1); 23887c478bd9Sstevel@tonic-gate } 23897c478bd9Sstevel@tonic-gate 23907c478bd9Sstevel@tonic-gate /* 23917c478bd9Sstevel@tonic-gate * set correct user identification and check his account 23927c478bd9Sstevel@tonic-gate */ 23937c478bd9Sstevel@tonic-gate r = set_user_cred(e->u, pproj); 23947c478bd9Sstevel@tonic-gate if (r == VUC_EXPIRED) { 23957c478bd9Sstevel@tonic-gate msg("user (%s) account is expired", e->u->name); 23967c478bd9Sstevel@tonic-gate audit_cron_user_acct_expired(e->u->name); 23977c478bd9Sstevel@tonic-gate clean_out_user(e->u); 23987c478bd9Sstevel@tonic-gate exit(1); 23997c478bd9Sstevel@tonic-gate } 24007c478bd9Sstevel@tonic-gate if (r == VUC_NEW_AUTH) { 24017c478bd9Sstevel@tonic-gate msg("user (%s) password has expired", e->u->name); 24027c478bd9Sstevel@tonic-gate audit_cron_user_acct_expired(e->u->name); 24037c478bd9Sstevel@tonic-gate clean_out_user(e->u); 24047c478bd9Sstevel@tonic-gate exit(1); 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate if (r != VUC_OK) { 24077c478bd9Sstevel@tonic-gate msg("bad user (%s)", e->u->name); 24087c478bd9Sstevel@tonic-gate audit_cron_bad_user(e->u->name); 24097c478bd9Sstevel@tonic-gate clean_out_user(e->u); 24107c478bd9Sstevel@tonic-gate exit(1); 24117c478bd9Sstevel@tonic-gate } 24127c478bd9Sstevel@tonic-gate /* 24137c478bd9Sstevel@tonic-gate * check user and initialize the supplementary group access list. 24147c478bd9Sstevel@tonic-gate * bugid 1230784: deleted from parent to avoid cron hang. Now 24157c478bd9Sstevel@tonic-gate * only child handles the call. 24167c478bd9Sstevel@tonic-gate */ 24177c478bd9Sstevel@tonic-gate 24187c478bd9Sstevel@tonic-gate if (verify_user_cred(e->u) != VUC_OK || 24197c478bd9Sstevel@tonic-gate setgid(e->u->gid) == -1 || 24207c478bd9Sstevel@tonic-gate initgroups(e->u->name, e->u->gid) == -1) { 24217c478bd9Sstevel@tonic-gate msg("bad user (%s) or setgid failed (%s)", 24224c4c9110Sbasabi e->u->name, e->u->name); 24237c478bd9Sstevel@tonic-gate audit_cron_bad_user(e->u->name); 24247c478bd9Sstevel@tonic-gate clean_out_user(e->u); 24257c478bd9Sstevel@tonic-gate exit(1); 24267c478bd9Sstevel@tonic-gate } 24277c478bd9Sstevel@tonic-gate 242863d5d94cSjc if ((e->u)->uid == 0) { /* set default path */ 242963d5d94cSjc /* path settable in defaults file */ 243063d5d94cSjc envinit[2] = supath; 243163d5d94cSjc } else { 243263d5d94cSjc envinit[2] = path; 243363d5d94cSjc } 243463d5d94cSjc 24357c478bd9Sstevel@tonic-gate if (e->etype != CRONEVENT) { 24367c478bd9Sstevel@tonic-gate r = audit_cron_session(e->u->name, NULL, 24374c4c9110Sbasabi e->u->uid, e->u->gid, at_cmdfile); 24387c478bd9Sstevel@tonic-gate cron_unlink(at_cmdfile); 24397c478bd9Sstevel@tonic-gate } else { 24407c478bd9Sstevel@tonic-gate r = audit_cron_session(e->u->name, CRONDIR, 24414c4c9110Sbasabi e->u->uid, e->u->gid, NULL); 24427c478bd9Sstevel@tonic-gate } 24437c478bd9Sstevel@tonic-gate if (r != 0) { 24447c478bd9Sstevel@tonic-gate msg("cron audit problem. job failed (%s) for user %s", 24454c4c9110Sbasabi e->cmd, e->u->name); 24467c478bd9Sstevel@tonic-gate exit(1); 24477c478bd9Sstevel@tonic-gate } 24487c478bd9Sstevel@tonic-gate 24497c478bd9Sstevel@tonic-gate audit_cron_new_job(e->cmd, e->etype, (void *)e); 24507c478bd9Sstevel@tonic-gate 24517c478bd9Sstevel@tonic-gate if (setuid(e->u->uid) == -1) { 24527c478bd9Sstevel@tonic-gate msg("setuid failed (%s)", e->u->name); 24537c478bd9Sstevel@tonic-gate clean_out_user(e->u); 24547c478bd9Sstevel@tonic-gate exit(1); 24557c478bd9Sstevel@tonic-gate } 24567c478bd9Sstevel@tonic-gate 24577c478bd9Sstevel@tonic-gate if (e->etype == CRONEVENT) { 24587c478bd9Sstevel@tonic-gate /* check for standard input to command */ 24597c478bd9Sstevel@tonic-gate if (e->of.ct.input != NULL) { 24607c478bd9Sstevel@tonic-gate if ((tmpfile = strdup(TMPINFILE)) == NULL) { 24617c478bd9Sstevel@tonic-gate mail((e->u)->name, MALLOCERR, 24624c4c9110Sbasabi ERR_CANTEXECCRON); 24637c478bd9Sstevel@tonic-gate exit(1); 24647c478bd9Sstevel@tonic-gate } 24657c478bd9Sstevel@tonic-gate if ((fd = mkstemp(tmpfile)) == -1 || 24664c4c9110Sbasabi (fptr = fdopen(fd, "w")) == NULL) { 24677c478bd9Sstevel@tonic-gate mail((e->u)->name, NOSTDIN, 24684c4c9110Sbasabi ERR_CANTEXECCRON); 24697c478bd9Sstevel@tonic-gate cron_unlink(tmpfile); 24707c478bd9Sstevel@tonic-gate free(tmpfile); 24717c478bd9Sstevel@tonic-gate exit(1); 24727c478bd9Sstevel@tonic-gate } 24737c478bd9Sstevel@tonic-gate if ((fwrite(e->of.ct.input, sizeof (char), 24744c4c9110Sbasabi strlen(e->of.ct.input), fptr)) != 24754c4c9110Sbasabi strlen(e->of.ct.input)) { 24767c478bd9Sstevel@tonic-gate mail((e->u)->name, NOSTDIN, ERR_CANTEXECCRON); 24777c478bd9Sstevel@tonic-gate cron_unlink(tmpfile); 24787c478bd9Sstevel@tonic-gate free(tmpfile); 24797c478bd9Sstevel@tonic-gate (void) close(fd); 24807c478bd9Sstevel@tonic-gate (void) fclose(fptr); 24817c478bd9Sstevel@tonic-gate exit(1); 24827c478bd9Sstevel@tonic-gate } 24837c478bd9Sstevel@tonic-gate if (fseek(fptr, (off_t)0, SEEK_SET) != -1) { 24847c478bd9Sstevel@tonic-gate if (fd != 0) { 24857c478bd9Sstevel@tonic-gate (void) dup2(fd, 0); 24867c478bd9Sstevel@tonic-gate (void) close(fd); 24877c478bd9Sstevel@tonic-gate } 24887c478bd9Sstevel@tonic-gate } 24897c478bd9Sstevel@tonic-gate cron_unlink(tmpfile); 24907c478bd9Sstevel@tonic-gate free(tmpfile); 24917c478bd9Sstevel@tonic-gate (void) fclose(fptr); 24927c478bd9Sstevel@tonic-gate } else if ((fd = open("/dev/null", O_RDONLY)) > 0) { 24937c478bd9Sstevel@tonic-gate (void) dup2(fd, 0); 24947c478bd9Sstevel@tonic-gate (void) close(fd); 24957c478bd9Sstevel@tonic-gate } 24967c478bd9Sstevel@tonic-gate } 24977c478bd9Sstevel@tonic-gate 24987c478bd9Sstevel@tonic-gate /* redirect stdout and stderr for the shell */ 24997c478bd9Sstevel@tonic-gate if ((fd = open(rp->outfile, O_WRONLY|O_CREAT|O_EXCL, OUTMODE)) == 1) 25007c478bd9Sstevel@tonic-gate fd = open("/dev/null", O_WRONLY); 25017c478bd9Sstevel@tonic-gate 25027c478bd9Sstevel@tonic-gate if (fd >= 0 && fd != 1) 25037c478bd9Sstevel@tonic-gate (void) dup2(fd, 1); 25047c478bd9Sstevel@tonic-gate 25057c478bd9Sstevel@tonic-gate if (fd >= 0 && fd != 2) { 25067c478bd9Sstevel@tonic-gate (void) dup2(fd, 2); 25077c478bd9Sstevel@tonic-gate if (fd != 1) 25087c478bd9Sstevel@tonic-gate (void) close(fd); 25097c478bd9Sstevel@tonic-gate } 25107c478bd9Sstevel@tonic-gate 2511*5b08e637SChris Gerhard if (e->etype == CRONEVENT && e->of.ct.home != NULL) { 2512*5b08e637SChris Gerhard home = (char *)get_obj(e->of.ct.home); 2513*5b08e637SChris Gerhard } else { 2514*5b08e637SChris Gerhard home = (e->u)->home; 2515*5b08e637SChris Gerhard } 2516*5b08e637SChris Gerhard (void) strlcat(homedir, home, sizeof (homedir)); 25177c478bd9Sstevel@tonic-gate (void) strlcat(logname, (e->u)->name, sizeof (logname)); 25187c478bd9Sstevel@tonic-gate environ = envinit; 2519*5b08e637SChris Gerhard if (chdir(home) == -1) { 2520*5b08e637SChris Gerhard snprintf(bufs.error, sizeof (bufs.error), CANTCDHOME, home); 2521*5b08e637SChris Gerhard mail((e->u)->name, bufs.error, 25224c4c9110Sbasabi e->etype == CRONEVENT ? ERR_CANTEXECCRON : 25234c4c9110Sbasabi ERR_CANTEXECAT); 25247c478bd9Sstevel@tonic-gate exit(1); 25257c478bd9Sstevel@tonic-gate } 25267c478bd9Sstevel@tonic-gate #ifdef TESTING 25277c478bd9Sstevel@tonic-gate exit(1); 25287c478bd9Sstevel@tonic-gate #endif 25297c478bd9Sstevel@tonic-gate /* 25307c478bd9Sstevel@tonic-gate * make sure that all file descriptors EXCEPT 0, 1 and 2 25317c478bd9Sstevel@tonic-gate * will be closed. 25327c478bd9Sstevel@tonic-gate */ 25337c478bd9Sstevel@tonic-gate closefrom(3); 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate if ((e->u)->uid != 0) 25367c478bd9Sstevel@tonic-gate (void) nice(qp->nice); 2537*5b08e637SChris Gerhard if (e->etype == CRONEVENT) { 2538*5b08e637SChris Gerhard if (e->of.ct.tz) { 2539*5b08e637SChris Gerhard (void) putenv((char *)get_obj(e->of.ct.tz)); 2540*5b08e637SChris Gerhard } 2541*5b08e637SChris Gerhard if (e->of.ct.shell) { 2542*5b08e637SChris Gerhard char *name; 2543*5b08e637SChris Gerhard 2544*5b08e637SChris Gerhard sh = (char *)get_obj(e->of.ct.shell); 2545*5b08e637SChris Gerhard name = strrchr(sh, '/'); 2546*5b08e637SChris Gerhard if (name == NULL) 2547*5b08e637SChris Gerhard name = sh; 2548*5b08e637SChris Gerhard else 2549*5b08e637SChris Gerhard name++; 2550*5b08e637SChris Gerhard 2551*5b08e637SChris Gerhard (void) putenv(sh); 2552*5b08e637SChris Gerhard sh += strlen(ENV_SHELL); 2553*5b08e637SChris Gerhard (void) execl(sh, name, "-c", e->cmd, 0); 2554*5b08e637SChris Gerhard } else { 2555*5b08e637SChris Gerhard (void) execl(SHELL, "sh", "-c", e->cmd, 0); 2556*5b08e637SChris Gerhard sh = SHELL; 2557*5b08e637SChris Gerhard } 2558*5b08e637SChris Gerhard } else { /* type == ATEVENT */ 25597c478bd9Sstevel@tonic-gate (void) execl(SHELL, "sh", 0); 2560*5b08e637SChris Gerhard sh = SHELL; 2561*5b08e637SChris Gerhard } 2562*5b08e637SChris Gerhard snprintf(bufs.error, sizeof (bufs.error), CANTEXECSH, sh); 2563*5b08e637SChris Gerhard mail((e->u)->name, bufs.error, 25644c4c9110Sbasabi e->etype == CRONEVENT ? ERR_CANTEXECCRON : ERR_CANTEXECAT); 25657c478bd9Sstevel@tonic-gate exit(1); 25667c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 25677c478bd9Sstevel@tonic-gate } 25687c478bd9Sstevel@tonic-gate 25697c478bd9Sstevel@tonic-gate static int 25707c478bd9Sstevel@tonic-gate idle(long t) 25717c478bd9Sstevel@tonic-gate { 25727c478bd9Sstevel@tonic-gate time_t now; 25737c478bd9Sstevel@tonic-gate 25747c478bd9Sstevel@tonic-gate while (t > 0L) { 25757c478bd9Sstevel@tonic-gate 25767c478bd9Sstevel@tonic-gate if (msg_wait(t) != 0) { 25777c478bd9Sstevel@tonic-gate /* we need to run next job immediately */ 25787c478bd9Sstevel@tonic-gate return (0); 25797c478bd9Sstevel@tonic-gate } 25807c478bd9Sstevel@tonic-gate 25817c478bd9Sstevel@tonic-gate reap_child(); 25827c478bd9Sstevel@tonic-gate 25837c478bd9Sstevel@tonic-gate now = time(NULL); 25847c478bd9Sstevel@tonic-gate if (last_time > now) { 25857c478bd9Sstevel@tonic-gate /* clock has been reset */ 25867c478bd9Sstevel@tonic-gate return (1); 25877c478bd9Sstevel@tonic-gate } 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate if (next_event == NULL && !el_empty()) { 25907c478bd9Sstevel@tonic-gate next_event = (struct event *)el_first(); 25917c478bd9Sstevel@tonic-gate } 25927c478bd9Sstevel@tonic-gate if (next_event == NULL) 25937c478bd9Sstevel@tonic-gate t = INFINITY; 25947c478bd9Sstevel@tonic-gate else 25957c478bd9Sstevel@tonic-gate t = (long)next_event->time - now; 25967c478bd9Sstevel@tonic-gate } 25977c478bd9Sstevel@tonic-gate return (0); 25987c478bd9Sstevel@tonic-gate } 25997c478bd9Sstevel@tonic-gate 26007c478bd9Sstevel@tonic-gate /* 26017c478bd9Sstevel@tonic-gate * This used to be in the idle(), but moved to the separate function. 26027c478bd9Sstevel@tonic-gate * This called from various place when cron needs to reap the 26037c478bd9Sstevel@tonic-gate * child. It includes the situation that cron hit maxrun, and needs 26047c478bd9Sstevel@tonic-gate * to reschedule the job. 26057c478bd9Sstevel@tonic-gate */ 26067c478bd9Sstevel@tonic-gate static void 26077c478bd9Sstevel@tonic-gate reap_child() 26087c478bd9Sstevel@tonic-gate { 26097c478bd9Sstevel@tonic-gate pid_t pid; 26107c478bd9Sstevel@tonic-gate int prc; 26117c478bd9Sstevel@tonic-gate struct runinfo *rp; 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate for (;;) { 26147c478bd9Sstevel@tonic-gate pid = waitpid((pid_t)-1, &prc, WNOHANG); 26157c478bd9Sstevel@tonic-gate if (pid <= 0) 26167c478bd9Sstevel@tonic-gate break; 26177c478bd9Sstevel@tonic-gate #ifdef DEBUG 26187c478bd9Sstevel@tonic-gate fprintf(stderr, 26194c4c9110Sbasabi "wait returned %x for process %d\n", prc, pid); 26207c478bd9Sstevel@tonic-gate #endif 26217c478bd9Sstevel@tonic-gate if ((rp = rinfo_get(pid)) == NULL) { 26227c478bd9Sstevel@tonic-gate if (miscpid_delete(pid) == 0) { 26237c478bd9Sstevel@tonic-gate /* not found in anywhere */ 26247c478bd9Sstevel@tonic-gate msg(PIDERR, pid); 26257c478bd9Sstevel@tonic-gate } 26267c478bd9Sstevel@tonic-gate } else if (rp->que == ZOMB) { 26277c478bd9Sstevel@tonic-gate (void) unlink(rp->outfile); 26287c478bd9Sstevel@tonic-gate rinfo_free(rp); 26297c478bd9Sstevel@tonic-gate } else { 26307c478bd9Sstevel@tonic-gate cleanup(rp, prc); 26317c478bd9Sstevel@tonic-gate } 26327c478bd9Sstevel@tonic-gate } 26337c478bd9Sstevel@tonic-gate } 26347c478bd9Sstevel@tonic-gate 26357c478bd9Sstevel@tonic-gate static void 26367c478bd9Sstevel@tonic-gate cleanup(struct runinfo *pr, int rc) 26377c478bd9Sstevel@tonic-gate { 26387c478bd9Sstevel@tonic-gate int nextfork = 1; 26397c478bd9Sstevel@tonic-gate struct usr *p; 26407c478bd9Sstevel@tonic-gate struct stat buf; 26417c478bd9Sstevel@tonic-gate 26427c478bd9Sstevel@tonic-gate logit(ECHAR, pr, rc); 26437c478bd9Sstevel@tonic-gate --qt[pr->que].nrun; 26447c478bd9Sstevel@tonic-gate p = pr->rusr; 26457c478bd9Sstevel@tonic-gate if (pr->que != CRONEVENT) 26467c478bd9Sstevel@tonic-gate --p->aruncnt; 26477c478bd9Sstevel@tonic-gate else 26487c478bd9Sstevel@tonic-gate --p->cruncnt; 26497c478bd9Sstevel@tonic-gate 26504bc0a2efScasper if (lstat(pr->outfile, &buf) == 0) { 26514bc0a2efScasper if (!S_ISLNK(buf.st_mode) && 26527c478bd9Sstevel@tonic-gate (buf.st_size > 0 || pr->mailwhendone)) { 26537c478bd9Sstevel@tonic-gate /* mail user stdout and stderr */ 26547c478bd9Sstevel@tonic-gate for (;;) { 26557c478bd9Sstevel@tonic-gate if ((pr->pid = fork()) < 0) { 26567c478bd9Sstevel@tonic-gate /* 26577c478bd9Sstevel@tonic-gate * if fork fails try forever in doubling 26587c478bd9Sstevel@tonic-gate * retry times, up to 16 seconds 26597c478bd9Sstevel@tonic-gate */ 26607c478bd9Sstevel@tonic-gate (void) sleep(nextfork); 26617c478bd9Sstevel@tonic-gate if (nextfork < 16) 26627c478bd9Sstevel@tonic-gate nextfork += nextfork; 26637c478bd9Sstevel@tonic-gate continue; 26647c478bd9Sstevel@tonic-gate } else if (pr->pid == 0) { 26657c478bd9Sstevel@tonic-gate child_sigreset(); 26667c478bd9Sstevel@tonic-gate contract_clear_template(); 26677c478bd9Sstevel@tonic-gate 26687c478bd9Sstevel@tonic-gate mail_result(p, pr, buf.st_size); 26697c478bd9Sstevel@tonic-gate /* NOTREACHED */ 26707c478bd9Sstevel@tonic-gate } else { 26717c478bd9Sstevel@tonic-gate contract_abandon_latest(pr->pid); 26727c478bd9Sstevel@tonic-gate pr->que = ZOMB; 26737c478bd9Sstevel@tonic-gate break; 26747c478bd9Sstevel@tonic-gate } 26757c478bd9Sstevel@tonic-gate } 26767c478bd9Sstevel@tonic-gate } else { 26777c478bd9Sstevel@tonic-gate (void) unlink(pr->outfile); 26787c478bd9Sstevel@tonic-gate rinfo_free(pr); 26797c478bd9Sstevel@tonic-gate } 26807c478bd9Sstevel@tonic-gate } else { 26817c478bd9Sstevel@tonic-gate rinfo_free(pr); 26827c478bd9Sstevel@tonic-gate } 26837c478bd9Sstevel@tonic-gate 26847c478bd9Sstevel@tonic-gate free_if_unused(p); 26857c478bd9Sstevel@tonic-gate } 26867c478bd9Sstevel@tonic-gate 26877c478bd9Sstevel@tonic-gate /* 26887c478bd9Sstevel@tonic-gate * Mail stdout and stderr of a job to user. Get uid for real user and become 26897c478bd9Sstevel@tonic-gate * that person. We do this so that mail won't come from root since this 26907c478bd9Sstevel@tonic-gate * could be a security hole. If failure, quit - don't send mail as root. 26917c478bd9Sstevel@tonic-gate */ 26927c478bd9Sstevel@tonic-gate static void 26937c478bd9Sstevel@tonic-gate mail_result(struct usr *p, struct runinfo *pr, size_t filesize) 26947c478bd9Sstevel@tonic-gate { 26957c478bd9Sstevel@tonic-gate struct passwd *ruser_ids; 26967c478bd9Sstevel@tonic-gate FILE *mailpipe; 26977c478bd9Sstevel@tonic-gate FILE *st; 26987c478bd9Sstevel@tonic-gate struct utsname name; 26997c478bd9Sstevel@tonic-gate int nbytes; 27007c478bd9Sstevel@tonic-gate char iobuf[BUFSIZ]; 27017c478bd9Sstevel@tonic-gate char *cmd; 27027c478bd9Sstevel@tonic-gate 27037c478bd9Sstevel@tonic-gate (void) uname(&name); 27047c478bd9Sstevel@tonic-gate if ((ruser_ids = getpwnam(p->name)) == NULL) 27057c478bd9Sstevel@tonic-gate exit(0); 27067c478bd9Sstevel@tonic-gate (void) setuid(ruser_ids->pw_uid); 27077c478bd9Sstevel@tonic-gate 27084c4c9110Sbasabi cmd = xmalloc(strlen(MAIL) + strlen(p->name)+2); 27097c478bd9Sstevel@tonic-gate (void) sprintf(cmd, "%s %s", MAIL, p->name); 27107c478bd9Sstevel@tonic-gate mailpipe = popen(cmd, "w"); 27117c478bd9Sstevel@tonic-gate free(cmd); 27127c478bd9Sstevel@tonic-gate if (mailpipe == NULL) 27137c478bd9Sstevel@tonic-gate exit(127); 27147c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "To: %s\n", p->name); 27157c478bd9Sstevel@tonic-gate if (pr->jobtype == CRONEVENT) { 27167c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, CRONOUT); 27177c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "Your \"cron\" job on %s\n", 27184c4c9110Sbasabi name.nodename); 27197c478bd9Sstevel@tonic-gate if (pr->jobname != NULL) { 27207c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "%s\n\n", pr->jobname); 27217c478bd9Sstevel@tonic-gate } 27227c478bd9Sstevel@tonic-gate } else { 27237c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "Subject: Output from \"at\" job\n\n"); 27247c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "Your \"at\" job on %s\n", 27254c4c9110Sbasabi name.nodename); 27267c478bd9Sstevel@tonic-gate if (pr->jobname != NULL) { 27277c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "\"%s\"\n\n", pr->jobname); 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate } 27307c478bd9Sstevel@tonic-gate /* Tmp. file is fopen'ed w/ "r", secure open */ 27317c478bd9Sstevel@tonic-gate if (filesize > 0 && 27327c478bd9Sstevel@tonic-gate (st = fopen(pr->outfile, "r")) != NULL) { 27337c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, 27344c4c9110Sbasabi "produced the following output:\n\n"); 27357c478bd9Sstevel@tonic-gate while ((nbytes = fread(iobuf, sizeof (char), BUFSIZ, st)) != 0) 27367c478bd9Sstevel@tonic-gate (void) fwrite(iobuf, sizeof (char), nbytes, mailpipe); 27377c478bd9Sstevel@tonic-gate (void) fclose(st); 27387c478bd9Sstevel@tonic-gate } else { 27397c478bd9Sstevel@tonic-gate (void) fprintf(mailpipe, "completed.\n"); 27407c478bd9Sstevel@tonic-gate } 27417c478bd9Sstevel@tonic-gate (void) pclose(mailpipe); 27427c478bd9Sstevel@tonic-gate exit(0); 27437c478bd9Sstevel@tonic-gate } 27447c478bd9Sstevel@tonic-gate 27457c478bd9Sstevel@tonic-gate static int 27467c478bd9Sstevel@tonic-gate msg_wait(long tim) 27477c478bd9Sstevel@tonic-gate { 27487c478bd9Sstevel@tonic-gate struct message msg; 27497c478bd9Sstevel@tonic-gate int cnt; 27507c478bd9Sstevel@tonic-gate time_t reftime; 27517c478bd9Sstevel@tonic-gate struct pollfd pfd[2]; 27527c478bd9Sstevel@tonic-gate int64_t tl; 27537c478bd9Sstevel@tonic-gate int timeout; 27547c478bd9Sstevel@tonic-gate static int pending_msg; 27557c478bd9Sstevel@tonic-gate static time_t pending_reftime; 27567c478bd9Sstevel@tonic-gate 27577c478bd9Sstevel@tonic-gate if (pending_msg) { 27587c478bd9Sstevel@tonic-gate process_msg(&msgbuf, pending_reftime); 27597c478bd9Sstevel@tonic-gate pending_msg = 0; 27607c478bd9Sstevel@tonic-gate return (0); 27617c478bd9Sstevel@tonic-gate } 27627c478bd9Sstevel@tonic-gate 27637c478bd9Sstevel@tonic-gate /* 27647c478bd9Sstevel@tonic-gate * We are opening the signal mask to receive SIGCLD. The notifypipe 27657c478bd9Sstevel@tonic-gate * is used to avoid race condition between SIGCLD and poll system 27667c478bd9Sstevel@tonic-gate * call. 27677c478bd9Sstevel@tonic-gate * If SIGCLD is delivered in poll(), poll will be interrupted, and 27687c478bd9Sstevel@tonic-gate * we will return to idle() to reap the dead children. 27697c478bd9Sstevel@tonic-gate * If SIGCLD is delivered between sigprocmask() below and poll(), 27707c478bd9Sstevel@tonic-gate * there is no way we can detect the SIGCLD because poll() won't 27717c478bd9Sstevel@tonic-gate * be interrupted. In such case, the dead children can't be wait'ed 27727c478bd9Sstevel@tonic-gate * until poll returns by timeout or a new job. To avoid this race 27737c478bd9Sstevel@tonic-gate * condition, child_handler write to the notifypipe, so that 27747c478bd9Sstevel@tonic-gate * poll() will be able to return with POLLIN which indicates that 27757c478bd9Sstevel@tonic-gate * we have received SIGCLD. 27767c478bd9Sstevel@tonic-gate * 27777c478bd9Sstevel@tonic-gate * Since the notifypipe is used to just let poll return from 27787c478bd9Sstevel@tonic-gate * system call, the data in the pipe won't be read. Therefore, 27797c478bd9Sstevel@tonic-gate * any data in the pipe needs to be flushed before opening signal 27807c478bd9Sstevel@tonic-gate * mask. 27817c478bd9Sstevel@tonic-gate * 27827c478bd9Sstevel@tonic-gate * Note that we can probably re-write this code with pselect() 27837c478bd9Sstevel@tonic-gate * which can handle this situation easily. 27847c478bd9Sstevel@tonic-gate */ 27857c478bd9Sstevel@tonic-gate (void) ioctl(notifypipe[0], I_FLUSH, FLUSHW); 27867c478bd9Sstevel@tonic-gate 27877c478bd9Sstevel@tonic-gate pfd[0].fd = msgfd; 27887c478bd9Sstevel@tonic-gate pfd[0].events = POLLIN; 27897c478bd9Sstevel@tonic-gate pfd[1].fd = notifypipe[1]; 27907c478bd9Sstevel@tonic-gate pfd[1].events = POLLIN; 27917c478bd9Sstevel@tonic-gate 27927c478bd9Sstevel@tonic-gate #ifdef CRON_MAXSLEEP 27937c478bd9Sstevel@tonic-gate /* 27947c478bd9Sstevel@tonic-gate * CRON_MAXSLEEP can be defined to have cron periodically wake 27957c478bd9Sstevel@tonic-gate * up, so that cron can detect a change of TOD and adjust the 27967c478bd9Sstevel@tonic-gate * sleep time accordingly. 27977c478bd9Sstevel@tonic-gate */ 27987c478bd9Sstevel@tonic-gate tim = (tim > CRON_MAXSLEEP) ? CRON_MAXSLEEP : tim; 27997c478bd9Sstevel@tonic-gate #endif 28007c478bd9Sstevel@tonic-gate tl = (tim == INFINITY) ? -1ll : (int64_t)tim * 1000; 28017c478bd9Sstevel@tonic-gate 28027c478bd9Sstevel@tonic-gate accept_sigcld = 1; 28037c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &childmask, NULL); 28047c478bd9Sstevel@tonic-gate do { 28057c478bd9Sstevel@tonic-gate timeout = (tl > INT_MAX ? INT_MAX : (int)tl); 28067c478bd9Sstevel@tonic-gate tl -= timeout; 28077c478bd9Sstevel@tonic-gate cnt = poll(pfd, 2, timeout); 28087c478bd9Sstevel@tonic-gate if (cnt == -1 && errno != EINTR) { 28097c478bd9Sstevel@tonic-gate perror("! poll"); 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate } while (tl > 0 && cnt == 0); 28127c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &childmask, NULL); 28137c478bd9Sstevel@tonic-gate accept_sigcld = 0; 28147c478bd9Sstevel@tonic-gate 28157c478bd9Sstevel@tonic-gate /* 28167c478bd9Sstevel@tonic-gate * poll timeout or interrupted. 28177c478bd9Sstevel@tonic-gate */ 28187c478bd9Sstevel@tonic-gate if (cnt <= 0) 28197c478bd9Sstevel@tonic-gate return (0); 28207c478bd9Sstevel@tonic-gate 28217c478bd9Sstevel@tonic-gate /* 28227c478bd9Sstevel@tonic-gate * Not the timeout or new job, but a SIGCLD has been delivered. 28237c478bd9Sstevel@tonic-gate */ 28247c478bd9Sstevel@tonic-gate if ((pfd[0].revents & POLLIN) == 0) 28257c478bd9Sstevel@tonic-gate return (0); 28267c478bd9Sstevel@tonic-gate 28277c478bd9Sstevel@tonic-gate errno = 0; 28287c478bd9Sstevel@tonic-gate if ((cnt = read(msgfd, &msg, sizeof (msg))) != sizeof (msg)) { 28297c478bd9Sstevel@tonic-gate if (cnt != -1 || errno != EAGAIN) 28307c478bd9Sstevel@tonic-gate perror("! read"); 28317c478bd9Sstevel@tonic-gate return (0); 28327c478bd9Sstevel@tonic-gate } 28337c478bd9Sstevel@tonic-gate reftime = time(NULL); 28347c478bd9Sstevel@tonic-gate if (next_event != NULL && reftime >= next_event->time) { 28357c478bd9Sstevel@tonic-gate /* 28367c478bd9Sstevel@tonic-gate * we need to run the job before reloading crontab. 28377c478bd9Sstevel@tonic-gate */ 28387c478bd9Sstevel@tonic-gate (void) memcpy(&msgbuf, &msg, sizeof (msg)); 28397c478bd9Sstevel@tonic-gate pending_msg = 1; 28407c478bd9Sstevel@tonic-gate pending_reftime = reftime; 28417c478bd9Sstevel@tonic-gate return (1); 28427c478bd9Sstevel@tonic-gate } 28437c478bd9Sstevel@tonic-gate process_msg(&msg, reftime); 28447c478bd9Sstevel@tonic-gate return (0); 28457c478bd9Sstevel@tonic-gate } 28467c478bd9Sstevel@tonic-gate 28477c478bd9Sstevel@tonic-gate /* 28487c478bd9Sstevel@tonic-gate * process the message supplied via pipe. This will be called either 28497c478bd9Sstevel@tonic-gate * immediately after cron read the message from pipe, or idle time 28507c478bd9Sstevel@tonic-gate * if the message was pending due to the job execution. 28517c478bd9Sstevel@tonic-gate */ 28527c478bd9Sstevel@tonic-gate static void 28537c478bd9Sstevel@tonic-gate process_msg(struct message *pmsg, time_t reftime) 28547c478bd9Sstevel@tonic-gate { 28557c478bd9Sstevel@tonic-gate if (pmsg->etype == NULL) 28567c478bd9Sstevel@tonic-gate return; 28577c478bd9Sstevel@tonic-gate 28587c478bd9Sstevel@tonic-gate switch (pmsg->etype) { 28597c478bd9Sstevel@tonic-gate case AT: 28607c478bd9Sstevel@tonic-gate if (pmsg->action == DELETE) 28617c478bd9Sstevel@tonic-gate del_atjob(pmsg->fname, pmsg->logname); 28627c478bd9Sstevel@tonic-gate else 28637c478bd9Sstevel@tonic-gate mod_atjob(pmsg->fname, (time_t)0); 28647c478bd9Sstevel@tonic-gate break; 28657c478bd9Sstevel@tonic-gate case CRON: 28667c478bd9Sstevel@tonic-gate if (pmsg->action == DELETE) 28677c478bd9Sstevel@tonic-gate del_ctab(pmsg->fname); 28687c478bd9Sstevel@tonic-gate else 28697c478bd9Sstevel@tonic-gate mod_ctab(pmsg->fname, reftime); 28707c478bd9Sstevel@tonic-gate break; 28717c478bd9Sstevel@tonic-gate default: 28727c478bd9Sstevel@tonic-gate msg("message received - bad format"); 28737c478bd9Sstevel@tonic-gate break; 28747c478bd9Sstevel@tonic-gate } 28757c478bd9Sstevel@tonic-gate if (next_event != NULL) { 2876e2553d68SSerge Dussud if (next_event->etype == CRONEVENT) { 2877e2553d68SSerge Dussud switch (el_add(next_event, next_event->time, 2878e2553d68SSerge Dussud (next_event->u)->ctid)) { 2879e2553d68SSerge Dussud case -1: 2880e2553d68SSerge Dussud ignore_msg("process_msg", "cron", next_event); 2881e2553d68SSerge Dussud break; 2882e2553d68SSerge Dussud case -2: /* event time lower than init time */ 2883e2553d68SSerge Dussud reset_needed = 1; 2884e2553d68SSerge Dussud break; 2885e2553d68SSerge Dussud } 2886e2553d68SSerge Dussud } else { /* etype == ATEVENT */ 2887e2553d68SSerge Dussud if (el_add(next_event, next_event->time, 2888e2553d68SSerge Dussud next_event->of.at.eventid) < 0) { 2889e2553d68SSerge Dussud ignore_msg("process_msg", "at", next_event); 2890e2553d68SSerge Dussud } 2891e2553d68SSerge Dussud } 28927c478bd9Sstevel@tonic-gate next_event = NULL; 28937c478bd9Sstevel@tonic-gate } 28947c478bd9Sstevel@tonic-gate (void) fflush(stdout); 28957c478bd9Sstevel@tonic-gate pmsg->etype = NULL; 28967c478bd9Sstevel@tonic-gate } 28977c478bd9Sstevel@tonic-gate 28989f163834Sbasabi /* 28999f163834Sbasabi * Allocate a new or find an existing runinfo structure 29009f163834Sbasabi */ 29017c478bd9Sstevel@tonic-gate static struct runinfo * 29027c478bd9Sstevel@tonic-gate rinfo_get(pid_t pid) 29037c478bd9Sstevel@tonic-gate { 29047c478bd9Sstevel@tonic-gate struct runinfo *rp; 29057c478bd9Sstevel@tonic-gate 29069f163834Sbasabi if (pid == 0) { /* allocate a new entry */ 29079f163834Sbasabi rp = xcalloc(1, sizeof (struct runinfo)); 29089f163834Sbasabi rp->next = rthead; /* link the entry into the list */ 29099f163834Sbasabi rthead = rp; 29109f163834Sbasabi return (rp); 29119f163834Sbasabi } 29129f163834Sbasabi /* search the list for an existing entry */ 29139f163834Sbasabi for (rp = rthead; rp != NULL; rp = rp->next) { 29147c478bd9Sstevel@tonic-gate if (rp->pid == pid) 29157c478bd9Sstevel@tonic-gate break; 29167c478bd9Sstevel@tonic-gate } 29179f163834Sbasabi return (rp); 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate /* 29219f163834Sbasabi * Free a runinfo structure and its associated memory 29227c478bd9Sstevel@tonic-gate */ 29237c478bd9Sstevel@tonic-gate static void 29249f163834Sbasabi rinfo_free(struct runinfo *entry) 29257c478bd9Sstevel@tonic-gate { 29269f163834Sbasabi struct runinfo **rpp; 29279f163834Sbasabi struct runinfo *rp; 29289f163834Sbasabi 29299f163834Sbasabi #ifdef DEBUG 29309f163834Sbasabi (void) fprintf(stderr, "freeing job %s\n", entry->jobname); 29319f163834Sbasabi #endif 29329f163834Sbasabi for (rpp = &rthead; (rp = *rpp) != NULL; rpp = &rp->next) { 29339f163834Sbasabi if (rp == entry) { 29349f163834Sbasabi *rpp = rp->next; /* unlink the entry */ 29359f163834Sbasabi free(rp->outfile); 29369f163834Sbasabi free(rp->jobname); 29379f163834Sbasabi free(rp); 29389f163834Sbasabi break; 29399f163834Sbasabi } 29409f163834Sbasabi } 29417c478bd9Sstevel@tonic-gate } 29427c478bd9Sstevel@tonic-gate 29437c478bd9Sstevel@tonic-gate /* ARGSUSED */ 29447c478bd9Sstevel@tonic-gate static void 29457c478bd9Sstevel@tonic-gate thaw_handler(int sig) 29467c478bd9Sstevel@tonic-gate { 29477c478bd9Sstevel@tonic-gate ; 29487c478bd9Sstevel@tonic-gate } 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate 29517c478bd9Sstevel@tonic-gate /* ARGSUSED */ 29527c478bd9Sstevel@tonic-gate static void 29537c478bd9Sstevel@tonic-gate cronend(int sig) 29547c478bd9Sstevel@tonic-gate { 29557c478bd9Sstevel@tonic-gate crabort("SIGTERM", REMOVE_FIFO); 29567c478bd9Sstevel@tonic-gate } 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 29597c478bd9Sstevel@tonic-gate static void 29607c478bd9Sstevel@tonic-gate child_handler(int sig) 29617c478bd9Sstevel@tonic-gate { 29627c478bd9Sstevel@tonic-gate /* 29637c478bd9Sstevel@tonic-gate * Just in case someone changes the signal mask. 29647c478bd9Sstevel@tonic-gate * we don't want to notify the SIGCLD. 29657c478bd9Sstevel@tonic-gate */ 29667c478bd9Sstevel@tonic-gate if (accept_sigcld) { 29677c478bd9Sstevel@tonic-gate (void) write(notifypipe[0], &sig, 1); 29687c478bd9Sstevel@tonic-gate } 29697c478bd9Sstevel@tonic-gate } 29707c478bd9Sstevel@tonic-gate 29717c478bd9Sstevel@tonic-gate static void 29727c478bd9Sstevel@tonic-gate child_sigreset(void) 29737c478bd9Sstevel@tonic-gate { 29747c478bd9Sstevel@tonic-gate (void) signal(SIGCLD, SIG_DFL); 29757c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_SETMASK, &defmask, NULL); 29767c478bd9Sstevel@tonic-gate } 29777c478bd9Sstevel@tonic-gate 29787c478bd9Sstevel@tonic-gate /* 29797c478bd9Sstevel@tonic-gate * crabort() - handle exits out of cron 29807c478bd9Sstevel@tonic-gate */ 29817c478bd9Sstevel@tonic-gate static void 29827c478bd9Sstevel@tonic-gate crabort(char *mssg, int action) 29837c478bd9Sstevel@tonic-gate { 29847c478bd9Sstevel@tonic-gate int c; 29857c478bd9Sstevel@tonic-gate 29867c478bd9Sstevel@tonic-gate if (action & REMOVE_FIFO) { 29877c478bd9Sstevel@tonic-gate /* FIFO vanishes when cron finishes */ 29887c478bd9Sstevel@tonic-gate if (unlink(FIFO) < 0) 29897c478bd9Sstevel@tonic-gate perror("cron could not unlink FIFO"); 29907c478bd9Sstevel@tonic-gate } 29917c478bd9Sstevel@tonic-gate 29927c478bd9Sstevel@tonic-gate if (action & CONSOLE_MSG) { 29937c478bd9Sstevel@tonic-gate /* write error msg to console */ 29947c478bd9Sstevel@tonic-gate if ((c = open(CONSOLE, O_WRONLY)) >= 0) { 29957c478bd9Sstevel@tonic-gate (void) write(c, "cron aborted: ", 14); 29967c478bd9Sstevel@tonic-gate (void) write(c, mssg, strlen(mssg)); 29977c478bd9Sstevel@tonic-gate (void) write(c, "\n", 1); 29987c478bd9Sstevel@tonic-gate (void) close(c); 29997c478bd9Sstevel@tonic-gate } 30007c478bd9Sstevel@tonic-gate } 30017c478bd9Sstevel@tonic-gate 30027c478bd9Sstevel@tonic-gate /* always log the message */ 30037c478bd9Sstevel@tonic-gate msg(mssg); 30047c478bd9Sstevel@tonic-gate msg("******* CRON ABORTED ********"); 30057c478bd9Sstevel@tonic-gate exit(1); 30067c478bd9Sstevel@tonic-gate } 30077c478bd9Sstevel@tonic-gate 30087c478bd9Sstevel@tonic-gate /* 30097c478bd9Sstevel@tonic-gate * msg() - time-stamped error reporting function 30107c478bd9Sstevel@tonic-gate */ 30117c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 30127c478bd9Sstevel@tonic-gate static void 30137c478bd9Sstevel@tonic-gate msg(char *fmt, ...) 30147c478bd9Sstevel@tonic-gate { 30157c478bd9Sstevel@tonic-gate va_list args; 30167c478bd9Sstevel@tonic-gate time_t t; 30177c478bd9Sstevel@tonic-gate 30187c478bd9Sstevel@tonic-gate t = time(NULL); 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate (void) fflush(stdout); 30217c478bd9Sstevel@tonic-gate 30227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "! "); 30237c478bd9Sstevel@tonic-gate 30247c478bd9Sstevel@tonic-gate va_start(args, fmt); 30257c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, fmt, args); 30267c478bd9Sstevel@tonic-gate va_end(args); 30277c478bd9Sstevel@tonic-gate 30287c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), FORMAT, localtime(&t)); 30297c478bd9Sstevel@tonic-gate (void) fprintf(stderr, " %s\n", timebuf); 30307c478bd9Sstevel@tonic-gate 30317c478bd9Sstevel@tonic-gate (void) fflush(stderr); 30327c478bd9Sstevel@tonic-gate } 30337c478bd9Sstevel@tonic-gate 3034e2553d68SSerge Dussud static void 3035e2553d68SSerge Dussud ignore_msg(char *func_name, char *job_type, struct event *event) 3036e2553d68SSerge Dussud { 3037e2553d68SSerge Dussud msg("%s: ignoring %s job (user: %s, cmd: %s, time: %ld)", 3038e2553d68SSerge Dussud func_name, job_type, 3039e2553d68SSerge Dussud event->u->name ? event->u->name : "unknown", 3040e2553d68SSerge Dussud event->cmd ? event->cmd : "unknown", 3041e2553d68SSerge Dussud event->time); 3042e2553d68SSerge Dussud } 3043e2553d68SSerge Dussud 30447c478bd9Sstevel@tonic-gate static void 30457c478bd9Sstevel@tonic-gate logit(int cc, struct runinfo *rp, int rc) 30467c478bd9Sstevel@tonic-gate { 30477c478bd9Sstevel@tonic-gate time_t t; 30487c478bd9Sstevel@tonic-gate int ret; 30497c478bd9Sstevel@tonic-gate 30507c478bd9Sstevel@tonic-gate if (!log) 30517c478bd9Sstevel@tonic-gate return; 30527c478bd9Sstevel@tonic-gate 30537c478bd9Sstevel@tonic-gate t = time(NULL); 30547c478bd9Sstevel@tonic-gate if (cc == BCHAR) 30557c478bd9Sstevel@tonic-gate (void) printf("%c CMD: %s\n", cc, next_event->cmd); 30567c478bd9Sstevel@tonic-gate (void) strftime(timebuf, sizeof (timebuf), FORMAT, localtime(&t)); 30577c478bd9Sstevel@tonic-gate (void) printf("%c %.8s %u %c %s", 30584c4c9110Sbasabi cc, (rp->rusr)->name, rp->pid, QUE(rp->que), timebuf); 30597c478bd9Sstevel@tonic-gate if ((ret = TSTAT(rc)) != 0) 30607c478bd9Sstevel@tonic-gate (void) printf(" ts=%d", ret); 30617c478bd9Sstevel@tonic-gate if ((ret = RCODE(rc)) != 0) 30627c478bd9Sstevel@tonic-gate (void) printf(" rc=%d", ret); 30637c478bd9Sstevel@tonic-gate (void) putchar('\n'); 30647c478bd9Sstevel@tonic-gate (void) fflush(stdout); 30657c478bd9Sstevel@tonic-gate } 30667c478bd9Sstevel@tonic-gate 30677c478bd9Sstevel@tonic-gate static void 30687c478bd9Sstevel@tonic-gate resched(int delay) 30697c478bd9Sstevel@tonic-gate { 30707c478bd9Sstevel@tonic-gate time_t nt; 30717c478bd9Sstevel@tonic-gate 30727c478bd9Sstevel@tonic-gate /* run job at a later time */ 30737c478bd9Sstevel@tonic-gate nt = next_event->time + delay; 30747c478bd9Sstevel@tonic-gate if (next_event->etype == CRONEVENT) { 30757c478bd9Sstevel@tonic-gate next_event->time = next_time(next_event, (time_t)0); 30767c478bd9Sstevel@tonic-gate if (nt < next_event->time) 30777c478bd9Sstevel@tonic-gate next_event->time = nt; 3078e2553d68SSerge Dussud switch (el_add(next_event, next_event->time, 3079e2553d68SSerge Dussud (next_event->u)->ctid)) { 3080e2553d68SSerge Dussud case -1: 3081e2553d68SSerge Dussud ignore_msg("resched", "cron", next_event); 3082e2553d68SSerge Dussud break; 3083e2553d68SSerge Dussud case -2: /* event time lower than init time */ 3084e2553d68SSerge Dussud reset_needed = 1; 3085e2553d68SSerge Dussud break; 3086e2553d68SSerge Dussud } 30877c478bd9Sstevel@tonic-gate delayed = 1; 30887c478bd9Sstevel@tonic-gate msg("rescheduling a cron job"); 30897c478bd9Sstevel@tonic-gate return; 30907c478bd9Sstevel@tonic-gate } 30917c478bd9Sstevel@tonic-gate add_atevent(next_event->u, next_event->cmd, nt, next_event->etype); 30927c478bd9Sstevel@tonic-gate msg("rescheduling at job"); 30937c478bd9Sstevel@tonic-gate } 30947c478bd9Sstevel@tonic-gate 30957c478bd9Sstevel@tonic-gate static void 30967c478bd9Sstevel@tonic-gate quedefs(int action) 30977c478bd9Sstevel@tonic-gate { 30987c478bd9Sstevel@tonic-gate int i; 30997c478bd9Sstevel@tonic-gate int j; 31007c478bd9Sstevel@tonic-gate char qbuf[QBUFSIZ]; 31017c478bd9Sstevel@tonic-gate FILE *fd; 31027c478bd9Sstevel@tonic-gate 31037c478bd9Sstevel@tonic-gate /* set up default queue definitions */ 31047c478bd9Sstevel@tonic-gate for (i = 0; i < NQUEUE; i++) { 31057c478bd9Sstevel@tonic-gate qt[i].njob = qd.njob; 31067c478bd9Sstevel@tonic-gate qt[i].nice = qd.nice; 31077c478bd9Sstevel@tonic-gate qt[i].nwait = qd.nwait; 31087c478bd9Sstevel@tonic-gate } 31097c478bd9Sstevel@tonic-gate if (action == DEFAULT) 31107c478bd9Sstevel@tonic-gate return; 31117c478bd9Sstevel@tonic-gate if ((fd = fopen(QUEDEFS, "r")) == NULL) { 31127c478bd9Sstevel@tonic-gate msg("cannot open quedefs file"); 31137c478bd9Sstevel@tonic-gate msg("using default queue definitions"); 31147c478bd9Sstevel@tonic-gate return; 31157c478bd9Sstevel@tonic-gate } 31167c478bd9Sstevel@tonic-gate while (fgets(qbuf, QBUFSIZ, fd) != NULL) { 31177c478bd9Sstevel@tonic-gate if ((j = qbuf[0]-'a') < 0 || j >= NQUEUE || qbuf[1] != '.') 31187c478bd9Sstevel@tonic-gate continue; 31197c478bd9Sstevel@tonic-gate parsqdef(&qbuf[2]); 31207c478bd9Sstevel@tonic-gate qt[j].njob = qq.njob; 31217c478bd9Sstevel@tonic-gate qt[j].nice = qq.nice; 31227c478bd9Sstevel@tonic-gate qt[j].nwait = qq.nwait; 31237c478bd9Sstevel@tonic-gate } 31247c478bd9Sstevel@tonic-gate (void) fclose(fd); 31257c478bd9Sstevel@tonic-gate } 31267c478bd9Sstevel@tonic-gate 31277c478bd9Sstevel@tonic-gate static void 31287c478bd9Sstevel@tonic-gate parsqdef(char *name) 31297c478bd9Sstevel@tonic-gate { 31307c478bd9Sstevel@tonic-gate int i; 31317c478bd9Sstevel@tonic-gate 31327c478bd9Sstevel@tonic-gate qq = qd; 31337c478bd9Sstevel@tonic-gate while (*name) { 31347c478bd9Sstevel@tonic-gate i = 0; 31357c478bd9Sstevel@tonic-gate while (isdigit(*name)) { 31367c478bd9Sstevel@tonic-gate i *= 10; 31377c478bd9Sstevel@tonic-gate i += *name++ - '0'; 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate switch (*name++) { 31407c478bd9Sstevel@tonic-gate case JOBF: 31417c478bd9Sstevel@tonic-gate qq.njob = i; 31427c478bd9Sstevel@tonic-gate break; 31437c478bd9Sstevel@tonic-gate case NICEF: 31447c478bd9Sstevel@tonic-gate qq.nice = i; 31457c478bd9Sstevel@tonic-gate break; 31467c478bd9Sstevel@tonic-gate case WAITF: 31477c478bd9Sstevel@tonic-gate qq.nwait = i; 31487c478bd9Sstevel@tonic-gate break; 31497c478bd9Sstevel@tonic-gate } 31507c478bd9Sstevel@tonic-gate } 31517c478bd9Sstevel@tonic-gate } 31527c478bd9Sstevel@tonic-gate 31537c478bd9Sstevel@tonic-gate /* 31547c478bd9Sstevel@tonic-gate * defaults - read defaults from /etc/default/cron 31557c478bd9Sstevel@tonic-gate */ 31567c478bd9Sstevel@tonic-gate static void 31577c478bd9Sstevel@tonic-gate defaults() 31587c478bd9Sstevel@tonic-gate { 31597c478bd9Sstevel@tonic-gate int flags; 31607c478bd9Sstevel@tonic-gate char *deflog; 31617c478bd9Sstevel@tonic-gate char *hz, *tz; 31627c478bd9Sstevel@tonic-gate 31637c478bd9Sstevel@tonic-gate /* 31647c478bd9Sstevel@tonic-gate * get HZ value for environment 31657c478bd9Sstevel@tonic-gate */ 31667c478bd9Sstevel@tonic-gate if ((hz = getenv("HZ")) == (char *)NULL) 31677c478bd9Sstevel@tonic-gate (void) sprintf(hzname, "HZ=%d", HZ); 31687c478bd9Sstevel@tonic-gate else 31697c478bd9Sstevel@tonic-gate (void) snprintf(hzname, sizeof (hzname), "HZ=%s", hz); 31707c478bd9Sstevel@tonic-gate /* 31717c478bd9Sstevel@tonic-gate * get TZ value for environment 31727c478bd9Sstevel@tonic-gate */ 31737c478bd9Sstevel@tonic-gate (void) snprintf(tzone, sizeof (tzone), "TZ=%s", 31744c4c9110Sbasabi ((tz = getenv("TZ")) != NULL) ? tz : DEFTZ); 31757c478bd9Sstevel@tonic-gate 31767c478bd9Sstevel@tonic-gate if (defopen(DEFFILE) == 0) { 31777c478bd9Sstevel@tonic-gate /* ignore case */ 31787c478bd9Sstevel@tonic-gate flags = defcntl(DC_GETFLAGS, 0); 31797c478bd9Sstevel@tonic-gate TURNOFF(flags, DC_CASE); 31807c478bd9Sstevel@tonic-gate (void) defcntl(DC_SETFLAGS, flags); 31817c478bd9Sstevel@tonic-gate 31827c478bd9Sstevel@tonic-gate if (((deflog = defread("CRONLOG=")) == NULL) || 31837c478bd9Sstevel@tonic-gate (*deflog == 'N') || (*deflog == 'n')) 31847c478bd9Sstevel@tonic-gate log = 0; 31857c478bd9Sstevel@tonic-gate else 31867c478bd9Sstevel@tonic-gate log = 1; 31877c478bd9Sstevel@tonic-gate /* fix for 1087611 - allow paths to be set in defaults file */ 31887c478bd9Sstevel@tonic-gate if ((Def_path = defread("PATH=")) != NULL) { 31897c478bd9Sstevel@tonic-gate (void) strlcat(path, Def_path, LINE_MAX); 31907c478bd9Sstevel@tonic-gate } else { 31917c478bd9Sstevel@tonic-gate (void) strlcpy(path, NONROOTPATH, LINE_MAX); 31927c478bd9Sstevel@tonic-gate } 31937c478bd9Sstevel@tonic-gate if ((Def_supath = defread("SUPATH=")) != NULL) { 31947c478bd9Sstevel@tonic-gate (void) strlcat(supath, Def_supath, LINE_MAX); 31957c478bd9Sstevel@tonic-gate } else { 31967c478bd9Sstevel@tonic-gate (void) strlcpy(supath, ROOTPATH, LINE_MAX); 31977c478bd9Sstevel@tonic-gate } 31987c478bd9Sstevel@tonic-gate (void) defopen(NULL); 31997c478bd9Sstevel@tonic-gate } 32007c478bd9Sstevel@tonic-gate } 32017c478bd9Sstevel@tonic-gate 32027c478bd9Sstevel@tonic-gate /* 32037c478bd9Sstevel@tonic-gate * Determine if a user entry for a job is still ok. The method used here 32047c478bd9Sstevel@tonic-gate * is a lot (about 75x) faster than using setgrent() / getgrent() 32057c478bd9Sstevel@tonic-gate * endgrent(). It should be safe because we use the sysconf to determine 32067c478bd9Sstevel@tonic-gate * the max, and it tolerates the max being 0. 32077c478bd9Sstevel@tonic-gate */ 32087c478bd9Sstevel@tonic-gate 32097c478bd9Sstevel@tonic-gate static int 32104c4c9110Sbasabi verify_user_cred(struct usr *u) 32117c478bd9Sstevel@tonic-gate { 32127c478bd9Sstevel@tonic-gate struct passwd *pw; 32137c478bd9Sstevel@tonic-gate size_t numUsrGrps = 0; 32147c478bd9Sstevel@tonic-gate size_t numOrigGrps = 0; 32157c478bd9Sstevel@tonic-gate size_t i; 32167c478bd9Sstevel@tonic-gate int retval; 32177c478bd9Sstevel@tonic-gate 32187c478bd9Sstevel@tonic-gate /* 32197c478bd9Sstevel@tonic-gate * Maximum number of groups a user may be in concurrently. This 32207c478bd9Sstevel@tonic-gate * is a value which we obtain at runtime through a sysconf() 32217c478bd9Sstevel@tonic-gate * call. 32227c478bd9Sstevel@tonic-gate */ 32237c478bd9Sstevel@tonic-gate 32247c478bd9Sstevel@tonic-gate static size_t nGroupsMax = (size_t)-1; 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate /* 32277c478bd9Sstevel@tonic-gate * Arrays for cron user's group list, constructed at startup to 32287c478bd9Sstevel@tonic-gate * be nGroupsMax elements long, used for verifying user 32297c478bd9Sstevel@tonic-gate * credentials prior to execution. 32307c478bd9Sstevel@tonic-gate */ 32317c478bd9Sstevel@tonic-gate 32327c478bd9Sstevel@tonic-gate static gid_t *UsrGrps; 32337c478bd9Sstevel@tonic-gate static gid_t *OrigGrps; 32347c478bd9Sstevel@tonic-gate 32354c4c9110Sbasabi if ((pw = getpwnam(u->name)) == NULL) 32367c478bd9Sstevel@tonic-gate return (VUC_BADUSER); 32374c4c9110Sbasabi if (u->home != NULL) { 32384c4c9110Sbasabi if (strcmp(u->home, pw->pw_dir) != 0) { 32394c4c9110Sbasabi free(u->home); 32404c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1); 32414c4c9110Sbasabi (void) strcpy(u->home, pw->pw_dir); 32424c4c9110Sbasabi } 32434c4c9110Sbasabi } else { 32444c4c9110Sbasabi u->home = xmalloc(strlen(pw->pw_dir) + 1); 32454c4c9110Sbasabi (void) strcpy(u->home, pw->pw_dir); 32467c478bd9Sstevel@tonic-gate } 32474c4c9110Sbasabi if (u->uid != pw->pw_uid) 32484c4c9110Sbasabi u->uid = pw->pw_uid; 32494c4c9110Sbasabi if (u->gid != pw->pw_gid) 32504c4c9110Sbasabi u->gid = pw->pw_gid; 32517c478bd9Sstevel@tonic-gate 32527c478bd9Sstevel@tonic-gate /* 32537c478bd9Sstevel@tonic-gate * Create the group id lists needed for job credential 32547c478bd9Sstevel@tonic-gate * verification. 32557c478bd9Sstevel@tonic-gate */ 32567c478bd9Sstevel@tonic-gate 32577c478bd9Sstevel@tonic-gate if (nGroupsMax == (size_t)-1) { 32587c478bd9Sstevel@tonic-gate if ((nGroupsMax = sysconf(_SC_NGROUPS_MAX)) > 0) { 32597c478bd9Sstevel@tonic-gate UsrGrps = xcalloc(nGroupsMax, sizeof (gid_t)); 32607c478bd9Sstevel@tonic-gate OrigGrps = xcalloc(nGroupsMax, sizeof (gid_t)); 32617c478bd9Sstevel@tonic-gate } 32627c478bd9Sstevel@tonic-gate 32637c478bd9Sstevel@tonic-gate #ifdef DEBUG 32647c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "nGroupsMax = %ld\n", nGroupsMax); 32657c478bd9Sstevel@tonic-gate #endif 32667c478bd9Sstevel@tonic-gate } 32677c478bd9Sstevel@tonic-gate 32687c478bd9Sstevel@tonic-gate #ifdef DEBUG 32697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred (%s-%d)\n", pw->pw_name, 32707c478bd9Sstevel@tonic-gate pw->pw_uid); 32717c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred: pw->pw_gid = %d, " 32727c478bd9Sstevel@tonic-gate "u->gid = %d\n", pw->pw_gid, u->gid); 32737c478bd9Sstevel@tonic-gate #endif 32747c478bd9Sstevel@tonic-gate 32757c478bd9Sstevel@tonic-gate retval = (u->gid == pw->pw_gid) ? VUC_OK : VUC_NOTINGROUP; 32767c478bd9Sstevel@tonic-gate 32777c478bd9Sstevel@tonic-gate if (nGroupsMax > 0) { 32787c478bd9Sstevel@tonic-gate numOrigGrps = getgroups(nGroupsMax, OrigGrps); 32797c478bd9Sstevel@tonic-gate 32807c478bd9Sstevel@tonic-gate (void) initgroups(pw->pw_name, pw->pw_gid); 32817c478bd9Sstevel@tonic-gate numUsrGrps = getgroups(nGroupsMax, UsrGrps); 32827c478bd9Sstevel@tonic-gate 32837c478bd9Sstevel@tonic-gate for (i = 0; i < numUsrGrps; i++) { 32847c478bd9Sstevel@tonic-gate if (UsrGrps[i] == u->gid) { 32857c478bd9Sstevel@tonic-gate retval = VUC_OK; 32867c478bd9Sstevel@tonic-gate break; 32877c478bd9Sstevel@tonic-gate } 32887c478bd9Sstevel@tonic-gate } 32897c478bd9Sstevel@tonic-gate 32907c478bd9Sstevel@tonic-gate if (OrigGrps) { 32917c478bd9Sstevel@tonic-gate (void) setgroups(numOrigGrps, OrigGrps); 32927c478bd9Sstevel@tonic-gate } 32937c478bd9Sstevel@tonic-gate } 32947c478bd9Sstevel@tonic-gate 32957c478bd9Sstevel@tonic-gate #ifdef DEBUG 32967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "verify_user_cred: VUC = %d\n", retval); 32977c478bd9Sstevel@tonic-gate #endif 32987c478bd9Sstevel@tonic-gate 32997c478bd9Sstevel@tonic-gate return (retval); 33007c478bd9Sstevel@tonic-gate } 33017c478bd9Sstevel@tonic-gate 33027c478bd9Sstevel@tonic-gate static int 33037c478bd9Sstevel@tonic-gate set_user_cred(const struct usr *u, struct project *pproj) 33047c478bd9Sstevel@tonic-gate { 33057c478bd9Sstevel@tonic-gate static char *progname = "cron"; 33067c478bd9Sstevel@tonic-gate int r = 0, rval = 0; 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate if ((r = pam_start(progname, u->name, &pam_conv, &pamh)) 33094c4c9110Sbasabi != PAM_SUCCESS) { 33107c478bd9Sstevel@tonic-gate #ifdef DEBUG 33117c478bd9Sstevel@tonic-gate msg("pam_start returns %d\n", r); 33127c478bd9Sstevel@tonic-gate #endif 33137c478bd9Sstevel@tonic-gate rval = VUC_BADUSER; 33147c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 33157c478bd9Sstevel@tonic-gate } 33167c478bd9Sstevel@tonic-gate 33177c478bd9Sstevel@tonic-gate r = pam_acct_mgmt(pamh, 0); 33187c478bd9Sstevel@tonic-gate #ifdef DEBUG 33197c478bd9Sstevel@tonic-gate msg("pam_acc_mgmt returns %d\n", r); 33207c478bd9Sstevel@tonic-gate #endif 33217c478bd9Sstevel@tonic-gate if (r == PAM_ACCT_EXPIRED) { 33227c478bd9Sstevel@tonic-gate rval = VUC_EXPIRED; 33237c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 33247c478bd9Sstevel@tonic-gate } 33257c478bd9Sstevel@tonic-gate if (r == PAM_NEW_AUTHTOK_REQD) { 33267c478bd9Sstevel@tonic-gate rval = VUC_NEW_AUTH; 33277c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 33287c478bd9Sstevel@tonic-gate } 33297c478bd9Sstevel@tonic-gate if (r != PAM_SUCCESS) { 33307c478bd9Sstevel@tonic-gate rval = VUC_BADUSER; 33317c478bd9Sstevel@tonic-gate goto set_eser_cred_exit; 33327c478bd9Sstevel@tonic-gate } 33337c478bd9Sstevel@tonic-gate 33347c478bd9Sstevel@tonic-gate if (pproj != NULL) { 33357c478bd9Sstevel@tonic-gate size_t sz = sizeof (PROJECT) + strlen(pproj->pj_name); 33367c478bd9Sstevel@tonic-gate char *buf = alloca(sz); 33377c478bd9Sstevel@tonic-gate 33387c478bd9Sstevel@tonic-gate (void) snprintf(buf, sz, PROJECT "%s", pproj->pj_name); 33397c478bd9Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_RESOURCE, buf); 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate r = pam_setcred(pamh, PAM_ESTABLISH_CRED); 33437c478bd9Sstevel@tonic-gate if (r != PAM_SUCCESS) 33447c478bd9Sstevel@tonic-gate rval = VUC_BADUSER; 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate set_eser_cred_exit: 33477c478bd9Sstevel@tonic-gate (void) pam_end(pamh, r); 33487c478bd9Sstevel@tonic-gate return (rval); 33497c478bd9Sstevel@tonic-gate } 33507c478bd9Sstevel@tonic-gate 33517c478bd9Sstevel@tonic-gate static void 33527c478bd9Sstevel@tonic-gate clean_out_user(struct usr *u) 33537c478bd9Sstevel@tonic-gate { 33547c478bd9Sstevel@tonic-gate if (next_event->u == u) { 33557c478bd9Sstevel@tonic-gate next_event = NULL; 33567c478bd9Sstevel@tonic-gate } 33577c478bd9Sstevel@tonic-gate 33587c478bd9Sstevel@tonic-gate clean_out_ctab(u); 33597c478bd9Sstevel@tonic-gate clean_out_atjobs(u); 33607c478bd9Sstevel@tonic-gate free_if_unused(u); 33617c478bd9Sstevel@tonic-gate } 33627c478bd9Sstevel@tonic-gate 33637c478bd9Sstevel@tonic-gate static void 33647c478bd9Sstevel@tonic-gate clean_out_atjobs(struct usr *u) 33657c478bd9Sstevel@tonic-gate { 33667c478bd9Sstevel@tonic-gate struct event *ev, *pv; 33677c478bd9Sstevel@tonic-gate 33687c478bd9Sstevel@tonic-gate for (pv = NULL, ev = u->atevents; 33694c4c9110Sbasabi ev != NULL; 33704c4c9110Sbasabi pv = ev, ev = ev->link, free(pv)) { 33717c478bd9Sstevel@tonic-gate el_remove(ev->of.at.eventid, 1); 33727c478bd9Sstevel@tonic-gate if (cwd == AT) 33737c478bd9Sstevel@tonic-gate cron_unlink(ev->cmd); 33747c478bd9Sstevel@tonic-gate else { 33757c478bd9Sstevel@tonic-gate char buf[PATH_MAX]; 33767c478bd9Sstevel@tonic-gate if (strlen(ATDIR) + strlen(ev->cmd) + 2 33774c4c9110Sbasabi < PATH_MAX) { 33787c478bd9Sstevel@tonic-gate (void) sprintf(buf, "%s/%s", ATDIR, ev->cmd); 33797c478bd9Sstevel@tonic-gate cron_unlink(buf); 33807c478bd9Sstevel@tonic-gate } 33817c478bd9Sstevel@tonic-gate } 33827c478bd9Sstevel@tonic-gate free(ev->cmd); 33837c478bd9Sstevel@tonic-gate } 33847c478bd9Sstevel@tonic-gate 33857c478bd9Sstevel@tonic-gate u->atevents = NULL; 33867c478bd9Sstevel@tonic-gate } 33877c478bd9Sstevel@tonic-gate 33887c478bd9Sstevel@tonic-gate static void 33897c478bd9Sstevel@tonic-gate clean_out_ctab(struct usr *u) 33907c478bd9Sstevel@tonic-gate { 33917c478bd9Sstevel@tonic-gate rm_ctevents(u); 33927c478bd9Sstevel@tonic-gate el_remove(u->ctid, 0); 33937c478bd9Sstevel@tonic-gate u->ctid = 0; 33947c478bd9Sstevel@tonic-gate u->ctexists = 0; 33957c478bd9Sstevel@tonic-gate } 33967c478bd9Sstevel@tonic-gate 33977c478bd9Sstevel@tonic-gate static void 33987c478bd9Sstevel@tonic-gate cron_unlink(char *name) 33997c478bd9Sstevel@tonic-gate { 34007c478bd9Sstevel@tonic-gate int r; 34017c478bd9Sstevel@tonic-gate 34027c478bd9Sstevel@tonic-gate r = unlink(name); 34037c478bd9Sstevel@tonic-gate if (r == 0 || (r == -1 && errno == ENOENT)) { 34047c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(name, NULL); 34057c478bd9Sstevel@tonic-gate } 34067c478bd9Sstevel@tonic-gate } 34077c478bd9Sstevel@tonic-gate 34087c478bd9Sstevel@tonic-gate static void 34097c478bd9Sstevel@tonic-gate create_anc_ctab(struct event *e) 34107c478bd9Sstevel@tonic-gate { 34117c478bd9Sstevel@tonic-gate if (audit_cron_create_anc_file(e->u->name, 34124c4c9110Sbasabi (cwd == CRON) ? NULL:CRONDIR, 34134c4c9110Sbasabi e->u->name, e->u->uid) == -1) { 34147c478bd9Sstevel@tonic-gate process_anc_files(CRON_ANC_DELETE); 34157c478bd9Sstevel@tonic-gate crabort("cannot create ancillary files for crontabs", 34164c4c9110Sbasabi REMOVE_FIFO|CONSOLE_MSG); 34177c478bd9Sstevel@tonic-gate } 34187c478bd9Sstevel@tonic-gate } 34197c478bd9Sstevel@tonic-gate 34207c478bd9Sstevel@tonic-gate static void 34217c478bd9Sstevel@tonic-gate delete_anc_ctab(struct event *e) 34227c478bd9Sstevel@tonic-gate { 34237c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(e->u->name, 34244c4c9110Sbasabi (cwd == CRON) ? NULL:CRONDIR); 34257c478bd9Sstevel@tonic-gate } 34267c478bd9Sstevel@tonic-gate 34277c478bd9Sstevel@tonic-gate static void 34287c478bd9Sstevel@tonic-gate create_anc_atjob(struct event *e) 34297c478bd9Sstevel@tonic-gate { 34307c478bd9Sstevel@tonic-gate if (!e->of.at.exists) 34317c478bd9Sstevel@tonic-gate return; 34327c478bd9Sstevel@tonic-gate 34337c478bd9Sstevel@tonic-gate if (audit_cron_create_anc_file(e->cmd, 34344c4c9110Sbasabi (cwd == AT) ? NULL:ATDIR, 34354c4c9110Sbasabi e->u->name, e->u->uid) == -1) { 34367c478bd9Sstevel@tonic-gate process_anc_files(CRON_ANC_DELETE); 34377c478bd9Sstevel@tonic-gate crabort("cannot create ancillary files for atjobs", 34384c4c9110Sbasabi REMOVE_FIFO|CONSOLE_MSG); 34397c478bd9Sstevel@tonic-gate } 34407c478bd9Sstevel@tonic-gate } 34417c478bd9Sstevel@tonic-gate 34427c478bd9Sstevel@tonic-gate static void 34437c478bd9Sstevel@tonic-gate delete_anc_atjob(struct event *e) 34447c478bd9Sstevel@tonic-gate { 34457c478bd9Sstevel@tonic-gate if (!e->of.at.exists) 34467c478bd9Sstevel@tonic-gate return; 34477c478bd9Sstevel@tonic-gate 34487c478bd9Sstevel@tonic-gate (void) audit_cron_delete_anc_file(e->cmd, 34494c4c9110Sbasabi (cwd == AT) ? NULL:ATDIR); 34507c478bd9Sstevel@tonic-gate } 34517c478bd9Sstevel@tonic-gate 34527c478bd9Sstevel@tonic-gate 34537c478bd9Sstevel@tonic-gate static void 34547c478bd9Sstevel@tonic-gate process_anc_files(int del) 34557c478bd9Sstevel@tonic-gate { 34567c478bd9Sstevel@tonic-gate struct usr *u = uhead; 34577c478bd9Sstevel@tonic-gate struct event *e; 34587c478bd9Sstevel@tonic-gate 34597c478bd9Sstevel@tonic-gate if (!audit_cron_mode()) 34607c478bd9Sstevel@tonic-gate return; 34617c478bd9Sstevel@tonic-gate 34627c478bd9Sstevel@tonic-gate for (;;) { 34637c478bd9Sstevel@tonic-gate if (u->ctexists && u->ctevents != NULL) { 34647c478bd9Sstevel@tonic-gate e = u->ctevents; 34657c478bd9Sstevel@tonic-gate for (;;) { 34667c478bd9Sstevel@tonic-gate if (del) 34677c478bd9Sstevel@tonic-gate delete_anc_ctab(e); 34687c478bd9Sstevel@tonic-gate else 34697c478bd9Sstevel@tonic-gate create_anc_ctab(e); 34707c478bd9Sstevel@tonic-gate if ((e = e->link) == NULL) 34717c478bd9Sstevel@tonic-gate break; 34727c478bd9Sstevel@tonic-gate } 34737c478bd9Sstevel@tonic-gate } 34747c478bd9Sstevel@tonic-gate 34757c478bd9Sstevel@tonic-gate if (u->atevents != NULL) { 34767c478bd9Sstevel@tonic-gate e = u->atevents; 34777c478bd9Sstevel@tonic-gate for (;;) { 34787c478bd9Sstevel@tonic-gate if (del) 34797c478bd9Sstevel@tonic-gate delete_anc_atjob(e); 34807c478bd9Sstevel@tonic-gate else 34817c478bd9Sstevel@tonic-gate create_anc_atjob(e); 34827c478bd9Sstevel@tonic-gate if ((e = e->link) == NULL) 34837c478bd9Sstevel@tonic-gate break; 34847c478bd9Sstevel@tonic-gate } 34857c478bd9Sstevel@tonic-gate } 34867c478bd9Sstevel@tonic-gate 34877c478bd9Sstevel@tonic-gate if ((u = u->nextusr) == NULL) 34887c478bd9Sstevel@tonic-gate break; 34897c478bd9Sstevel@tonic-gate } 34907c478bd9Sstevel@tonic-gate } 34917c478bd9Sstevel@tonic-gate 34927c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 34937c478bd9Sstevel@tonic-gate static int 34947c478bd9Sstevel@tonic-gate cron_conv(int num_msg, struct pam_message **msgs, 34957c478bd9Sstevel@tonic-gate struct pam_response **response, void *appdata_ptr) 34967c478bd9Sstevel@tonic-gate { 34977c478bd9Sstevel@tonic-gate struct pam_message **m = msgs; 34987c478bd9Sstevel@tonic-gate int i; 34997c478bd9Sstevel@tonic-gate 35007c478bd9Sstevel@tonic-gate for (i = 0; i < num_msg; i++) { 35017c478bd9Sstevel@tonic-gate switch (m[i]->msg_style) { 35027c478bd9Sstevel@tonic-gate case PAM_ERROR_MSG: 35037c478bd9Sstevel@tonic-gate case PAM_TEXT_INFO: 35047c478bd9Sstevel@tonic-gate if (m[i]->msg != NULL) { 35057c478bd9Sstevel@tonic-gate (void) msg("%s\n", m[i]->msg); 35067c478bd9Sstevel@tonic-gate } 35077c478bd9Sstevel@tonic-gate break; 35087c478bd9Sstevel@tonic-gate 35097c478bd9Sstevel@tonic-gate default: 35107c478bd9Sstevel@tonic-gate break; 35117c478bd9Sstevel@tonic-gate } 35127c478bd9Sstevel@tonic-gate } 35137c478bd9Sstevel@tonic-gate return (0); 35147c478bd9Sstevel@tonic-gate } 35157c478bd9Sstevel@tonic-gate 35167c478bd9Sstevel@tonic-gate /* 35177c478bd9Sstevel@tonic-gate * Cron creates process for other than job. Mail process is the 35187c478bd9Sstevel@tonic-gate * one which rinfo does not cover. Therefore, miscpid will keep 35197c478bd9Sstevel@tonic-gate * track of the pids executed from cron. Otherwise, we will see 35207c478bd9Sstevel@tonic-gate * "unexpected pid returned.." messages appear in the log file. 35217c478bd9Sstevel@tonic-gate */ 35227c478bd9Sstevel@tonic-gate static void 35237c478bd9Sstevel@tonic-gate miscpid_insert(pid_t pid) 35247c478bd9Sstevel@tonic-gate { 35257c478bd9Sstevel@tonic-gate struct miscpid *mp; 35267c478bd9Sstevel@tonic-gate 35277c478bd9Sstevel@tonic-gate mp = xmalloc(sizeof (*mp)); 35287c478bd9Sstevel@tonic-gate mp->pid = pid; 35297c478bd9Sstevel@tonic-gate mp->next = miscpid_head; 35307c478bd9Sstevel@tonic-gate miscpid_head = mp; 35317c478bd9Sstevel@tonic-gate } 35327c478bd9Sstevel@tonic-gate 35337c478bd9Sstevel@tonic-gate static int 35347c478bd9Sstevel@tonic-gate miscpid_delete(pid_t pid) 35357c478bd9Sstevel@tonic-gate { 35367c478bd9Sstevel@tonic-gate struct miscpid *mp, *omp; 35377c478bd9Sstevel@tonic-gate int found = 0; 35387c478bd9Sstevel@tonic-gate 35397c478bd9Sstevel@tonic-gate omp = NULL; 35407c478bd9Sstevel@tonic-gate for (mp = miscpid_head; mp != NULL; mp = mp->next) { 35417c478bd9Sstevel@tonic-gate if (mp->pid == pid) { 35427c478bd9Sstevel@tonic-gate found = 1; 35437c478bd9Sstevel@tonic-gate break; 35447c478bd9Sstevel@tonic-gate } 35457c478bd9Sstevel@tonic-gate omp = mp; 35467c478bd9Sstevel@tonic-gate } 35477c478bd9Sstevel@tonic-gate if (found) { 35487c478bd9Sstevel@tonic-gate if (omp != NULL) 35497c478bd9Sstevel@tonic-gate omp->next = mp->next; 35507c478bd9Sstevel@tonic-gate else 35517c478bd9Sstevel@tonic-gate miscpid_head = NULL; 35527c478bd9Sstevel@tonic-gate free(mp); 35537c478bd9Sstevel@tonic-gate } 35547c478bd9Sstevel@tonic-gate return (found); 35557c478bd9Sstevel@tonic-gate } 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate /* 35587c478bd9Sstevel@tonic-gate * Establish contract terms such that all children are in abandoned 35597c478bd9Sstevel@tonic-gate * process contracts. 35607c478bd9Sstevel@tonic-gate */ 3561032624d5Sbasabi static void 3562032624d5Sbasabi contract_set_template(void) 35637c478bd9Sstevel@tonic-gate { 35647c478bd9Sstevel@tonic-gate int fd; 35657c478bd9Sstevel@tonic-gate 35667c478bd9Sstevel@tonic-gate if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) < 0) 35677c478bd9Sstevel@tonic-gate crabort("cannot open process contract template", 35687c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 35697c478bd9Sstevel@tonic-gate 35707c478bd9Sstevel@tonic-gate if (ct_pr_tmpl_set_param(fd, 0) || 35717c478bd9Sstevel@tonic-gate ct_tmpl_set_informative(fd, 0) || 35727c478bd9Sstevel@tonic-gate ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR)) 35737c478bd9Sstevel@tonic-gate crabort("cannot establish contract template terms", 35747c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 35757c478bd9Sstevel@tonic-gate 35767c478bd9Sstevel@tonic-gate if (ct_tmpl_activate(fd)) 35777c478bd9Sstevel@tonic-gate crabort("cannot activate contract template", 35787c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 35797c478bd9Sstevel@tonic-gate 35807c478bd9Sstevel@tonic-gate (void) close(fd); 35817c478bd9Sstevel@tonic-gate } 35827c478bd9Sstevel@tonic-gate 35837c478bd9Sstevel@tonic-gate /* 35847c478bd9Sstevel@tonic-gate * Clear active process contract template. 35857c478bd9Sstevel@tonic-gate */ 3586032624d5Sbasabi static void 3587032624d5Sbasabi contract_clear_template(void) 35887c478bd9Sstevel@tonic-gate { 35897c478bd9Sstevel@tonic-gate int fd; 35907c478bd9Sstevel@tonic-gate 35917c478bd9Sstevel@tonic-gate if ((fd = open64(CTFS_ROOT "/process/template", O_RDWR)) < 0) 35927c478bd9Sstevel@tonic-gate crabort("cannot open process contract template", 35937c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 35947c478bd9Sstevel@tonic-gate 35957c478bd9Sstevel@tonic-gate if (ct_tmpl_clear(fd)) 35967c478bd9Sstevel@tonic-gate crabort("cannot clear contract template", 35977c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 35987c478bd9Sstevel@tonic-gate 35997c478bd9Sstevel@tonic-gate (void) close(fd); 36007c478bd9Sstevel@tonic-gate } 36017c478bd9Sstevel@tonic-gate 36027c478bd9Sstevel@tonic-gate /* 36037c478bd9Sstevel@tonic-gate * Abandon latest process contract unconditionally. If we have leaked [some 36047c478bd9Sstevel@tonic-gate * critical amount], exit such that the kernel reaps our contracts. 36057c478bd9Sstevel@tonic-gate */ 36067c478bd9Sstevel@tonic-gate static void 36077c478bd9Sstevel@tonic-gate contract_abandon_latest(pid_t pid) 36087c478bd9Sstevel@tonic-gate { 36097c478bd9Sstevel@tonic-gate int r; 36107c478bd9Sstevel@tonic-gate ctid_t id; 36117c478bd9Sstevel@tonic-gate static uint_t cts_lost; 36127c478bd9Sstevel@tonic-gate 36137c478bd9Sstevel@tonic-gate if (cts_lost > MAX_LOST_CONTRACTS) 36147c478bd9Sstevel@tonic-gate crabort("repeated failure to abandon contracts", 36157c478bd9Sstevel@tonic-gate REMOVE_FIFO | CONSOLE_MSG); 36167c478bd9Sstevel@tonic-gate 36177c478bd9Sstevel@tonic-gate if (r = contract_latest(&id)) { 361855aa09b1Sbasabi msg("could not obtain latest contract for " 361955aa09b1Sbasabi "PID %ld: %s", pid, strerror(r)); 36207c478bd9Sstevel@tonic-gate cts_lost++; 36217c478bd9Sstevel@tonic-gate return; 36227c478bd9Sstevel@tonic-gate } 36237c478bd9Sstevel@tonic-gate 36247c478bd9Sstevel@tonic-gate if (r = contract_abandon_id(id)) { 36257c478bd9Sstevel@tonic-gate msg("could not abandon latest contract %ld: %s", id, 36267c478bd9Sstevel@tonic-gate strerror(r)); 36277c478bd9Sstevel@tonic-gate cts_lost++; 36287c478bd9Sstevel@tonic-gate return; 36297c478bd9Sstevel@tonic-gate } 36307c478bd9Sstevel@tonic-gate } 3631*5b08e637SChris Gerhard 3632*5b08e637SChris Gerhard static struct shared * 3633*5b08e637SChris Gerhard create_shared(void *obj, void * (*obj_alloc)(void *obj), 3634*5b08e637SChris Gerhard void (*obj_free)(void *)) 3635*5b08e637SChris Gerhard { 3636*5b08e637SChris Gerhard struct shared *out; 3637*5b08e637SChris Gerhard 3638*5b08e637SChris Gerhard if ((out = xmalloc(sizeof (struct shared))) == NULL) { 3639*5b08e637SChris Gerhard return (NULL); 3640*5b08e637SChris Gerhard } 3641*5b08e637SChris Gerhard if ((out->obj = obj_alloc(obj)) == NULL) { 3642*5b08e637SChris Gerhard free(out); 3643*5b08e637SChris Gerhard return (NULL); 3644*5b08e637SChris Gerhard } 3645*5b08e637SChris Gerhard out->count = 1; 3646*5b08e637SChris Gerhard out->free = obj_free; 3647*5b08e637SChris Gerhard 3648*5b08e637SChris Gerhard return (out); 3649*5b08e637SChris Gerhard } 3650*5b08e637SChris Gerhard 3651*5b08e637SChris Gerhard static struct shared * 3652*5b08e637SChris Gerhard create_shared_str(char *str) 3653*5b08e637SChris Gerhard { 3654*5b08e637SChris Gerhard return (create_shared(str, (void *(*)(void *))strdup, free)); 3655*5b08e637SChris Gerhard } 3656*5b08e637SChris Gerhard 3657*5b08e637SChris Gerhard static struct shared * 3658*5b08e637SChris Gerhard dup_shared(struct shared *obj) 3659*5b08e637SChris Gerhard { 3660*5b08e637SChris Gerhard if (obj != NULL) { 3661*5b08e637SChris Gerhard obj->count++; 3662*5b08e637SChris Gerhard } 3663*5b08e637SChris Gerhard return (obj); 3664*5b08e637SChris Gerhard } 3665*5b08e637SChris Gerhard 3666*5b08e637SChris Gerhard static void 3667*5b08e637SChris Gerhard rel_shared(struct shared *obj) 3668*5b08e637SChris Gerhard { 3669*5b08e637SChris Gerhard if (obj && (--obj->count) == 0) { 3670*5b08e637SChris Gerhard obj->free(obj->obj); 3671*5b08e637SChris Gerhard free(obj); 3672*5b08e637SChris Gerhard } 3673*5b08e637SChris Gerhard } 3674*5b08e637SChris Gerhard 3675*5b08e637SChris Gerhard static void * 3676*5b08e637SChris Gerhard get_obj(struct shared *obj) 3677*5b08e637SChris Gerhard { 3678*5b08e637SChris Gerhard return (obj->obj); 3679*5b08e637SChris Gerhard } 3680