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 5d1419d5aSNobutomo Nakano * Common Development and Distribution License (the "License"). 6d1419d5aSNobutomo Nakano * 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 227c478bd9Sstevel@tonic-gate /* 23b0d023d2SGary Mills * Copyright (c) 2011 Gary Mills 24b0d023d2SGary Mills * 25d1419d5aSNobutomo Nakano * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 267c478bd9Sstevel@tonic-gate * Use is subject to license terms. 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 29032624d5Sbasabi /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 30032624d5Sbasabi /* All Rights Reserved */ 31032624d5Sbasabi 327c478bd9Sstevel@tonic-gate #include <sys/resource.h> 337c478bd9Sstevel@tonic-gate #include <sys/stat.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #include <dirent.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <stdlib.h> 397c478bd9Sstevel@tonic-gate #include <fcntl.h> 407c478bd9Sstevel@tonic-gate #include <pwd.h> 417c478bd9Sstevel@tonic-gate #include <stdio.h> 427c478bd9Sstevel@tonic-gate #include <ctype.h> 437c478bd9Sstevel@tonic-gate #include <time.h> 447c478bd9Sstevel@tonic-gate #include <signal.h> 457c478bd9Sstevel@tonic-gate #include <errno.h> 467c478bd9Sstevel@tonic-gate #include <limits.h> 477c478bd9Sstevel@tonic-gate #include <ulimit.h> 487c478bd9Sstevel@tonic-gate #include <unistd.h> 497c478bd9Sstevel@tonic-gate #include <locale.h> 507c478bd9Sstevel@tonic-gate #include <libintl.h> 517c478bd9Sstevel@tonic-gate #include <tzfile.h> 527c478bd9Sstevel@tonic-gate #include <project.h> 536a5408e6SRichard Lowe #include <paths.h> 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate #include "cron.h" 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate #define TMPFILE "_at" /* prefix for temporary files */ 587c478bd9Sstevel@tonic-gate /* 597c478bd9Sstevel@tonic-gate * Mode for creating files in ATDIR. 607c478bd9Sstevel@tonic-gate * Setuid bit on so that if an owner of a file gives that file 617c478bd9Sstevel@tonic-gate * away to someone else, the setuid bit will no longer be set. 627c478bd9Sstevel@tonic-gate * If this happens, atrun will not execute the file 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate #define ATMODE (S_ISUID | S_IRUSR | S_IRGRP | S_IROTH) 657c478bd9Sstevel@tonic-gate #define ROOT 0 /* user-id of super-user */ 667c478bd9Sstevel@tonic-gate #define MAXTRYS 100 /* max trys to create at job file */ 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate #define BADTIME "bad time specification" 697c478bd9Sstevel@tonic-gate #define BADQUEUE "queue name must be a single character a-z" 707c478bd9Sstevel@tonic-gate #define NOTCQUEUE "queue c is reserved for cron entries" 717c478bd9Sstevel@tonic-gate #define BADSHELL "because your login shell isn't /usr/bin/sh,"\ 727c478bd9Sstevel@tonic-gate "you can't use at" 737c478bd9Sstevel@tonic-gate #define WARNSHELL "commands will be executed using %s\n" 747c478bd9Sstevel@tonic-gate #define CANTCD "can't change directory to the at directory" 757c478bd9Sstevel@tonic-gate #define CANTCHOWN "can't change the owner of your job to you" 76b0d023d2SGary Mills #define CANTCHUID "can't change user identifier" 777c478bd9Sstevel@tonic-gate #define CANTCREATE "can't create a job for you" 787c478bd9Sstevel@tonic-gate #define INVALIDUSER "you are not a valid user (no entry in /etc/passwd)" 797c478bd9Sstevel@tonic-gate #define NOOPENDIR "can't open the at directory" 807c478bd9Sstevel@tonic-gate #define NOTALLOWED "you are not authorized to use at. Sorry." 817c478bd9Sstevel@tonic-gate #define USAGE\ 827c478bd9Sstevel@tonic-gate "usage: at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\ 837c478bd9Sstevel@tonic-gate "-t time\n"\ 847c478bd9Sstevel@tonic-gate " at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\ 857c478bd9Sstevel@tonic-gate "timespec\n"\ 867c478bd9Sstevel@tonic-gate " at -l [-p project] [-q queuename] [at_job_id...]\n"\ 877c478bd9Sstevel@tonic-gate " at -r at_job_id ...\n" 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate #define FORMAT "%a %b %e %H:%M:%S %Y" 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static int leap(int); 927c478bd9Sstevel@tonic-gate static int atoi_for2(char *); 937c478bd9Sstevel@tonic-gate static int check_queue(char *, int); 947c478bd9Sstevel@tonic-gate static int list_jobs(int, char **, int, int); 957c478bd9Sstevel@tonic-gate static int remove_jobs(int, char **, char *); 967c478bd9Sstevel@tonic-gate static void usage(void); 977c478bd9Sstevel@tonic-gate static void catch(int); 987c478bd9Sstevel@tonic-gate static void copy(char *, FILE *, int); 997c478bd9Sstevel@tonic-gate static void atime(struct tm *, struct tm *); 1007c478bd9Sstevel@tonic-gate static int not_this_project(char *); 1017c478bd9Sstevel@tonic-gate static char *mkjobname(time_t); 1027c478bd9Sstevel@tonic-gate static time_t parse_time(char *); 1037c478bd9Sstevel@tonic-gate static time_t gtime(struct tm *); 104*a725189cSMohamed A. Khalfella static void escapestr(const char *); 105032624d5Sbasabi void atabort(char *)__NORETURN; 1067c478bd9Sstevel@tonic-gate void yyerror(void); 1077c478bd9Sstevel@tonic-gate extern int yyparse(void); 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate extern void audit_at_delete(char *, char *, int); 1107c478bd9Sstevel@tonic-gate extern int audit_at_create(char *, int); 1117c478bd9Sstevel@tonic-gate extern int audit_cron_is_anc_name(char *); 1127c478bd9Sstevel@tonic-gate extern int audit_cron_delete_anc_file(char *, char *); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * Error in getdate(3G) 1167c478bd9Sstevel@tonic-gate */ 1177c478bd9Sstevel@tonic-gate static char *errlist[] = { 1187c478bd9Sstevel@tonic-gate /* 0 */ "", 1197c478bd9Sstevel@tonic-gate /* 1 */ "getdate: The DATEMSK environment variable is not set", 1207c478bd9Sstevel@tonic-gate /* 2 */ "getdate: Error on \"open\" of the template file", 1217c478bd9Sstevel@tonic-gate /* 3 */ "getdate: Error on \"stat\" of the template file", 1227c478bd9Sstevel@tonic-gate /* 4 */ "getdate: The template file is not a regular file", 1237c478bd9Sstevel@tonic-gate /* 5 */ "getdate: An error is encountered while reading the template", 1247c478bd9Sstevel@tonic-gate /* 6 */ "getdate: Malloc(3C) failed", 1257c478bd9Sstevel@tonic-gate /* 7 */ "getdate: There is no line in the template that matches the input", 1267c478bd9Sstevel@tonic-gate /* 8 */ "getdate: Invalid input specification" 1277c478bd9Sstevel@tonic-gate }; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate int gmtflag = 0; 1307c478bd9Sstevel@tonic-gate int mday[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 1317c478bd9Sstevel@tonic-gate uid_t user; 1327c478bd9Sstevel@tonic-gate struct tm *tp, at, rt; 1337c478bd9Sstevel@tonic-gate static int cshflag = 0; 1347c478bd9Sstevel@tonic-gate static int kshflag = 0; 1357c478bd9Sstevel@tonic-gate static int shflag = 0; 1367c478bd9Sstevel@tonic-gate static int mflag = 0; 1377c478bd9Sstevel@tonic-gate static int pflag = 0; 1387c478bd9Sstevel@tonic-gate static char *Shell; 1397c478bd9Sstevel@tonic-gate static char *tfname; 1407c478bd9Sstevel@tonic-gate static char pname[80]; 1417c478bd9Sstevel@tonic-gate static char pname1[80]; 1427c478bd9Sstevel@tonic-gate static short jobtype = ATEVENT; /* set to 1 if batch job */ 1437c478bd9Sstevel@tonic-gate extern char *argp; 1447c478bd9Sstevel@tonic-gate extern int per_errno; 1457c478bd9Sstevel@tonic-gate static projid_t project; 1467c478bd9Sstevel@tonic-gate 147032624d5Sbasabi int 148032624d5Sbasabi main(int argc, char **argv) 1497c478bd9Sstevel@tonic-gate { 1507c478bd9Sstevel@tonic-gate FILE *inputfile; 1517c478bd9Sstevel@tonic-gate int i, fd; 1527c478bd9Sstevel@tonic-gate int try = 0; 1537c478bd9Sstevel@tonic-gate int fflag = 0; 1547c478bd9Sstevel@tonic-gate int lflag = 0; 1557c478bd9Sstevel@tonic-gate int qflag = 0; 1567c478bd9Sstevel@tonic-gate int rflag = 0; 1577c478bd9Sstevel@tonic-gate int tflag = 0; 1587c478bd9Sstevel@tonic-gate int c; 1597c478bd9Sstevel@tonic-gate int tflen; 1607c478bd9Sstevel@tonic-gate char *file; 1617c478bd9Sstevel@tonic-gate char *login; 1627c478bd9Sstevel@tonic-gate char *job; 1637c478bd9Sstevel@tonic-gate char *jobfile = NULL; /* file containing job to be run */ 1647c478bd9Sstevel@tonic-gate char argpbuf[LINE_MAX], timebuf[80]; 1657c478bd9Sstevel@tonic-gate time_t now; 1667c478bd9Sstevel@tonic-gate time_t when = 0; 1677c478bd9Sstevel@tonic-gate struct tm *ct; 1687c478bd9Sstevel@tonic-gate char *proj; 1697c478bd9Sstevel@tonic-gate struct project prj, *pprj; 1707c478bd9Sstevel@tonic-gate char mybuf[PROJECT_BUFSZ]; 1717c478bd9Sstevel@tonic-gate char ipbuf[PROJECT_BUFSZ]; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 1747c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1757c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 1767c478bd9Sstevel@tonic-gate #endif 1777c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate user = getuid(); 1807c478bd9Sstevel@tonic-gate login = getuser(user); 1817c478bd9Sstevel@tonic-gate if (login == NULL) { 1827c478bd9Sstevel@tonic-gate if (per_errno == 2) 1837c478bd9Sstevel@tonic-gate atabort(BADSHELL); 1847c478bd9Sstevel@tonic-gate else 1857c478bd9Sstevel@tonic-gate atabort(INVALIDUSER); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (!allowed(login, ATALLOW, ATDENY)) 1897c478bd9Sstevel@tonic-gate atabort(NOTALLOWED); 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "cklmsrf:p:q:t:")) != EOF) 1927c478bd9Sstevel@tonic-gate switch (c) { 1937c478bd9Sstevel@tonic-gate case 'c': 1947c478bd9Sstevel@tonic-gate cshflag++; 1957c478bd9Sstevel@tonic-gate break; 1967c478bd9Sstevel@tonic-gate case 'f': 1977c478bd9Sstevel@tonic-gate fflag++; 1987c478bd9Sstevel@tonic-gate jobfile = optarg; 1997c478bd9Sstevel@tonic-gate break; 2007c478bd9Sstevel@tonic-gate case 'k': 2017c478bd9Sstevel@tonic-gate kshflag++; 2027c478bd9Sstevel@tonic-gate break; 2037c478bd9Sstevel@tonic-gate case 'l': 2047c478bd9Sstevel@tonic-gate lflag++; 2057c478bd9Sstevel@tonic-gate break; 2067c478bd9Sstevel@tonic-gate case 'm': 2077c478bd9Sstevel@tonic-gate mflag++; 2087c478bd9Sstevel@tonic-gate break; 2097c478bd9Sstevel@tonic-gate case 'p': 2107c478bd9Sstevel@tonic-gate proj = optarg; 2117c478bd9Sstevel@tonic-gate pprj = &prj; 2127c478bd9Sstevel@tonic-gate if ((pprj = getprojbyname(proj, pprj, 2137c478bd9Sstevel@tonic-gate (void *)&mybuf, sizeof (mybuf))) != NULL) { 2147c478bd9Sstevel@tonic-gate project = pprj->pj_projid; 2157c478bd9Sstevel@tonic-gate if (inproj(login, pprj->pj_name, 2167c478bd9Sstevel@tonic-gate (void *)&ipbuf, sizeof (ipbuf))) 2177c478bd9Sstevel@tonic-gate pflag++; 2187c478bd9Sstevel@tonic-gate else { 2197c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2207c478bd9Sstevel@tonic-gate gettext("at: user %s is " 2217c478bd9Sstevel@tonic-gate "not a member of " 2227c478bd9Sstevel@tonic-gate "project %s (%d)\n"), 2237c478bd9Sstevel@tonic-gate login, pprj->pj_name, 2247c478bd9Sstevel@tonic-gate project); 2257c478bd9Sstevel@tonic-gate exit(2); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate break; 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate pprj = &prj; 2307c478bd9Sstevel@tonic-gate if (isdigit(proj[0]) && 2317c478bd9Sstevel@tonic-gate (pprj = getprojbyid(atoi(proj), pprj, 2327c478bd9Sstevel@tonic-gate (void *)&mybuf, sizeof (mybuf))) != NULL) { 2337c478bd9Sstevel@tonic-gate project = pprj->pj_projid; 2347c478bd9Sstevel@tonic-gate if (inproj(login, pprj->pj_name, 2357c478bd9Sstevel@tonic-gate (void *)&ipbuf, sizeof (ipbuf))) 2367c478bd9Sstevel@tonic-gate pflag++; 2377c478bd9Sstevel@tonic-gate else { 2387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2397c478bd9Sstevel@tonic-gate gettext("at: user %s is " 2407c478bd9Sstevel@tonic-gate "not a member of " 2417c478bd9Sstevel@tonic-gate "project %s (%d)\n"), 2427c478bd9Sstevel@tonic-gate login, pprj->pj_name, 2437c478bd9Sstevel@tonic-gate project); 2447c478bd9Sstevel@tonic-gate exit(2); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate break; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("at: project " 2497c478bd9Sstevel@tonic-gate "%s not found.\n"), proj); 2507c478bd9Sstevel@tonic-gate exit(2); 2517c478bd9Sstevel@tonic-gate break; 2527c478bd9Sstevel@tonic-gate case 'q': 2537c478bd9Sstevel@tonic-gate qflag++; 2547c478bd9Sstevel@tonic-gate if (optarg[1] != '\0') 2557c478bd9Sstevel@tonic-gate atabort(BADQUEUE); 2567c478bd9Sstevel@tonic-gate jobtype = *optarg - 'a'; 2577c478bd9Sstevel@tonic-gate if ((jobtype < 0) || (jobtype > 25)) 2587c478bd9Sstevel@tonic-gate atabort(BADQUEUE); 2597c478bd9Sstevel@tonic-gate if (jobtype == 2) 2607c478bd9Sstevel@tonic-gate atabort(NOTCQUEUE); 2617c478bd9Sstevel@tonic-gate break; 2627c478bd9Sstevel@tonic-gate case 'r': 2637c478bd9Sstevel@tonic-gate rflag++; 2647c478bd9Sstevel@tonic-gate break; 2657c478bd9Sstevel@tonic-gate case 's': 2667c478bd9Sstevel@tonic-gate shflag++; 2677c478bd9Sstevel@tonic-gate break; 2687c478bd9Sstevel@tonic-gate case 't': 2697c478bd9Sstevel@tonic-gate tflag++; 2707c478bd9Sstevel@tonic-gate when = parse_time(optarg); 2717c478bd9Sstevel@tonic-gate break; 2727c478bd9Sstevel@tonic-gate default: 2737c478bd9Sstevel@tonic-gate usage(); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate argc -= optind; 2777c478bd9Sstevel@tonic-gate argv += optind; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate if (lflag + rflag > 1) 2807c478bd9Sstevel@tonic-gate usage(); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate if (lflag) { 2837c478bd9Sstevel@tonic-gate if (cshflag || kshflag || shflag || mflag || 2847c478bd9Sstevel@tonic-gate fflag || tflag || rflag) 2857c478bd9Sstevel@tonic-gate usage(); 2867c478bd9Sstevel@tonic-gate return (list_jobs(argc, argv, qflag, jobtype)); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate if (rflag) { 2907c478bd9Sstevel@tonic-gate if (cshflag || kshflag || shflag || mflag || 2917c478bd9Sstevel@tonic-gate fflag || tflag || qflag) 2927c478bd9Sstevel@tonic-gate usage(); 2937c478bd9Sstevel@tonic-gate return (remove_jobs(argc, argv, login)); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate if ((argc + tflag == 0) && (jobtype != BATCHEVENT)) 2977c478bd9Sstevel@tonic-gate usage(); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (cshflag + kshflag + shflag > 1) 3007c478bd9Sstevel@tonic-gate atabort("ambiguous shell request"); 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate time(&now); 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if (jobtype == BATCHEVENT) 3057c478bd9Sstevel@tonic-gate when = now; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if (when == 0) { /* figure out what time to run the job */ 3087c478bd9Sstevel@tonic-gate int argplen = sizeof (argpbuf) - 1; 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate argpbuf[0] = '\0'; 3117c478bd9Sstevel@tonic-gate argp = argpbuf; 3127c478bd9Sstevel@tonic-gate i = 0; 3137c478bd9Sstevel@tonic-gate while (i < argc) { 3147c478bd9Sstevel@tonic-gate /* guard against buffer overflow */ 3157c478bd9Sstevel@tonic-gate argplen -= strlen(argv[i]) + 1; 3167c478bd9Sstevel@tonic-gate if (argplen < 0) 3177c478bd9Sstevel@tonic-gate atabort(BADTIME); 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate strcat(argp, argv[i]); 3207c478bd9Sstevel@tonic-gate strcat(argp, " "); 3217c478bd9Sstevel@tonic-gate i++; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate if ((file = getenv("DATEMSK")) == 0 || file[0] == '\0') { 3247c478bd9Sstevel@tonic-gate tp = localtime(&now); 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Fix for 1047182 - we have to let yyparse 3277c478bd9Sstevel@tonic-gate * check bounds on mday[] first, then fixup 3287c478bd9Sstevel@tonic-gate * the leap year case. 3297c478bd9Sstevel@tonic-gate */ 3307c478bd9Sstevel@tonic-gate yyparse(); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate mday[1] = 28 + leap(at.tm_year); 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate if (at.tm_mday > mday[at.tm_mon]) 3357c478bd9Sstevel@tonic-gate atabort("bad date"); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate atime(&at, &rt); 3387c478bd9Sstevel@tonic-gate when = gtime(&at); 3397c478bd9Sstevel@tonic-gate if (!gmtflag) { 3407c478bd9Sstevel@tonic-gate when += timezone; 3417c478bd9Sstevel@tonic-gate if (localtime(&when)->tm_isdst) 3427c478bd9Sstevel@tonic-gate when -= (timezone-altzone); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate } else { /* DATEMSK is set */ 3457c478bd9Sstevel@tonic-gate if ((ct = getdate(argpbuf)) == NULL) 3467c478bd9Sstevel@tonic-gate atabort(errlist[getdate_err]); 3477c478bd9Sstevel@tonic-gate else 3487c478bd9Sstevel@tonic-gate when = mktime(ct); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate if (when < now) /* time has already past */ 3537c478bd9Sstevel@tonic-gate atabort("too late"); 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate tflen = strlen(ATDIR) + 1 + strlen(TMPFILE) + 3567c478bd9Sstevel@tonic-gate 10 + 1; /* 10 for an INT_MAX pid */ 3577c478bd9Sstevel@tonic-gate tfname = xmalloc(tflen); 3587c478bd9Sstevel@tonic-gate snprintf(tfname, tflen, "%s/%s%d", ATDIR, TMPFILE, getpid()); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* catch INT, HUP, TERM and QUIT signals */ 3617c478bd9Sstevel@tonic-gate if (signal(SIGINT, catch) == SIG_IGN) 3627c478bd9Sstevel@tonic-gate signal(SIGINT, SIG_IGN); 3637c478bd9Sstevel@tonic-gate if (signal(SIGHUP, catch) == SIG_IGN) 3647c478bd9Sstevel@tonic-gate signal(SIGHUP, SIG_IGN); 3657c478bd9Sstevel@tonic-gate if (signal(SIGQUIT, catch) == SIG_IGN) 3667c478bd9Sstevel@tonic-gate signal(SIGQUIT, SIG_IGN); 3677c478bd9Sstevel@tonic-gate if (signal(SIGTERM, catch) == SIG_IGN) 3687c478bd9Sstevel@tonic-gate signal(SIGTERM, SIG_IGN); 3697c478bd9Sstevel@tonic-gate if ((fd = open(tfname, O_CREAT|O_EXCL|O_WRONLY, ATMODE)) < 0) 3707c478bd9Sstevel@tonic-gate atabort(CANTCREATE); 3717c478bd9Sstevel@tonic-gate if (chown(tfname, user, getgid()) == -1) { 3727c478bd9Sstevel@tonic-gate unlink(tfname); 3737c478bd9Sstevel@tonic-gate atabort(CANTCHOWN); 3747c478bd9Sstevel@tonic-gate } 3757c478bd9Sstevel@tonic-gate close(1); 3767c478bd9Sstevel@tonic-gate dup(fd); 3777c478bd9Sstevel@tonic-gate close(fd); 3787c478bd9Sstevel@tonic-gate sprintf(pname, "%s", PROTO); 3797c478bd9Sstevel@tonic-gate sprintf(pname1, "%s.%c", PROTO, 'a'+jobtype); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate /* 3827c478bd9Sstevel@tonic-gate * Open the input file with the user's permissions. 3837c478bd9Sstevel@tonic-gate */ 3847c478bd9Sstevel@tonic-gate if (jobfile != NULL) { 3857c478bd9Sstevel@tonic-gate if ((seteuid(user) < 0) || 3867c478bd9Sstevel@tonic-gate (inputfile = fopen(jobfile, "r")) == NULL) { 3877c478bd9Sstevel@tonic-gate unlink(tfname); 3887c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: %s\n", jobfile, errmsg(errno)); 3897c478bd9Sstevel@tonic-gate exit(1); 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate else 3927c478bd9Sstevel@tonic-gate seteuid(0); 3937c478bd9Sstevel@tonic-gate } else 3947c478bd9Sstevel@tonic-gate inputfile = stdin; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate copy(jobfile, inputfile, when); 3977c478bd9Sstevel@tonic-gate while (rename(tfname, job = mkjobname(when)) == -1) { 3987c478bd9Sstevel@tonic-gate sleep(1); 3997c478bd9Sstevel@tonic-gate if (++try > MAXTRYS / 10) { 4007c478bd9Sstevel@tonic-gate unlink(tfname); 4017c478bd9Sstevel@tonic-gate atabort(CANTCREATE); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate } 4047c478bd9Sstevel@tonic-gate unlink(tfname); 4057c478bd9Sstevel@tonic-gate if (audit_at_create(job, 0)) 4067c478bd9Sstevel@tonic-gate atabort(CANTCREATE); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate cron_sendmsg(ADD, login, strrchr(job, '/')+1, AT); 4097c478bd9Sstevel@tonic-gate if (per_errno == 2) 4107c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(WARNSHELL), Shell); 4117c478bd9Sstevel@tonic-gate cftime(timebuf, FORMAT, &when); 4127c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("job %s at %s\n"), 4137c478bd9Sstevel@tonic-gate strrchr(job, '/')+1, timebuf); 4147c478bd9Sstevel@tonic-gate if (when - MINUTE < HOUR) 4157c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 4167c478bd9Sstevel@tonic-gate "at: this job may not be executed at the proper time.\n")); 4177c478bd9Sstevel@tonic-gate return (0); 4187c478bd9Sstevel@tonic-gate } 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate static char * 4227c478bd9Sstevel@tonic-gate mkjobname(t) 4237c478bd9Sstevel@tonic-gate time_t t; 4247c478bd9Sstevel@tonic-gate { 4257c478bd9Sstevel@tonic-gate int i, fd; 4267c478bd9Sstevel@tonic-gate char *name; 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate name = xmalloc(200); 4297c478bd9Sstevel@tonic-gate for (i = 0; i < MAXTRYS; i++) { 4307c478bd9Sstevel@tonic-gate sprintf(name, "%s/%ld.%c", ATDIR, t, 'a'+jobtype); 4317c478bd9Sstevel@tonic-gate /* fix for 1099183, 1116833 - create file here, avoid race */ 4327c478bd9Sstevel@tonic-gate if ((fd = open(name, O_CREAT | O_EXCL, ATMODE)) > 0) { 4337c478bd9Sstevel@tonic-gate close(fd); 4347c478bd9Sstevel@tonic-gate return (name); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate t += 1; 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate atabort("queue full"); 439032624d5Sbasabi /* NOTREACHED */ 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate static void 4447c478bd9Sstevel@tonic-gate catch(int x) 4457c478bd9Sstevel@tonic-gate { 4467c478bd9Sstevel@tonic-gate unlink(tfname); 4477c478bd9Sstevel@tonic-gate exit(1); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate void 4527c478bd9Sstevel@tonic-gate atabort(msg) 4537c478bd9Sstevel@tonic-gate char *msg; 4547c478bd9Sstevel@tonic-gate { 4557c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s\n", gettext(msg)); 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate exit(1); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 460032624d5Sbasabi int 4617c478bd9Sstevel@tonic-gate yywrap(void) 4627c478bd9Sstevel@tonic-gate { 4637c478bd9Sstevel@tonic-gate return (1); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate void 4677c478bd9Sstevel@tonic-gate yyerror(void) 4687c478bd9Sstevel@tonic-gate { 4697c478bd9Sstevel@tonic-gate atabort(BADTIME); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate /* 4737c478bd9Sstevel@tonic-gate * add time structures logically 4747c478bd9Sstevel@tonic-gate */ 4757c478bd9Sstevel@tonic-gate static void 4767c478bd9Sstevel@tonic-gate atime(struct tm *a, struct tm *b) 4777c478bd9Sstevel@tonic-gate { 4787c478bd9Sstevel@tonic-gate if ((a->tm_sec += b->tm_sec) >= 60) { 4797c478bd9Sstevel@tonic-gate b->tm_min += a->tm_sec / 60; 4807c478bd9Sstevel@tonic-gate a->tm_sec %= 60; 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate if ((a->tm_min += b->tm_min) >= 60) { 4837c478bd9Sstevel@tonic-gate b->tm_hour += a->tm_min / 60; 4847c478bd9Sstevel@tonic-gate a->tm_min %= 60; 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate if ((a->tm_hour += b->tm_hour) >= 24) { 4877c478bd9Sstevel@tonic-gate b->tm_mday += a->tm_hour / 24; 4887c478bd9Sstevel@tonic-gate a->tm_hour %= 24; 4897c478bd9Sstevel@tonic-gate } 4907c478bd9Sstevel@tonic-gate a->tm_year += b->tm_year; 4917c478bd9Sstevel@tonic-gate if ((a->tm_mon += b->tm_mon) >= 12) { 4927c478bd9Sstevel@tonic-gate a->tm_year += a->tm_mon / 12; 4937c478bd9Sstevel@tonic-gate a->tm_mon %= 12; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate a->tm_mday += b->tm_mday; 4967c478bd9Sstevel@tonic-gate mday[1] = 28 + leap(a->tm_year); 4977c478bd9Sstevel@tonic-gate while (a->tm_mday > mday[a->tm_mon]) { 4987c478bd9Sstevel@tonic-gate a->tm_mday -= mday[a->tm_mon++]; 4997c478bd9Sstevel@tonic-gate if (a->tm_mon > 11) { 5007c478bd9Sstevel@tonic-gate a->tm_mon = 0; 5017c478bd9Sstevel@tonic-gate mday[1] = 28 + leap(++a->tm_year); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate static int 5087c478bd9Sstevel@tonic-gate leap(int year) 5097c478bd9Sstevel@tonic-gate { 5107c478bd9Sstevel@tonic-gate return (isleap(year + TM_YEAR_BASE)); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * return time from time structure 5157c478bd9Sstevel@tonic-gate */ 5167c478bd9Sstevel@tonic-gate static time_t 5177c478bd9Sstevel@tonic-gate gtime(tptr) 5187c478bd9Sstevel@tonic-gate struct tm *tptr; 5197c478bd9Sstevel@tonic-gate { 520032624d5Sbasabi int i; 5217c478bd9Sstevel@tonic-gate long tv; 5227c478bd9Sstevel@tonic-gate int dmsize[12] = 5237c478bd9Sstevel@tonic-gate {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate tv = 0; 5277c478bd9Sstevel@tonic-gate for (i = 1970; i != tptr->tm_year+TM_YEAR_BASE; i++) 5287c478bd9Sstevel@tonic-gate tv += (365 + isleap(i)); 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * We call isleap since leap() adds 5317c478bd9Sstevel@tonic-gate * 1900 onto any value passed 5327c478bd9Sstevel@tonic-gate */ 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (!leap(tptr->tm_year) && at.tm_mday == 29 && at.tm_mon == 1) 5357c478bd9Sstevel@tonic-gate atabort("bad date - not a leap year"); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if ((leap(tptr->tm_year)) && tptr->tm_mon >= 2) 5387c478bd9Sstevel@tonic-gate ++tv; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate for (i = 0; i < tptr->tm_mon; ++i) 5417c478bd9Sstevel@tonic-gate tv += dmsize[i]; 5427c478bd9Sstevel@tonic-gate tv += tptr->tm_mday - 1; 5437c478bd9Sstevel@tonic-gate tv = 24 * tv + tptr->tm_hour; 5447c478bd9Sstevel@tonic-gate tv = 60 * tv + tptr->tm_min; 5457c478bd9Sstevel@tonic-gate tv = 60 * tv + tptr->tm_sec; 5467c478bd9Sstevel@tonic-gate return (tv); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* 550*a725189cSMohamed A. Khalfella * Escape a string to be used inside the job shell script. 551*a725189cSMohamed A. Khalfella */ 552*a725189cSMohamed A. Khalfella static void 553*a725189cSMohamed A. Khalfella escapestr(const char *str) 554*a725189cSMohamed A. Khalfella { 555*a725189cSMohamed A. Khalfella char c; 556*a725189cSMohamed A. Khalfella (void) putchar('\''); 557*a725189cSMohamed A. Khalfella while ((c = *str++) != '\0') { 558*a725189cSMohamed A. Khalfella if (c != '\'') 559*a725189cSMohamed A. Khalfella (void) putchar(c); 560*a725189cSMohamed A. Khalfella else 561*a725189cSMohamed A. Khalfella (void) fputs("'\\''", stdout); /* ' -> '\'' */ 562*a725189cSMohamed A. Khalfella } 563*a725189cSMohamed A. Khalfella (void) putchar('\''); 564*a725189cSMohamed A. Khalfella } 565*a725189cSMohamed A. Khalfella 566*a725189cSMohamed A. Khalfella /* 5677c478bd9Sstevel@tonic-gate * make job file from proto + stdin 5687c478bd9Sstevel@tonic-gate */ 5697c478bd9Sstevel@tonic-gate static void 5707c478bd9Sstevel@tonic-gate copy(char *jobfile, FILE *inputfile, int when) 5717c478bd9Sstevel@tonic-gate { 572032624d5Sbasabi int c; 573032624d5Sbasabi FILE *pfp; 5747c478bd9Sstevel@tonic-gate char *shell; 5757c478bd9Sstevel@tonic-gate char dirbuf[PATH_MAX + 1]; 5767c478bd9Sstevel@tonic-gate char line[LINE_MAX]; 577032624d5Sbasabi char **ep; 5787c478bd9Sstevel@tonic-gate mode_t um; 5797c478bd9Sstevel@tonic-gate char *val; 5807c478bd9Sstevel@tonic-gate extern char **environ; 581b0d023d2SGary Mills uid_t realusr, effeusr; 5827c478bd9Sstevel@tonic-gate int ttyinput; 5837c478bd9Sstevel@tonic-gate int ulimit_flag = 0; 5847c478bd9Sstevel@tonic-gate struct rlimit rlp; 5857c478bd9Sstevel@tonic-gate struct project prj, *pprj; 5867c478bd9Sstevel@tonic-gate char pbuf[PROJECT_BUFSZ]; 5877c478bd9Sstevel@tonic-gate char pbuf2[PROJECT_BUFSZ]; 5887c478bd9Sstevel@tonic-gate char *user; 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * Fix for 1099381: 5927c478bd9Sstevel@tonic-gate * If the inputfile is from a tty, then turn on prompting, and 5937c478bd9Sstevel@tonic-gate * put out a prompt now, instead of waiting for a lot of file 5947c478bd9Sstevel@tonic-gate * activity to complete. 5957c478bd9Sstevel@tonic-gate */ 5967c478bd9Sstevel@tonic-gate ttyinput = isatty(fileno(inputfile)); 5977c478bd9Sstevel@tonic-gate if (ttyinput) { 5987c478bd9Sstevel@tonic-gate fputs("at> ", stderr); 5997c478bd9Sstevel@tonic-gate fflush(stderr); 6007c478bd9Sstevel@tonic-gate } 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate /* 6037c478bd9Sstevel@tonic-gate * Fix for 1053807: 6047c478bd9Sstevel@tonic-gate * Determine what shell we should use to run the job. If the user 6057c478bd9Sstevel@tonic-gate * didn't explicitly request that his/her current shell be over- 6067c478bd9Sstevel@tonic-gate * ridden (shflag or cshflag), then we use the current shell. 6077c478bd9Sstevel@tonic-gate */ 6087c478bd9Sstevel@tonic-gate if (cshflag) 6097c478bd9Sstevel@tonic-gate Shell = shell = "/bin/csh"; 6107c478bd9Sstevel@tonic-gate else if (kshflag) { 6117c478bd9Sstevel@tonic-gate Shell = shell = "/bin/ksh"; 6127c478bd9Sstevel@tonic-gate ulimit_flag = 1; 6137c478bd9Sstevel@tonic-gate } else if (shflag) { 6147c478bd9Sstevel@tonic-gate Shell = shell = "/bin/sh"; 6157c478bd9Sstevel@tonic-gate ulimit_flag = 1; 6167c478bd9Sstevel@tonic-gate } else if (((Shell = val = getenv("SHELL")) != NULL) && 6177c478bd9Sstevel@tonic-gate (*val != '\0')) { 6187c478bd9Sstevel@tonic-gate shell = "$SHELL"; 6197c478bd9Sstevel@tonic-gate if ((strstr(val, "/sh") != NULL) || 6207c478bd9Sstevel@tonic-gate (strstr(val, "/ksh") != NULL)) 6217c478bd9Sstevel@tonic-gate ulimit_flag = 1; 6227c478bd9Sstevel@tonic-gate } else { 6237c478bd9Sstevel@tonic-gate /* SHELL is NULL or unset, therefore use default */ 6246a5408e6SRichard Lowe Shell = shell = _PATH_BSHELL; 6257c478bd9Sstevel@tonic-gate ulimit_flag = 1; 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate printf(": %s job\n", jobtype ? "batch" : "at"); 6297c478bd9Sstevel@tonic-gate printf(": jobname: %.127s\n", (jobfile == NULL) ? "stdin" : jobfile); 6307c478bd9Sstevel@tonic-gate printf(": notify by mail: %s\n", (mflag) ? "yes" : "no"); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate if (pflag) { 6337c478bd9Sstevel@tonic-gate (void) printf(": project: %d\n", project); 6347c478bd9Sstevel@tonic-gate } else { 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * Check if current user is a member of current project. 6377c478bd9Sstevel@tonic-gate * This check is done here to avoid setproject() failure 6387c478bd9Sstevel@tonic-gate * later when the job gets executed. If current user does 6397c478bd9Sstevel@tonic-gate * not belong to current project, user's default project 6407c478bd9Sstevel@tonic-gate * will be used instead. This is achieved by not specifying 6417c478bd9Sstevel@tonic-gate * the project (": project: <project>\n") in the job file. 6427c478bd9Sstevel@tonic-gate */ 6437c478bd9Sstevel@tonic-gate if ((user = getuser(getuid())) == NULL) 6447c478bd9Sstevel@tonic-gate atabort(INVALIDUSER); 6457c478bd9Sstevel@tonic-gate project = getprojid(); 6467c478bd9Sstevel@tonic-gate pprj = getprojbyid(project, &prj, pbuf, sizeof (pbuf)); 6477c478bd9Sstevel@tonic-gate if (pprj != NULL) { 6487c478bd9Sstevel@tonic-gate if (inproj(user, pprj->pj_name, pbuf2, sizeof (pbuf2))) 6497c478bd9Sstevel@tonic-gate (void) printf(": project: %d\n", project); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate for (ep = environ; *ep; ep++) { 6547c478bd9Sstevel@tonic-gate if ((val = strchr(*ep, '=')) == NULL) 6557c478bd9Sstevel@tonic-gate continue; 6567c478bd9Sstevel@tonic-gate *val++ = '\0'; 657*a725189cSMohamed A. Khalfella (void) printf("export %s; %s=", *ep, *ep); 658*a725189cSMohamed A. Khalfella escapestr(val); 659*a725189cSMohamed A. Khalfella (void) putchar('\n'); 6607c478bd9Sstevel@tonic-gate *--val = '='; 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate if ((pfp = fopen(pname1, "r")) == NULL && 6637c478bd9Sstevel@tonic-gate (pfp = fopen(pname, "r")) == NULL) 6647c478bd9Sstevel@tonic-gate atabort("no prototype"); 6657c478bd9Sstevel@tonic-gate /* 6667c478bd9Sstevel@tonic-gate * Put in a line to run the proper shell using the rest of 6677c478bd9Sstevel@tonic-gate * the file as input. Note that 'exec'ing the shell will 6687c478bd9Sstevel@tonic-gate * cause sh() to leave a /tmp/sh### file around. (1053807) 6697c478bd9Sstevel@tonic-gate */ 6707c478bd9Sstevel@tonic-gate printf("%s << '...the rest of this file is shell input'\n", shell); 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate um = umask(0); 6737c478bd9Sstevel@tonic-gate while ((c = getc(pfp)) != EOF) { 6747c478bd9Sstevel@tonic-gate if (c != '$') 6757c478bd9Sstevel@tonic-gate putchar(c); 6767c478bd9Sstevel@tonic-gate else switch (c = getc(pfp)) { 6777c478bd9Sstevel@tonic-gate case EOF: 6787c478bd9Sstevel@tonic-gate goto out; 6797c478bd9Sstevel@tonic-gate case 'd': 6807c478bd9Sstevel@tonic-gate /* 681b0d023d2SGary Mills * Must obtain current working directory as the user 6827c478bd9Sstevel@tonic-gate */ 6837c478bd9Sstevel@tonic-gate 684b0d023d2SGary Mills dirbuf[0] = '\0'; 685b0d023d2SGary Mills realusr = getuid(); 686b0d023d2SGary Mills effeusr = geteuid(); 687b0d023d2SGary Mills /* change euid for getcwd */ 688b0d023d2SGary Mills if (seteuid(realusr) < 0) { 689b0d023d2SGary Mills atabort(CANTCHUID); 6907c478bd9Sstevel@tonic-gate } 691b0d023d2SGary Mills if (getcwd(dirbuf, sizeof (dirbuf)) == NULL) { 692b0d023d2SGary Mills atabort( 693b0d023d2SGary Mills "can't obtain current working directory"); 6947c478bd9Sstevel@tonic-gate } 695b0d023d2SGary Mills /* change back afterwards */ 696b0d023d2SGary Mills if (seteuid(effeusr) < 0) { 697b0d023d2SGary Mills atabort(CANTCHUID); 698b0d023d2SGary Mills } 699*a725189cSMohamed A. Khalfella escapestr(dirbuf); 7007c478bd9Sstevel@tonic-gate break; 7017c478bd9Sstevel@tonic-gate case 'm': 7027c478bd9Sstevel@tonic-gate printf("%o", um); 7037c478bd9Sstevel@tonic-gate break; 7047c478bd9Sstevel@tonic-gate case '<': 7057c478bd9Sstevel@tonic-gate if (ulimit_flag) { 7067c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_FSIZE, &rlp) == 0) { 7077c478bd9Sstevel@tonic-gate if (rlp.rlim_cur == RLIM_INFINITY) 7087c478bd9Sstevel@tonic-gate printf("ulimit unlimited\n"); 7097c478bd9Sstevel@tonic-gate else 7107c478bd9Sstevel@tonic-gate printf("ulimit %lld\n", 7117c478bd9Sstevel@tonic-gate rlp.rlim_cur / 512); 7127c478bd9Sstevel@tonic-gate } 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate /* 7157c478bd9Sstevel@tonic-gate * fix for 1113572 - use fputs() so that a 7167c478bd9Sstevel@tonic-gate * newline isn't appended to the one returned 7177c478bd9Sstevel@tonic-gate * with fgets(); 1099381 - prompt for input. 7187c478bd9Sstevel@tonic-gate */ 7197c478bd9Sstevel@tonic-gate while (fgets(line, LINE_MAX, inputfile) != NULL) { 7207c478bd9Sstevel@tonic-gate fputs(line, stdout); 7217c478bd9Sstevel@tonic-gate if (ttyinput) 7227c478bd9Sstevel@tonic-gate fputs("at> ", stderr); 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate if (ttyinput) /* clean up the final output */ 7257c478bd9Sstevel@tonic-gate fputs("<EOT>\n", stderr); 7267c478bd9Sstevel@tonic-gate break; 7277c478bd9Sstevel@tonic-gate case 't': 7287c478bd9Sstevel@tonic-gate printf(":%lu", when); 7297c478bd9Sstevel@tonic-gate break; 7307c478bd9Sstevel@tonic-gate default: 7317c478bd9Sstevel@tonic-gate putchar(c); 7327c478bd9Sstevel@tonic-gate } 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate out: 7357c478bd9Sstevel@tonic-gate fclose(pfp); 7367c478bd9Sstevel@tonic-gate fflush(NULL); 7377c478bd9Sstevel@tonic-gate } 7387c478bd9Sstevel@tonic-gate 7397c478bd9Sstevel@tonic-gate static int 7407c478bd9Sstevel@tonic-gate remove_jobs(int argc, char **argv, char *login) 7417c478bd9Sstevel@tonic-gate /* remove jobs that are specified */ 7427c478bd9Sstevel@tonic-gate { 7437c478bd9Sstevel@tonic-gate int i, r; 7447c478bd9Sstevel@tonic-gate int error = 0; 7457c478bd9Sstevel@tonic-gate struct stat buf; 7467c478bd9Sstevel@tonic-gate struct passwd *pw; 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate pw = getpwuid(user); 7497c478bd9Sstevel@tonic-gate if (pw == NULL) { 7507c478bd9Sstevel@tonic-gate atabort("Invalid user.\n"); 7517c478bd9Sstevel@tonic-gate } 7527c478bd9Sstevel@tonic-gate 7537c478bd9Sstevel@tonic-gate if (argc == 0) 7547c478bd9Sstevel@tonic-gate usage(); 7557c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == -1) 7567c478bd9Sstevel@tonic-gate atabort(CANTCD); 7577c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) 7587c478bd9Sstevel@tonic-gate if (strchr(argv[i], '/') != NULL) { 7597c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: not a valid job-id\n", 7607c478bd9Sstevel@tonic-gate argv[i]); 7617c478bd9Sstevel@tonic-gate } else if (stat(argv[i], &buf)) { 7627c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: ", argv[i]); 7637c478bd9Sstevel@tonic-gate perror(""); 7647c478bd9Sstevel@tonic-gate } else if ((user != buf.st_uid) && 765d1419d5aSNobutomo Nakano (!cron_admin(pw->pw_name))) { 7667c478bd9Sstevel@tonic-gate fprintf(stderr, "at: you don't own %s\n", 7677c478bd9Sstevel@tonic-gate argv[i]); 7687c478bd9Sstevel@tonic-gate error = 1; 7697c478bd9Sstevel@tonic-gate } else { 770d1419d5aSNobutomo Nakano if (cron_admin(pw->pw_name)) { 7717c478bd9Sstevel@tonic-gate login = getuser((uid_t)buf.st_uid); 7727c478bd9Sstevel@tonic-gate if (login == NULL) { 7737c478bd9Sstevel@tonic-gate if (per_errno == 2) 7747c478bd9Sstevel@tonic-gate atabort(BADSHELL); 7757c478bd9Sstevel@tonic-gate else 7767c478bd9Sstevel@tonic-gate atabort(INVALIDUSER); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate } 7797c478bd9Sstevel@tonic-gate cron_sendmsg(DELETE, login, argv[i], AT); 7807c478bd9Sstevel@tonic-gate r = unlink(argv[i]); 7817c478bd9Sstevel@tonic-gate audit_at_delete(argv[i], ATDIR, r); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate return (error); 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate static int 7897c478bd9Sstevel@tonic-gate list_jobs(int argc, char **argv, int qflag, int queue) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate DIR *dir; 7927c478bd9Sstevel@tonic-gate int i; 7937c478bd9Sstevel@tonic-gate int error = 0; 7947c478bd9Sstevel@tonic-gate char *patdir, *atdir, *ptr; 7957c478bd9Sstevel@tonic-gate char timebuf[80]; 7967c478bd9Sstevel@tonic-gate time_t t; 7977c478bd9Sstevel@tonic-gate struct stat buf, st1, st2; 7987c478bd9Sstevel@tonic-gate struct dirent *dentry; 7997c478bd9Sstevel@tonic-gate struct passwd *pw; 8007c478bd9Sstevel@tonic-gate unsigned int atdirlen; 8017c478bd9Sstevel@tonic-gate int r; 8027c478bd9Sstevel@tonic-gate struct passwd *pwd, pwds; 8037c478bd9Sstevel@tonic-gate char buf_pwd[1024]; 8047c478bd9Sstevel@tonic-gate char job_file[PATH_MAX]; 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate pwd = getpwuid_r(user, &pwds, buf_pwd, sizeof (buf_pwd)); 8077c478bd9Sstevel@tonic-gate if (pwd == NULL) { 8087c478bd9Sstevel@tonic-gate atabort("Invalid user.\n"); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate 8117c478bd9Sstevel@tonic-gate /* list jobs for user */ 8127c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == -1) 8137c478bd9Sstevel@tonic-gate atabort(CANTCD); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate atdirlen = strlen(ATDIR); 8167c478bd9Sstevel@tonic-gate atdir = xmalloc(atdirlen + 1); 8177c478bd9Sstevel@tonic-gate strcpy(atdir, ATDIR); 8187c478bd9Sstevel@tonic-gate patdir = strrchr(atdir, '/'); 8197c478bd9Sstevel@tonic-gate *patdir = '\0'; 8207c478bd9Sstevel@tonic-gate if (argc == 0) { 8217c478bd9Sstevel@tonic-gate /* list all jobs for a user */ 8227c478bd9Sstevel@tonic-gate if (stat(ATDIR, &st1) != 0 || stat(atdir, &st2) != 0) 8237c478bd9Sstevel@tonic-gate atabort("Can not get status of spooling" 8247c478bd9Sstevel@tonic-gate "directory for at"); 8257c478bd9Sstevel@tonic-gate if ((dir = opendir(ATDIR)) == NULL) 8267c478bd9Sstevel@tonic-gate atabort(NOOPENDIR); 8277c478bd9Sstevel@tonic-gate while (1) { 8287c478bd9Sstevel@tonic-gate if ((dentry = readdir(dir)) == NULL) 8297c478bd9Sstevel@tonic-gate break; 8307c478bd9Sstevel@tonic-gate if ((dentry->d_ino == st1.st_ino) || 8317c478bd9Sstevel@tonic-gate (dentry->d_ino == st2.st_ino)) 8327c478bd9Sstevel@tonic-gate continue; 8337c478bd9Sstevel@tonic-gate if ((r = audit_cron_is_anc_name(dentry->d_name)) == 1) 8347c478bd9Sstevel@tonic-gate continue; 8357c478bd9Sstevel@tonic-gate if (stat(dentry->d_name, &buf)) { 8367c478bd9Sstevel@tonic-gate unlink(dentry->d_name); 8377c478bd9Sstevel@tonic-gate audit_cron_delete_anc_file(dentry->d_name, 8387c478bd9Sstevel@tonic-gate NULL); 8397c478bd9Sstevel@tonic-gate continue; 8407c478bd9Sstevel@tonic-gate } 841d1419d5aSNobutomo Nakano if ((!cron_admin(pwd->pw_name)) && 8427c478bd9Sstevel@tonic-gate (buf.st_uid != user)) 8437c478bd9Sstevel@tonic-gate continue; 8447c478bd9Sstevel@tonic-gate ptr = dentry->d_name; 8457c478bd9Sstevel@tonic-gate if (((t = num(&ptr)) == 0) || (*ptr != '.')) 8467c478bd9Sstevel@tonic-gate continue; 8477c478bd9Sstevel@tonic-gate strcpy(job_file, patdir); 8487c478bd9Sstevel@tonic-gate strcat(job_file, dentry->d_name); 8497c478bd9Sstevel@tonic-gate if (pflag && not_this_project(job_file)) 8507c478bd9Sstevel@tonic-gate continue; 8517c478bd9Sstevel@tonic-gate ascftime(timebuf, FORMAT, localtime(&t)); 852d1419d5aSNobutomo Nakano if ((cron_admin(pwd->pw_name)) && 8537c478bd9Sstevel@tonic-gate ((pw = getpwuid(buf.st_uid)) != NULL)) { 8547c478bd9Sstevel@tonic-gate if (!qflag || (qflag && 8557c478bd9Sstevel@tonic-gate check_queue(ptr, queue))) 8567c478bd9Sstevel@tonic-gate printf("user = %s\t%s\t%s\n", 8577c478bd9Sstevel@tonic-gate pw->pw_name, dentry->d_name, 8587c478bd9Sstevel@tonic-gate timebuf); 8597c478bd9Sstevel@tonic-gate } else 8607c478bd9Sstevel@tonic-gate if (!qflag || (qflag && 8617c478bd9Sstevel@tonic-gate check_queue(ptr, queue))) 8627c478bd9Sstevel@tonic-gate printf("%s\t%s\n", 8637c478bd9Sstevel@tonic-gate dentry->d_name, timebuf); 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate (void) closedir(dir); 8667c478bd9Sstevel@tonic-gate } else /* list particular jobs for user */ 8677c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 8687c478bd9Sstevel@tonic-gate ptr = argv[i]; 8697c478bd9Sstevel@tonic-gate strlcpy(job_file, patdir, PATH_MAX); 8707c478bd9Sstevel@tonic-gate strlcat(job_file, ptr, PATH_MAX); 8717c478bd9Sstevel@tonic-gate if (((t = num(&ptr)) == 0) || (*ptr != '.')) { 8727c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 8737c478bd9Sstevel@tonic-gate "at: invalid job name %s\n"), argv[i]); 8747c478bd9Sstevel@tonic-gate error = 1; 8757c478bd9Sstevel@tonic-gate } else if (stat(argv[i], &buf)) { 8767c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: ", argv[i]); 8777c478bd9Sstevel@tonic-gate perror(""); 8787c478bd9Sstevel@tonic-gate error = 1; 8797c478bd9Sstevel@tonic-gate } else if ((user != buf.st_uid) && 880d1419d5aSNobutomo Nakano (!cron_admin(pwd->pw_name))) { 8817c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 8827c478bd9Sstevel@tonic-gate "at: you don't own %s\n"), argv[i]); 8837c478bd9Sstevel@tonic-gate error = 1; 8847c478bd9Sstevel@tonic-gate } else if (pflag && not_this_project(job_file)) { 8857c478bd9Sstevel@tonic-gate continue; 8867c478bd9Sstevel@tonic-gate } else { 8877c478bd9Sstevel@tonic-gate if (!qflag || (qflag && 8887c478bd9Sstevel@tonic-gate check_queue(ptr, queue))) { 8897c478bd9Sstevel@tonic-gate ascftime(timebuf, FORMAT, 8907c478bd9Sstevel@tonic-gate localtime(&t)); 8917c478bd9Sstevel@tonic-gate printf("%s\t%s\n", argv[i], timebuf); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate return (error); 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate * open the command file and read the project id line 9007c478bd9Sstevel@tonic-gate * compare to the project number provided via -p on the command line 9017c478bd9Sstevel@tonic-gate * return 0 if they match, 1 if they don't match or an error occurs. 9027c478bd9Sstevel@tonic-gate */ 9037c478bd9Sstevel@tonic-gate #define SKIPCOUNT 3 /* lines to skip to get to project line in file */ 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate static int 9067c478bd9Sstevel@tonic-gate not_this_project(char *filename) 9077c478bd9Sstevel@tonic-gate { 9087c478bd9Sstevel@tonic-gate FILE *fp; 9097c478bd9Sstevel@tonic-gate projid_t sproj; 9107c478bd9Sstevel@tonic-gate int i; 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) 9137c478bd9Sstevel@tonic-gate return (1); 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate for (i = 0; i < SKIPCOUNT; i++) 9167c478bd9Sstevel@tonic-gate fscanf(fp, "%*[^\n]\n"); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate fscanf(fp, ": project: %d\n", &sproj); 9197c478bd9Sstevel@tonic-gate fclose(fp); 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate return (sproj == project ? 0 : 1); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate static int 9257c478bd9Sstevel@tonic-gate check_queue(char *name, int queue) 9267c478bd9Sstevel@tonic-gate { 9277c478bd9Sstevel@tonic-gate if ((name[strlen(name) - 1] - 'a') == queue) 9287c478bd9Sstevel@tonic-gate return (1); 9297c478bd9Sstevel@tonic-gate else 9307c478bd9Sstevel@tonic-gate return (0); 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate static time_t 9347c478bd9Sstevel@tonic-gate parse_time(char *t) 9357c478bd9Sstevel@tonic-gate { 9367c478bd9Sstevel@tonic-gate int century = 0; 9377c478bd9Sstevel@tonic-gate int seconds = 0; 9387c478bd9Sstevel@tonic-gate char *p; 9397c478bd9Sstevel@tonic-gate time_t when = 0; 9407c478bd9Sstevel@tonic-gate struct tm tm; 9417c478bd9Sstevel@tonic-gate 9427c478bd9Sstevel@tonic-gate /* 9437c478bd9Sstevel@tonic-gate * time in the following format (defined by the touch(1) spec): 9447c478bd9Sstevel@tonic-gate * [[CC]YY]MMDDhhmm[.SS] 9457c478bd9Sstevel@tonic-gate */ 9467c478bd9Sstevel@tonic-gate if ((p = strchr(t, '.')) != NULL) { 9477c478bd9Sstevel@tonic-gate if (strchr(p+1, '.') != NULL) 9487c478bd9Sstevel@tonic-gate atabort(BADTIME); 9497c478bd9Sstevel@tonic-gate seconds = atoi_for2(p+1); 9507c478bd9Sstevel@tonic-gate *p = '\0'; 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate memset(&tm, 0, sizeof (struct tm)); 9547c478bd9Sstevel@tonic-gate when = time(0); 9557c478bd9Sstevel@tonic-gate tm.tm_year = localtime(&when)->tm_year; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate switch (strlen(t)) { 9587c478bd9Sstevel@tonic-gate case 12: /* CCYYMMDDhhmm */ 9597c478bd9Sstevel@tonic-gate century = atoi_for2(t); 9607c478bd9Sstevel@tonic-gate t += 2; 9617c478bd9Sstevel@tonic-gate case 10: /* YYMMDDhhmm */ 9627c478bd9Sstevel@tonic-gate tm.tm_year = atoi_for2(t); 9637c478bd9Sstevel@tonic-gate t += 2; 9647c478bd9Sstevel@tonic-gate if (century == 0) { 9657c478bd9Sstevel@tonic-gate if (tm.tm_year < 69) 9667c478bd9Sstevel@tonic-gate tm.tm_year += 100; 9677c478bd9Sstevel@tonic-gate } else 9687c478bd9Sstevel@tonic-gate tm.tm_year += (century - 19) * 100; 9697c478bd9Sstevel@tonic-gate case 8: /* MMDDhhmm */ 9707c478bd9Sstevel@tonic-gate tm.tm_mon = atoi_for2(t) - 1; 9717c478bd9Sstevel@tonic-gate t += 2; 9727c478bd9Sstevel@tonic-gate tm.tm_mday = atoi_for2(t); 9737c478bd9Sstevel@tonic-gate t += 2; 9747c478bd9Sstevel@tonic-gate tm.tm_hour = atoi_for2(t); 9757c478bd9Sstevel@tonic-gate t += 2; 9767c478bd9Sstevel@tonic-gate tm.tm_min = atoi_for2(t); 9777c478bd9Sstevel@tonic-gate t += 2; 9787c478bd9Sstevel@tonic-gate tm.tm_sec = seconds; 9797c478bd9Sstevel@tonic-gate break; 9807c478bd9Sstevel@tonic-gate default: 9817c478bd9Sstevel@tonic-gate atabort(BADTIME); 9827c478bd9Sstevel@tonic-gate } 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate if ((when = mktime(&tm)) == -1) 9857c478bd9Sstevel@tonic-gate atabort(BADTIME); 9867c478bd9Sstevel@tonic-gate if (tm.tm_isdst) 9877c478bd9Sstevel@tonic-gate when -= (timezone-altzone); 9887c478bd9Sstevel@tonic-gate return (when); 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate static int 9927c478bd9Sstevel@tonic-gate atoi_for2(char *p) { 9937c478bd9Sstevel@tonic-gate int value; 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate value = (*p - '0') * 10 + *(p+1) - '0'; 9967c478bd9Sstevel@tonic-gate if ((value < 0) || (value > 99)) 9977c478bd9Sstevel@tonic-gate atabort(BADTIME); 9987c478bd9Sstevel@tonic-gate return (value); 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate static void 10027c478bd9Sstevel@tonic-gate usage(void) 10037c478bd9Sstevel@tonic-gate { 10047c478bd9Sstevel@tonic-gate fprintf(stderr, USAGE); 10057c478bd9Sstevel@tonic-gate exit(1); 10067c478bd9Sstevel@tonic-gate } 1007