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