From 5b57d28ffb6e1ef86b50f7d05d977826eae89bfe Mon Sep 17 00:00:00 2001 From: Kiyoshi Aman Date: Fri, 1 Feb 2019 22:55:37 +0000 Subject: initial population --- usr.bin/at/at.1 | 339 ++++++++++++++++++++++ usr.bin/at/at.c | 758 +++++++++++++++++++++++++++++++++++++++++++++++++ usr.bin/at/at.h | 43 +++ usr.bin/at/panic.c | 110 +++++++ usr.bin/at/panic.h | 37 +++ usr.bin/at/parsetime.c | 652 ++++++++++++++++++++++++++++++++++++++++++ usr.bin/at/parsetime.h | 35 +++ usr.bin/at/pathnames.h | 51 ++++ usr.bin/at/perm.c | 118 ++++++++ usr.bin/at/perm.h | 33 +++ usr.bin/at/privs.c | 104 +++++++ usr.bin/at/privs.h | 76 +++++ usr.bin/at/stime.c | 116 ++++++++ usr.bin/at/stime.h | 53 ++++ 14 files changed, 2525 insertions(+) create mode 100644 usr.bin/at/at.1 create mode 100644 usr.bin/at/at.c create mode 100644 usr.bin/at/at.h create mode 100644 usr.bin/at/panic.c create mode 100644 usr.bin/at/panic.h create mode 100644 usr.bin/at/parsetime.c create mode 100644 usr.bin/at/parsetime.h create mode 100644 usr.bin/at/pathnames.h create mode 100644 usr.bin/at/perm.c create mode 100644 usr.bin/at/perm.h create mode 100644 usr.bin/at/privs.c create mode 100644 usr.bin/at/privs.h create mode 100644 usr.bin/at/stime.c create mode 100644 usr.bin/at/stime.h (limited to 'usr.bin/at') diff --git a/usr.bin/at/at.1 b/usr.bin/at/at.1 new file mode 100644 index 0000000..cdd97e1 --- /dev/null +++ b/usr.bin/at/at.1 @@ -0,0 +1,339 @@ +.\" $NetBSD: at.1,v 1.29 2016/11/18 12:16:48 abhinav Exp $ +.\" $OpenBSD: at.1,v 1.6 1998/06/05 00:47:46 deraadt Exp $ +.\" $FreeBSD: at.man,v 1.6 1997/02/22 19:54:05 peter Exp $ +.Dd March 10, 2008 +.Dt AT 1 +.Os +.Sh NAME +.Nm at , +.Nm batch , +.Nm atq , +.Nm atrm +.Nd queue, examine or delete jobs for later execution +.Sh SYNOPSIS +.Nm at +.Op Fl bdlmrVv +.Op Fl f Ar file +.Op Fl q Ar queue +.Fl t Ar [[CC]YY]MMDDhhmm[.SS] +.Nm +.Op Fl bdlmrVv +.Op Fl f Ar file +.Op Fl q Ar queue +.Ar time +.Nm +.Op Fl V +.Fl c Ar job Op Ar job ... +.Nm atq +.Op Fl Vv +.Op Fl q Ar queue +.Nm atrm +.Op Fl V +.Ar job +.Op Ar job ... +.Nm batch +.Op Fl mVv +.Op Fl f Ar file +.Op Fl q Ar queue +.Op Fl t Ar [[CC]YY]MMDDhhmm[.SS] +.Nm batch +.Op Fl mVv +.Op Fl f Ar file +.Op Fl q Ar queue +.Op Ar time +.Sh DESCRIPTION +.Nm +and +.Nm batch +read commands from standard input or a specified file which +are to be executed at a later time, using +.Xr sh 1 . +.Bl -tag -width indent +.It Nm at +Executes commands at a specified time. +.It Nm atq +Lists the user's pending jobs, unless the user is the superuser. +In that case, everybody's jobs are listed. +.It Nm atrm +Deletes jobs. +.It Nm batch +Executes commands when system load levels permit. +In other words, when +the load average drops below 1.5, or the value specified in the invocation of +.Xr atrun 8 . +.El +.Pp +.Nm +allows some moderately complex +.Ar time +specifications. +It accepts times of the form +.Ar HHMM +or +.Ar HH:MM +to run a job at a specific time of day. +(If that time is already past, the next day is assumed.) +You may also specify +.Sq midnight , +.Sq noon , +or +.Sq teatime +(4pm) +and you can have a time-of-day suffixed with +.Sq AM +or +.Sq PM +for running in the morning or the evening. +You can also say what day the job will be run, +by giving a date in the form +.Ar %month-name day +with an optional +.Ar year , +or giving a date of the form +.Ar MMDDYY +or +.Ar MM/DD/YY +or +.Ar DD.MM.YY . +The specification of a date must follow the specification of +the time of day. +You can also give times like +.Op Nm now +or +.Op Nm now +.Sq + Ar count %time-units , +where the time-units can be +.Sq minutes , +.Sq hours , +.Sq days , +.Sq weeks , +.Sq months , +or +.Sq years +and you can tell +.Nm +to run the job today by suffixing the time with +.Sq today +and to run the job tomorrow by suffixing the time with +.Sq tomorrow . +.Pp +For example, to run a job at 4pm three days from now, you would do +.Dl at 4pm + 3 days , +to run a job at 10:00am on July 31, you would do +.Dl at 10am Jul 31 +and to run a job at 1am tomorrow, you would do +.Dl at 1am tomorrow . +.Pp +Alternatively the time may be specified in a language-neutral fashion +by using the +.Fl t +options. +.Pp +For both +.Nm +and +.Nm batch , +commands are read from standard input or the file specified +with the +.Fl f +option and executed. +The working directory, the environment (except for the variables +.Ev TERM , +.Ev TERMCAP , +.Ev DISPLAY +and +.Ev _ ) +and the +.Ar umask +are retained from the time of invocation. +An +.Nm +or +.Nm batch +command invoked from a +.Xr su 1 +shell will retain the current userid. +The user will be mailed standard error and standard output from his +commands, if any. +Mail will be sent using the command +.Xr sendmail 1 . +If +.Nm +is executed from a +.Xr su 1 +shell, the owner of the login shell will receive the mail. +.Pp +The superuser may use these commands in any case. +For other users, permission to use +.Nm at +is determined by the files +.Pa /var/at/at.allow +and +.Pa /var/at/at.deny . +.Pp +If the file +.Pa /var/at/at.allow +exists, only usernames mentioned in it are allowed to use +.Nm . +.Pp +If +.Pa /var/at/at.allow +does not exist, +.Pa /var/at/at.deny +is checked; every username not mentioned in it is then allowed +to use +.Nm . +.Pp +If neither exists, only the superuser is allowed use of +.Nm . +.Pp +An empty +.Pa /var/at/at.deny +means that every user is allowed use these commands. +This is the default configuration. +.Sh OPTIONS +.Bl -tag -offset indent -width XqXqueueXX +.It Fl b +Is an alias for +.Nm batch . +.It Fl c +Cats the jobs listed on the command line to standard output. +.It Fl d +Is an alias for +.Nm atrm . +.It Fl f Ar file +Reads the job from +.Ar file +rather than standard input. +.It Fl l +Is an alias for +.Nm atq . +.It Fl m +Send mail to the user when the job has completed even if there was no +output. +.It Fl q Ar queue +Uses the specified queue. +A queue designation consists of a single letter. +Valid queue designations +range from +.Sq a +to +.Sq z +and +.Sq A +to +.Sq Z . +The +.Sq c +queue is the default for +.Nm +and the +.Sq E +queue for +.Nm batch . +Queues with higher letters run with increased niceness. +If a job is submitted to a queue designated with an uppercase letter, it +is treated as if it had been submitted to batch at that time. +If +.Nm atq +is given a specific queue, it will only show jobs pending in that queue. +.It Fl r +Is an alias for +.Nm atrm . +.It Fl t +For both +.Nm +and +.Nm batch , +the time may be specified in a language-neutral format consisting of: +.Bl -tag -width Ds -compact -offset indent +.It Ar CC +The first two digits of the year (the century). +.It Ar YY +The second two digits of the year. +If +.Ar YY +is specified, but +.Ar CC +is not, a value for +.Ar YY +between 69 and 99 results in a +.Ar CC +value of 19. +Otherwise, a +.Ar CC +value of 20 is used. +.It Ar MM +The month of the year, from 01 to 12. +.It Ar \&DD +The day of the month, from 01 to 31. +.It Ar hh +The hour of the day, from 00 to 23. +.It Ar mm +The minute of the hour, from 00 to 59. +.It Ar \&SS +The second of the minute, from 00 to 61. +.El +.It Fl V +Prints the version number to standard error. +.It Fl v +For +.Nm atq , +shows completed but not yet deleted jobs in the queue. +Otherwise shows the time the job will be executed. +.El +.Sh FILES +.Bl -tag -width /var/at/.lockfile -compact +.It Pa /var/at/jobs +Directory containing job files +.It Pa /var/at/spool +Directory containing output spool files +.It Pa /var/run/utmp +Login records +.It Pa /var/at/at.allow +Allow permission control +.It Pa /var/at/at.deny +Deny permission control +.It Pa /var/at/.lockfile +Job-creation lock file. +.El +.Sh SEE ALSO +.Xr nice 1 , +.Xr sendmail 1 , +.Xr sh 1 , +.Xr umask 2 , +.Xr atrun 8 , +.Xr cron 8 +.Sh STANDARDS +The +.Nm +and +.Nm batch +utilities conform to +.St -p1003.2-92 . +.Sh AUTHORS +.An -nosplit +.Nm +was mostly written by +.An Thomas Koenig Aq Mt ig25@rz.uni-karlsruhe.de . +The time parsing routines are implemented by +.An David Parsons Aq Mt orc@pell.chi.il.us . +.Sh BUGS +If the file +.Pa /var/run/utmp +is not available or corrupted, or if the user is not logged on at the +time +.Nm +is invoked, the mail is sent to the userid found +in the environment variable +.Ev LOGNAME . +If that is undefined or empty, the current userid is assumed. +.Pp +.Nm +and +.Nm batch +as presently implemented are not suitable when users are competing for +resources. +If this is the case for your site, you might want to consider another +batch system, such as +.Ic nqs . diff --git a/usr.bin/at/at.c b/usr.bin/at/at.c new file mode 100644 index 0000000..621b95d --- /dev/null +++ b/usr.bin/at/at.c @@ -0,0 +1,758 @@ +/* $NetBSD: at.c,v 1.31 2016/03/13 00:32:09 dholland Exp $ */ + +/* + * at.c : Put file into atrun queue + * Copyright (C) 1993, 1994 Thomas Koenig + * + * Atrun & Atq modifications + * Copyright (C) 1993 David Parsons + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* System Headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Local headers */ +#include "at.h" +#include "panic.h" +#include "parsetime.h" +#include "perm.h" +#include "pathnames.h" +#include "stime.h" +#include "privs.h" + +/* Macros */ +#define ALARMC 10 /* Number of seconds to wait for timeout */ + +#define TIMESIZE 50 + +enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */ + +/* File scope variables */ +#ifndef lint +#if 0 +static char rcsid[] = "$OpenBSD: at.c,v 1.15 1998/06/03 16:20:26 deraadt Exp $"; +#else +__RCSID("$NetBSD: at.c,v 1.31 2016/03/13 00:32:09 dholland Exp $"); +#endif +#endif + +const char *no_export[] = {"TERM", "TERMCAP", "DISPLAY", "_"}; +static int send_mail = 0; + +/* External variables */ + +extern char **environ; +bool fcreated = false; +char atfile[FILENAME_MAX]; + +char *atinput = NULL; /* where to get input from */ +unsigned char atqueue = 0; /* which queue to examine for jobs (atq) */ +char atverify = 0; /* verify time instead of queuing job */ + +/* Function declarations */ + +__dead static void sigc (int); +__dead static void alarmc (int); +static char *cwdname (void); +static int nextjob (void); +static void writefile (time_t, unsigned char); +static void list_jobs (void); +static void process_jobs (int, char **, int); + +/* Signal catching functions */ + +/*ARGSUSED*/ +static void +sigc(int signo) +{ + + /* If a signal interrupts us, remove the spool file and exit. */ + if (fcreated) { + privs_enter(); + (void)unlink(atfile); + privs_exit(); + } + (void)raise_default_signal(signo); + exit(EXIT_FAILURE); +} + +/*ARGSUSED*/ +static void +alarmc(int signo) +{ + + /* Time out after some seconds. */ + warnx("File locking timed out"); + sigc(signo); +} + +/* Local functions */ + +static char * +cwdname(void) +{ + + /* + * Read in the current directory; the name will be overwritten on + * subsequent calls. + */ + static char path[MAXPATHLEN]; + + return getcwd(path, sizeof(path)); +} + +static int +nextjob(void) +{ + int jobno; + FILE *fid; + + if ((fid = fopen(_PATH_SEQFILE, "r+")) != NULL) { + if (fscanf(fid, "%5x", &jobno) == 1) { + (void)rewind(fid); + jobno = (1+jobno) % 0xfffff; /* 2^20 jobs enough? */ + (void)fprintf(fid, "%05x\n", jobno); + } else + jobno = EOF; + (void)fclose(fid); + return jobno; + } else if ((fid = fopen(_PATH_SEQFILE, "w")) != NULL) { + (void)fprintf(fid, "%05x\n", jobno = 1); + (void)fclose(fid); + return 1; + } + return EOF; +} + +static void +writefile(time_t runtimer, unsigned char queue) +{ + /* + * This does most of the work if at or batch are invoked for + * writing a job. + */ + int jobno; + char *ap, *ppos; + const char *mailname; + struct passwd *pass_entry; + struct stat statbuf; + int fdes, lockdes, fd2; + FILE *fp, *fpin; + struct sigaction act; + char **atenv; + int ch; + mode_t cmask; + struct flock lock; + + (void)setlocale(LC_TIME, ""); + + /* + * Install the signal handler for SIGINT; terminate after removing the + * spool file if necessary + */ + (void)memset(&act, 0, sizeof(act)); + act.sa_handler = sigc; + (void)sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + (void)sigaction(SIGINT, &act, NULL); + + (void)strlcpy(atfile, _PATH_ATJOBS, sizeof(atfile)); + ppos = atfile + strlen(atfile); + + /* + * Loop over all possible file names for running something at this + * particular time, see if a file is there; the first empty slot at + * any particular time is used. Lock the file _PATH_LOCKFILE first + * to make sure we're alone when doing this. + */ + + privs_enter(); + + if ((lockdes = open(_PATH_LOCKFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0) + perr("Cannot open lockfile " _PATH_LOCKFILE); + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + + act.sa_handler = alarmc; + (void)sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + /* + * Set an alarm so a timeout occurs after ALARMC seconds, in case + * something is seriously broken. + */ + (void)sigaction(SIGALRM, &act, NULL); + (void)alarm(ALARMC); + (void)fcntl(lockdes, F_SETLKW, &lock); + (void)alarm(0); + + if ((jobno = nextjob()) == EOF) + perr("Cannot generate job number"); + + (void)snprintf(ppos, sizeof(atfile) - (ppos - atfile), + "%c%5x%8lx", queue, jobno, (unsigned long) (runtimer/60)); + + for (ap = ppos; *ap != '\0'; ap++) + if (*ap == ' ') + *ap = '0'; + + if (stat(atfile, &statbuf) == -1) + if (errno != ENOENT) + perr("Cannot access " _PATH_ATJOBS); + + /* + * Create the file. The x bit is only going to be set after it has + * been completely written out, to make sure it is not executed in + * the meantime. To make sure they do not get deleted, turn off + * their r bit. Yes, this is a kluge. + */ + cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR); + if ((fdes = open(atfile, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR)) == -1) + perr("Cannot create atjob file"); + + if ((fd2 = dup(fdes)) == -1) + perr("Error in dup() of job file"); + + if (fchown(fd2, real_uid, real_gid) == -1) + perr("Cannot give away file"); + + privs_exit(); + + /* + * We've successfully created the file; let's set the flag so it + * gets removed in case of an interrupt or error. + */ + fcreated = true; + + /* Now we can release the lock, so other people can access it */ + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + lock.l_start = 0; + lock.l_len = 0; + (void)fcntl(lockdes, F_SETLKW, &lock); + (void)close(lockdes); + + if ((fp = fdopen(fdes, "w")) == NULL) + panic("Cannot reopen atjob file"); + + /* + * Get the userid to mail to, first by trying getlogin(), which reads + * /etc/utmp, then from $LOGNAME or $USER, finally from getpwuid(). + */ + mailname = getlogin(); + if (mailname == NULL && (mailname = getenv("LOGNAME")) == NULL) + mailname = getenv("USER"); + + if (mailname == NULL || mailname[0] == '\0' || + strlen(mailname) > LOGIN_NAME_MAX || getpwnam(mailname) == NULL) { + pass_entry = getpwuid(real_uid); + if (pass_entry != NULL) + mailname = pass_entry->pw_name; + } + + if (atinput != NULL) { + fpin = freopen(atinput, "r", stdin); + if (fpin == NULL) + perr("Cannot open input file"); + } + (void)fprintf(fp, + "#!/bin/sh\n" + "# atrun uid=%u gid=%u\n" + "# mail %s %d\n", + real_uid, real_gid, mailname, send_mail); + + /* Write out the umask at the time of invocation */ + (void)fprintf(fp, "umask %o\n", cmask); + + /* + * Write out the environment. Anything that may look like a special + * character to the shell is quoted, except for \n, which is done + * with a pair of "'s. Dont't export the no_export list (such as + * TERM or DISPLAY) because we don't want these. + */ + for (atenv = environ; *atenv != NULL; atenv++) { + int export = 1; + char *eqp; + + eqp = strchr(*atenv, '='); + if (eqp == NULL) + eqp = *atenv; + else { + size_t i; + + for (i = 0; i < __arraycount(no_export); i++) { + export = export && + strncmp(*atenv, no_export[i], + (size_t)(eqp - *atenv)) != 0; + } + eqp++; + } + + if (export) { + (void)fwrite(*atenv, sizeof(char), + (size_t)(eqp - *atenv), fp); + for (ap = eqp; *ap != '\0'; ap++) { + if (*ap == '\n') + (void)fprintf(fp, "\"\n\""); + else { + if (!isalnum((unsigned char)*ap)) { + switch (*ap) { + case '%': case '/': case '{': + case '[': case ']': case '=': + case '}': case '@': case '+': + case '#': case ',': case '.': + case ':': case '-': case '_': + break; + default: + (void)fputc('\\', fp); + break; + } + } + (void)fputc(*ap, fp); + } + } + (void)fputs("; export ", fp); + (void)fwrite(*atenv, sizeof(char), + (size_t)(eqp - *atenv - 1), fp); + (void)fputc('\n', fp); + } + } + /* + * Cd to the directory at the time and write out all the + * commands the user supplies from stdin. + */ + (void)fputs("cd ", fp); + for (ap = cwdname(); *ap != '\0'; ap++) { + if (*ap == '\n') + (void)fprintf(fp, "\"\n\""); + else { + if (*ap != '/' && !isalnum((unsigned char)*ap)) + (void)fputc('\\', fp); + + (void)fputc(*ap, fp); + } + } + /* + * Test cd's exit status: die if the original directory has been + * removed, become unreadable or whatever. + */ + (void)fprintf(fp, + " || {\n" + "\t echo 'Execution directory inaccessible' >&2\n" + "\t exit 1\n" + "}\n"); + + if ((ch = getchar()) == EOF) + panic("Input error"); + + do { + (void)fputc(ch, fp); + } while ((ch = getchar()) != EOF); + + (void)fprintf(fp, "\n"); + if (ferror(fp)) + panic("Output error"); + + if (ferror(stdin)) + panic("Input error"); + + (void)fclose(fp); + + privs_enter(); + + /* + * Set the x bit so that we're ready to start executing + */ + if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + perr("Cannot give away file"); + + privs_exit(); + + (void)close(fd2); + (void)fprintf(stderr, + "Job %d will be executed using /bin/sh\n", jobno); +} + +static void +list_jobs(void) +{ + /* + * List all a user's jobs in the queue, by looping through + * _PATH_ATJOBS, or everybody's if we are root + */ + struct passwd *pw; + DIR *spool; + struct dirent *dirent; + struct stat buf; + struct tm runtime; + unsigned long ctm; + unsigned char queue; + int jobno; + time_t runtimer; + char timestr[TIMESIZE]; + int first = 1; + + privs_enter(); + + if (chdir(_PATH_ATJOBS) == -1) + perr("Cannot change to " _PATH_ATJOBS); + + if ((spool = opendir(".")) == NULL) + perr("Cannot open " _PATH_ATJOBS); + + /* Loop over every file in the directory */ + while ((dirent = readdir(spool)) != NULL) { + if (stat(dirent->d_name, &buf) == -1) + perr("Cannot stat in " _PATH_ATJOBS); + + /* + * See it's a regular file and has its x bit turned on and + * is the user's + */ + if (!S_ISREG(buf.st_mode) + || (buf.st_uid != real_uid && real_uid != 0) + || !(S_IXUSR & buf.st_mode || atverify)) + continue; + + if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) != 3) + continue; + + if (atqueue && queue != atqueue) + continue; + + runtimer = 60 * (time_t)ctm; + runtime = *localtime(&runtimer); +#if 1 + /* + * Provide a consistent date/time format instead of a + * locale-specific one that might have 2 digit years + */ + (void)strftime(timestr, TIMESIZE, "%T %F", &runtime); +#else + (void)strftime(timestr, TIMESIZE, "%X %x", &runtime); +#endif + if (first) { + (void)printf("%-*s %-*s %-*s %s\n", + (int)strlen(timestr), "Date", + LOGIN_NAME_MAX, "Owner", + 7, "Queue", + "Job"); + first = 0; + } + pw = getpwuid(buf.st_uid); + + (void)printf("%s %-*s %c%-*s %d\n", + timestr, + LOGIN_NAME_MAX, pw ? pw->pw_name : "???", + queue, + 6, (S_IXUSR & buf.st_mode) ? "" : "(done)", + jobno); + } + (void)closedir(spool); + privs_exit(); +} + +static void +process_jobs(int argc, char **argv, int what) +{ + /* Delete every argument (job - ID) given */ + int i; + struct stat buf; + DIR *spool; + struct dirent *dirent; + unsigned long ctm; + unsigned char queue; + int jobno; + + privs_enter(); + + if (chdir(_PATH_ATJOBS) == -1) + perr("Cannot change to " _PATH_ATJOBS); + + if ((spool = opendir(".")) == NULL) + perr("Cannot open " _PATH_ATJOBS); + + privs_exit(); + + /* Loop over every file in the directory */ + while((dirent = readdir(spool)) != NULL) { + + privs_enter(); + if (stat(dirent->d_name, &buf) == -1) + perr("Cannot stat in " _PATH_ATJOBS); + privs_exit(); + + if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) !=3) + continue; + + for (i = optind; i < argc; i++) { + if (atoi(argv[i]) == jobno) { + if (buf.st_uid != real_uid && real_uid != 0) + errx(EXIT_FAILURE, + "%s: Not owner", argv[i]); + + switch (what) { + case ATRM: + privs_enter(); + + if (unlink(dirent->d_name) == -1) + perr(dirent->d_name); + + privs_exit(); + break; + + case CAT: { + FILE *fp; + int ch; + + privs_enter(); + + fp = fopen(dirent->d_name, "r"); + + privs_exit(); + + if (!fp) + perr("Cannot open file"); + else { + while((ch = getc(fp)) != EOF) + (void)putchar(ch); + (void)fclose(fp); + } + } + break; + + default: + errx(EXIT_FAILURE, + "Internal error, process_jobs = %d", + what); + break; + } + } + } + } + (void)closedir(spool); +} + +/* Global functions */ + +int +main(int argc, char **argv) +{ + int c; + unsigned char queue = DEFAULT_AT_QUEUE; + char queue_set = 0; + char time_set = 0; + char *pgm; + + int program = AT; /* our default program */ + const char *options = "q:f:t:mvldbrVc"; /* default options for at */ + int disp_version = 0; + time_t timer; + + privs_relinquish(); + + /* Eat any leading paths */ + if ((pgm = strrchr(argv[0], '/')) == NULL) + pgm = argv[0]; + else + pgm++; + + /* find out what this program is supposed to do */ + if (strcmp(pgm, "atq") == 0) { + program = ATQ; + options = "q:vV"; + } else if (strcmp(pgm, "atrm") == 0) { + program = ATRM; + options = "V"; + } else if (strcmp(pgm, "batch") == 0) { + program = BATCH; + options = "f:q:t:mvV"; + } + + /* process whatever options we can process */ + opterr = 1; + while ((c = getopt(argc, argv, options)) != -1) { + switch (c) { + case 'v': /* verify time settings */ + atverify = 1; + break; + + case 'm': /* send mail when job is complete */ + send_mail = 1; + break; + + case 'f': + atinput = optarg; + break; + + case 'q': /* specify queue */ + if (strlen(optarg) > 1) + usage(); + + atqueue = queue = *optarg; + if (!(islower(queue) || isupper(queue))) + usage(); + + queue_set = 1; + break; + case 't': /* touch(1) date format */ + timer = stime(optarg); + time_set = 1; + break; + + case 'd': + case 'r': + if (program != AT) + usage(); + + program = ATRM; + options = "V"; + break; + + case 'l': + if (program != AT) + usage(); + + program = ATQ; + options = "q:vV"; + break; + + case 'b': + if (program != AT) + usage(); + + program = BATCH; + options = "f:q:mvV"; + break; + + case 'V': + disp_version = 1; + break; + + case 'c': + program = CAT; + options = ""; + break; + + default: + usage(); + break; + } + } /* end of options eating */ + + if (disp_version) + (void)fprintf(stderr, "%s version %.1f\n", pgm, AT_VERSION); + + if (!check_permission()) + errx(EXIT_FAILURE, + "You do not have permission to use %s.", pgm); + + /* select our program */ + switch (program) { + case ATQ: + if (optind != argc) + usage(); + list_jobs(); + break; + + case ATRM: + case CAT: + if (optind == argc) + usage(); + process_jobs(argc, argv, program); + break; + + case AT: + if (argc > optind) { + /* -t and timespec argument are mutually exclusive */ + if (time_set) { + usage(); + exit(EXIT_FAILURE); + } else { + timer = parsetime(argc, argv); + time_set = 1; + } + } + + if (atverify) { + struct tm *tm = localtime(&timer); + (void)fprintf(stderr, "%s\n", asctime(tm)); + } + writefile(timer, queue); + break; + + case BATCH: + if (queue_set) + queue = toupper(queue); + else + queue = DEFAULT_BATCH_QUEUE; + + if (argc > optind) { + /* -t and timespec argument are mutually exclusive */ + if (time_set) { + usage(); + exit(EXIT_FAILURE); + } else { + timer = parsetime(argc, argv); + time_set = 1; + } + } else if (!time_set) + timer = time(NULL); + + if (atverify) { + struct tm *tm = localtime(&timer); + (void)fprintf(stderr, "%s\n", asctime(tm)); + } + + writefile(timer, queue); + break; + + default: + panic("Internal error"); + break; + } + return EXIT_SUCCESS; +} diff --git a/usr.bin/at/at.h b/usr.bin/at/at.h new file mode 100644 index 0000000..64a4a53 --- /dev/null +++ b/usr.bin/at/at.h @@ -0,0 +1,43 @@ +/* $NetBSD: at.h,v 1.5 2008/04/05 16:26:57 christos Exp $ */ + +/* + * at.h - header for at(1) + * Copyright (C) 1993 Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: $OpenBSD: at.h,v 1.3 1997/03/01 23:40:09 millert Exp $ + */ + +#ifndef _AT_H_ +#define _AT_H_ + +extern bool fcreated; +extern char atfile[]; +extern char atverify; + +#define AT_MAXJOBS 255 /* max jobs outstanding per user */ +#define AT_VERSION 2.9 /* our version number */ + +#define DEFAULT_BATCH_QUEUE 'E' +#define DEFAULT_AT_QUEUE 'c' + +#endif /* _AT_H_ */ diff --git a/usr.bin/at/panic.c b/usr.bin/at/panic.c new file mode 100644 index 0000000..b0b09ca --- /dev/null +++ b/usr.bin/at/panic.c @@ -0,0 +1,110 @@ +/* $NetBSD: panic.c,v 1.14 2016/03/13 00:32:09 dholland Exp $ */ + +/* + * panic.c - terminate fast in case of error + * Copyright (c) 1993 by Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* System Headers */ + +#include +#include +#include +#include +#include +#include + +/* Local headers */ + +#include "panic.h" +#include "at.h" +#include "privs.h" + +/* File scope variables */ + +#ifndef lint +#if 0 +static char rcsid[] = "$OpenBSD: panic.c,v 1.4 1997/03/01 23:40:09 millert Exp $"; +#else +__RCSID("$NetBSD: panic.c,v 1.14 2016/03/13 00:32:09 dholland Exp $"); +#endif +#endif + +/* Global functions */ + +__dead +void +panic(const char *a) +{ + + /* + * Something fatal has happened, print error message and exit. + */ + if (fcreated) { + privs_enter(); + (void)unlink(atfile); + privs_exit(); + } + errx(EXIT_FAILURE, "%s", a); +} + +__dead +void +perr(const char *a) +{ + + /* + * Some operating system error; print error message and exit. + */ + perror(a); + if (fcreated) { + privs_enter(); + (void)unlink(atfile); + privs_exit(); + } + exit(EXIT_FAILURE); +} + +__dead +void +privs_fail(const char *msg) +{ + perr(msg); +} + +__dead +void +usage(void) +{ + + /* Print usage and exit. */ + (void)fprintf(stderr, + "usage: at [-bdlmrVv] [-f file] [-q queue] -t [[CC]YY]MMDDhhmm[.SS]\n" + " at [-bdlmrVv] [-f file] [-q queue] time\n" + " at [-V] -c job [job ...]\n" + " atq [-Vv] [-q queue]\n" + " atrm [-V] job [job ...]\n" + " batch [-mVv] [-f file] [-q queue] [-t [[CC]YY]MMDDhhmm[.SS]]\n" + " batch [-mVv] [-f file] [-q queue] [time]\n"); + exit(EXIT_FAILURE); +} diff --git a/usr.bin/at/panic.h b/usr.bin/at/panic.h new file mode 100644 index 0000000..3f470fe --- /dev/null +++ b/usr.bin/at/panic.h @@ -0,0 +1,37 @@ +/* $NetBSD: panic.h,v 1.5 2008/04/05 16:26:57 christos Exp $ */ + +/* + * panic.h - header for at(1) + * Copyright (c) 1993 Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: $OpenBSD: panic.h,v 1.3 1997/03/01 23:40:10 millert Exp $ + */ + +#ifndef _PANIC_H_ +#define _PANIC_H_ + +void panic(const char *) __dead; +void perr(const char *) __dead; +void usage(void) __dead; + +#endif /* _PANIC_H_ */ diff --git a/usr.bin/at/parsetime.c b/usr.bin/at/parsetime.c new file mode 100644 index 0000000..5b1cc15 --- /dev/null +++ b/usr.bin/at/parsetime.c @@ -0,0 +1,652 @@ +/* $NetBSD: parsetime.c,v 1.19 2009/01/18 01:02:31 lukem Exp $ */ + +/* + * parsetime.c - parse time for at(1) + * Copyright (C) 1993, 1994 Thomas Koenig + * + * modifications for english-language times + * Copyright (C) 1993 David Parsons + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * at [NOW] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS + * /NUMBER [DOT NUMBER] [AM|PM]\ /[MONTH NUMBER [NUMBER]] \ + * |NOON | |[TOMORROW] | + * |MIDNIGHT | |[DAY OF WEEK] | + * \TEATIME / |NUMBER [SLASH NUMBER [SLASH NUMBER]]| + * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/ + */ + +/* System Headers */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Local headers */ + +#include "at.h" +#include "panic.h" +#include "parsetime.h" +#include "stime.h" + +/* Structures and unions */ + +typedef enum { /* symbols */ + MIDNIGHT, NOON, TEATIME, + PM, AM, TOMORROW, TODAY, NOW, + MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS, + NUMBER, PLUS, DOT, SLASH, ID, JUNK, + JAN, FEB, MAR, APR, MAY, JUN, + JUL, AUG, SEP, OCT, NOV, DEC, + SUN, MON, TUE, WED, THU, FRI, SAT, + TOKEOF /* EOF marker */ +} tokid_t; + +/* + * parse translation table - table driven parsers can be your FRIEND! + */ +static const struct { + const char *name; /* token name */ + tokid_t value; /* token id */ + bool plural; /* is this plural? */ +} Specials[] = { + {"midnight", MIDNIGHT, false}, /* 00:00:00 of today or tomorrow */ + {"noon", NOON, false}, /* 12:00:00 of today or tomorrow */ + {"teatime", TEATIME, false}, /* 16:00:00 of today or tomorrow */ + {"am", AM, false}, /* morning times for 0-12 clock */ + {"pm", PM, false}, /* evening times for 0-12 clock */ + {"tomorrow", TOMORROW, false}, /* execute 24 hours from time */ + {"today", TODAY, false}, /* execute today - don't advance time */ + {"now", NOW, false}, /* opt prefix for PLUS */ + + {"minute", MINUTES, false}, /* minutes multiplier */ + {"min", MINUTES, false}, + {"m", MINUTES, false}, + {"minutes", MINUTES, true}, /* (pluralized) */ + {"hour", HOURS, false}, /* hours ... */ + {"hr", HOURS, false}, /* abbreviated */ + {"h", HOURS, false}, + {"hours", HOURS, true}, /* (pluralized) */ + {"day", DAYS, false}, /* days ... */ + {"d", DAYS, false}, + {"days", DAYS, true}, /* (pluralized) */ + {"week", WEEKS, false}, /* week ... */ + {"w", WEEKS, false}, + {"weeks", WEEKS, true}, /* (pluralized) */ + { "month", MONTHS, 0 }, /* month ... */ + { "months", MONTHS, 1 }, /* (pluralized) */ + { "year", YEARS, 0 }, /* year ... */ + { "years", YEARS, 1 }, /* (pluralized) */ + {"jan", JAN, false}, + {"feb", FEB, false}, + {"mar", MAR, false}, + {"apr", APR, false}, + {"may", MAY, false}, + {"jun", JUN, false}, + {"jul", JUL, false}, + {"aug", AUG, false}, + {"sep", SEP, false}, + {"oct", OCT, false}, + {"nov", NOV, false}, + {"dec", DEC, false}, + {"january", JAN, false}, + {"february", FEB, false}, + {"march", MAR, false}, + {"april", APR, false}, + {"may", MAY, false}, + {"june", JUN, false}, + {"july", JUL, false}, + {"august", AUG, false}, + {"september", SEP, false}, + {"october", OCT, false}, + {"november", NOV, false}, + {"december", DEC, false}, + {"sunday", SUN, false}, + {"sun", SUN, false}, + {"monday", MON, false}, + {"mon", MON, false}, + {"tuesday", TUE, false}, + {"tue", TUE, false}, + {"wednesday", WED, false}, + {"wed", WED, false}, + {"thursday", THU, false}, + {"thu", THU, false}, + {"friday", FRI, false}, + {"fri", FRI, false}, + {"saturday", SAT, false}, + {"sat", SAT, false} +}; + +/* File scope variables */ + +static char **scp; /* scanner - pointer at arglist */ +static char scc; /* scanner - count of remaining arguments */ +static char *sct; /* scanner - next char pointer in current argument */ +static bool need; /* scanner - need to advance to next argument */ + +static char *sc_token; /* scanner - token buffer */ +static size_t sc_len; /* scanner - length of token buffer */ +static tokid_t sc_tokid;/* scanner - token id */ +static bool sc_tokplur; /* scanner - is token plural? */ + +#ifndef lint +#if 0 +static char rcsid[] = "$OpenBSD: parsetime.c,v 1.4 1997/03/01 23:40:10 millert Exp $"; +#else +__RCSID("$NetBSD: parsetime.c,v 1.19 2009/01/18 01:02:31 lukem Exp $"); +#endif +#endif + +/* Local functions */ +static void assign_date(struct tm *, int, int, int); +static void expect(tokid_t); +static void init_scanner(int, char **); +static void month(struct tm *); +static tokid_t parse_token(char *); +static void plonk(tokid_t) __dead; +static void plus(struct tm *); +static void tod(struct tm *); +static tokid_t token(void); + +/* + * parse a token, checking if it's something special to us + */ +static tokid_t +parse_token(char *arg) +{ + size_t i; + + for (i=0; i < __arraycount(Specials); i++) { + if (strcasecmp(Specials[i].name, arg) == 0) { + sc_tokplur = Specials[i].plural; + return sc_tokid = Specials[i].value; + } + } + + /* not special - must be some random id */ + return ID; +} + +/* + * init_scanner() sets up the scanner to eat arguments + */ +static void +init_scanner(int argc, char **argv) +{ + + scp = argv; + scc = argc; + need = true; + sc_len = 1; + while (argc-- > 0) + sc_len += strlen(*argv++); + + if ((sc_token = malloc(sc_len)) == NULL) + panic("Insufficient virtual memory"); +} + +/* + * token() fetches a token from the input stream + */ +static tokid_t +token(void) +{ + int idx; + + for(;;) { + (void)memset(sc_token, 0, sc_len); + sc_tokid = TOKEOF; + sc_tokplur = false; + idx = 0; + + /* + * if we need to read another argument, walk along the + * argument list; when we fall off the arglist, we'll + * just return TOKEOF forever + */ + if (need) { + if (scc < 1) + return sc_tokid; + sct = *scp; + scp++; + scc--; + need = false; + } + /* + * eat whitespace now - if we walk off the end of the argument, + * we'll continue, which puts us up at the top of the while loop + * to fetch the next argument in + */ + while (isspace((unsigned char)*sct)) + ++sct; + if (!*sct) { + need = true; + continue; + } + + /* + * preserve the first character of the new token + */ + sc_token[0] = *sct++; + + /* + * then see what it is + */ + if (isdigit((unsigned char)sc_token[0])) { + while (isdigit((unsigned char)*sct)) + sc_token[++idx] = *sct++; + sc_token[++idx] = 0; + return sc_tokid = NUMBER; + } else if (isalpha((unsigned char)sc_token[0])) { + while (isalpha((unsigned char)*sct)) + sc_token[++idx] = *sct++; + sc_token[++idx] = 0; + return parse_token(sc_token); + } + else if (sc_token[0] == ':' || sc_token[0] == '.') + return sc_tokid = DOT; + else if (sc_token[0] == '+') + return sc_tokid = PLUS; + else if (sc_token[0] == '/') + return sc_tokid = SLASH; + else + return sc_tokid = JUNK; + } +} + +/* + * plonk() gives an appropriate error message if a token is incorrect + */ +__dead +static void +plonk(tokid_t tok) +{ + + panic(tok == TOKEOF ? "incomplete time" : "garbled time"); +} + +/* + * expect() gets a token and dies most horribly if it's not the token we want + */ +static void +expect(tokid_t desired) +{ + + if (token() != desired) + plonk(sc_tokid); /* and we die here... */ +} + +/* + * plus() parses a now + time + * + * at [NOW] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS] + * + */ +static void +plus(struct tm *tm) +{ + int delay; + int expectplur; + + expect(NUMBER); + + delay = atoi(sc_token); + expectplur = delay != 1; + + switch (token()) { + case YEARS: + tm->tm_year += delay; + break; + case MONTHS: + tm->tm_mon += delay; + break; + case WEEKS: + delay *= 7; + /*FALLTHROUGH*/ + case DAYS: + tm->tm_mday += delay; + break; + case HOURS: + tm->tm_hour += delay; + break; + case MINUTES: + tm->tm_min += delay; + break; + default: + plonk(sc_tokid); + break; + } + + if (expectplur != sc_tokplur) + warnx("pluralization is wrong"); + + tm->tm_isdst = -1; + if (mktime(tm) == -1) + plonk(sc_tokid); +} + +/* + * tod() computes the time of day + * [NUMBER [DOT NUMBER] [AM|PM]] + */ +static void +tod(struct tm *tm) +{ + int hour, minute; + size_t tlen; + + minute = 0; + hour = atoi(sc_token); + tlen = strlen(sc_token); + + /* + * first pick out the time of day - if it's 4 digits, we assume + * a HHMM time, otherwise it's HH DOT MM time + */ + if (token() == DOT) { + expect(NUMBER); + minute = atoi(sc_token); + (void)token(); + } else if (tlen == 4) { + minute = hour % 100; + hour = hour / 100; + } + + if (minute > 59) + panic("garbled time"); + + /* + * check if an AM or PM specifier was given + */ + if (sc_tokid == AM || sc_tokid == PM) { + if (hour > 12) + panic("garbled time"); + + if (sc_tokid == PM) { + if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */ + hour += 12; + } else { + if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */ + hour = 0; + } + (void)token(); + } else if (hour > 23) + panic("garbled time"); + + /* + * if we specify an absolute time, we don't want to bump the day even + * if we've gone past that time - but if we're specifying a time plus + * a relative offset, it's okay to bump things + */ + if ((sc_tokid == TOKEOF || sc_tokid == PLUS) && tm->tm_hour > hour) { + tm->tm_mday++; + tm->tm_wday++; + } + + tm->tm_hour = hour; + tm->tm_min = minute; +} + +/* + * assign_date() assigns a date, wrapping to next year if needed. + * Accept years in 4-digit, 2-digit, or current year (-1). + */ +static void +assign_date(struct tm *tm, int mday, int mon, int year) +{ + + if (year > 99) { /* four digit year */ + if (year >= TM_YEAR_BASE) + tm->tm_year = year - TM_YEAR_BASE; + else + panic("garbled time"); + } + else if (year >= 0) { /* two digit year */ + tm->tm_year = conv_2dig_year(year) - TM_YEAR_BASE; + } + else if (year == -1) { /* year not given (use default in tm) */ + /* allow for 1 year range from current date */ + if (tm->tm_mon > mon || + (tm->tm_mon == mon && tm->tm_mday > mday)) + tm->tm_year++; + } + else + panic("invalid year"); + + tm->tm_mday = mday; + tm->tm_mon = mon; +} + +/* + * month() picks apart a month specification + * + * /[ NUMBER [NUMBER]] \ + * |[TOMORROW] | + * |[DAY OF WEEK] | + * |NUMBER [SLASH NUMBER [SLASH NUMBER]]| + * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/ + */ +static void +month(struct tm *tm) +{ + int year; + int mday, wday, mon; + size_t tlen; + + year = -1; + mday = 0; + switch (sc_tokid) { + case PLUS: + plus(tm); + break; + + case TOMORROW: + /* do something tomorrow */ + tm->tm_mday++; + tm->tm_wday++; + /*FALLTHROUGH*/ + case TODAY: + /* force ourselves to stay in today - no further processing */ + (void)token(); + break; + + case JAN: case FEB: case MAR: case APR: case MAY: case JUN: + case JUL: case AUG: case SEP: case OCT: case NOV: case DEC: + /* + * do month mday [year] + */ + mon = sc_tokid - JAN; + expect(NUMBER); + mday = atoi(sc_token); + if (token() == NUMBER) { + year = atoi(sc_token); + (void)token(); + } + assign_date(tm, mday, mon, year); + break; + + case SUN: case MON: case TUE: + case WED: case THU: case FRI: + case SAT: + /* do a particular day of the week */ + wday = sc_tokid - SUN; + + mday = tm->tm_mday; + + /* if this day is < today, then roll to next week */ + if (wday < tm->tm_wday) + mday += 7 - (tm->tm_wday - wday); + else + mday += (wday - tm->tm_wday); + + tm->tm_wday = wday; + + assign_date(tm, mday, tm->tm_mon, tm->tm_year + TM_YEAR_BASE); + break; + + case NUMBER: + /* + * get numeric MMDDYY, mm/dd/yy, or dd.mm.yy + */ + tlen = strlen(sc_token); + mon = atoi(sc_token); + (void)token(); + + if (sc_tokid == SLASH || sc_tokid == DOT) { + tokid_t sep; + + sep = sc_tokid; + expect(NUMBER); + mday = atoi(sc_token); + if (token() == sep) { + expect(NUMBER); + year = atoi(sc_token); + (void)token(); + } + + /* + * flip months and days for european timing + */ + if (sep == DOT) { + int x = mday; + mday = mon; + mon = x; + } + } else if (tlen == 6 || tlen == 8) { + if (tlen == 8) { + year = (mon % 10000) - 1900; + mon /= 10000; + } else { + year = mon % 100; + mon /= 100; + } + mday = mon % 100; + mon /= 100; + } else + panic("garbled time"); + + mon--; + if (mon < 0 || mon > 11 || mday < 1 || mday > 31) + panic("garbled time"); + + assign_date(tm, mday, mon, year); + break; + default: + /* plonk(sc_tokid); */ /* XXX - die here? */ + break; + } +} + + +/* Global functions */ + +time_t +parsetime(int argc, char **argv) +{ + /* + * Do the argument parsing, die if necessary, and return the + * time the job should be run. + */ + time_t nowtimer, runtimer; + struct tm nowtime, runtime; + int hr = 0; /* this MUST be initialized to zero for + midnight/noon/teatime */ + + nowtimer = time(NULL); + nowtime = *localtime(&nowtimer); + + runtime = nowtime; + runtime.tm_sec = 0; + + if (argc <= optind) + usage(); + + init_scanner(argc - optind, argv + optind); + + switch (token()) { + case NOW: + if (scc < 1) + return nowtimer; + + /* now is optional prefix for PLUS tree */ + expect(PLUS); + /*FALLTHROUGH*/ + case PLUS: + plus(&runtime); + break; + + case NUMBER: + tod(&runtime); + month(&runtime); + break; + + /* + * evil coding for TEATIME|NOON|MIDNIGHT - we've initialised + * hr to zero up above, then fall into this case in such a + * way so we add +12 +4 hours to it for teatime, +12 hours + * to it for noon, and nothing at all for midnight, then + * set our runtime to that hour before leaping into the + * month scanner + */ + case TEATIME: + hr += 4; + /*FALLTHROUGH*/ + case NOON: + hr += 12; + /*FALLTHROUGH*/ + case MIDNIGHT: + if (runtime.tm_hour >= hr) { + runtime.tm_mday++; + runtime.tm_wday++; + } + runtime.tm_hour = hr; + runtime.tm_min = 0; + (void)token(); + /*FALLTHROUGH*/ /* fall through to month setting */ + default: + month(&runtime); + break; + } + expect(TOKEOF); + + /* + * adjust for daylight savings time + */ + runtime.tm_isdst = -1; + runtimer = mktime(&runtime); + + if (runtimer == (time_t)-1) + panic("Invalid time"); + + if (nowtimer > runtimer) + panic("Trying to travel back in time"); + + return runtimer; +} diff --git a/usr.bin/at/parsetime.h b/usr.bin/at/parsetime.h new file mode 100644 index 0000000..a2c9a69 --- /dev/null +++ b/usr.bin/at/parsetime.h @@ -0,0 +1,35 @@ +/* $NetBSD: parsetime.h,v 1.5 2008/04/05 16:26:57 christos Exp $ */ + +/* + * parsetime.h - header for at(1) + * Copyright (c) 1993 Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: $OpenBSD: parsetime.h,v 1.3 1997/03/01 23:40:11 millert Exp $ + */ + +#ifndef _PARSETIME_H_ +#define _PARSETIME_H_ + +time_t parsetime(int, char **); + +#endif /* _PARSETIME_H_ */ diff --git a/usr.bin/at/pathnames.h b/usr.bin/at/pathnames.h new file mode 100644 index 0000000..88e6a53 --- /dev/null +++ b/usr.bin/at/pathnames.h @@ -0,0 +1,51 @@ +/* $NetBSD: pathnames.h,v 1.8 2008/04/05 16:26:57 christos Exp $ */ + +/* + * Copyright (c) 1993 Christopher G. Demetriou + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the + * NetBSD Project. See http://www.NetBSD.org/ for + * information about NetBSD. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * <> + * + * From: $OpenBSD: pathnames.h,v 1.3 1997/03/01 23:40:11 millert Exp $ + */ + +#ifndef _PATHNAMES_H_ +#define _PATHNAMES_H_ + +#include + +#define _PATH_ATJOBS "/var/at/jobs/" +#define _PATH_ATSPOOL "/var/at/spool/" +#define _PATH_LOCKFILE "/var/at/.lockfile" +#define _PATH_SEQFILE "/var/at/.SEQ" +#define _PATH_AT_ALLOW "/var/at/at.allow" +#define _PATH_AT_DENY "/var/at/at.deny" + +#endif /* _PATHNAMES_H_ */ diff --git a/usr.bin/at/perm.c b/usr.bin/at/perm.c new file mode 100644 index 0000000..64e4fbb --- /dev/null +++ b/usr.bin/at/perm.c @@ -0,0 +1,118 @@ +/* $NetBSD: perm.c,v 1.4 2016/03/13 00:32:09 dholland Exp $ */ + +/* + * perm.c - check user permission for at(1) + * Copyright (C) 1994 Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* System Headers */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Local headers */ + +#include "at.h" +#include "panic.h" +#include "pathnames.h" +#include "privs.h" +#include "perm.h" + +/* File scope variables */ + +#ifndef lint +#if 0 +static char rcsid[] = "$OpenBSD: perm.c,v 1.1 1997/03/01 23:40:12 millert Exp $"; +#else +__RCSID("$NetBSD: perm.c,v 1.4 2016/03/13 00:32:09 dholland Exp $"); +#endif +#endif + +/* Local functions */ + +static bool +check_for_user(FILE *fp, const char *name) +{ + char *buffer; + size_t len; + bool found = false; + + len = strlen(name); + if ((buffer = malloc(len + 2)) == NULL) + panic("Insufficient virtual memory"); + + while (fgets(buffer, (int)len + 2, fp) != NULL) { + if (strncmp(name, buffer, len) == 0 && buffer[len] == '\n') { + found = true; + break; + } + } + (void)fclose(fp); + free(buffer); + return found; +} + +/* Global functions */ + +bool +check_permission(void) +{ + FILE *fp; + uid_t uid = geteuid(); + struct passwd *pentry; + + if (uid == 0) + return true; + + if ((pentry = getpwuid(uid)) == NULL) { + perror("Cannot access user database"); + exit(EXIT_FAILURE); + } + + privs_enter(); + + fp = fopen(_PATH_AT_ALLOW, "r"); + + privs_exit(); + + if (fp != NULL) { + return check_for_user(fp, pentry->pw_name); + } else { + privs_enter(); + + fp = fopen(_PATH_AT_DENY, "r"); + + privs_exit(); + + if (fp != NULL) + return !check_for_user(fp, pentry->pw_name); + } + return false; +} diff --git a/usr.bin/at/perm.h b/usr.bin/at/perm.h new file mode 100644 index 0000000..89d0178 --- /dev/null +++ b/usr.bin/at/perm.h @@ -0,0 +1,33 @@ +/* $NetBSD: perm.h,v 1.3 2008/04/05 16:26:57 christos Exp $ */ + +/* + * perm.h - header for at(1) + * Copyright (C) 1994 Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PERM_H_ +#define _PERM_H_ + +bool check_permission(void); + +#endif /* _PERM_H_ */ diff --git a/usr.bin/at/privs.c b/usr.bin/at/privs.c new file mode 100644 index 0000000..1b7e12d --- /dev/null +++ b/usr.bin/at/privs.c @@ -0,0 +1,104 @@ +/* $NetBSD: privs.c,v 1.3 2018/02/25 23:48:16 htodd Exp $ */ + +/* + * privs.c - privileged operations + * Copyright (C) 1993 Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: OpenBSD: privs.h,v 1.4 1997/03/01 23:40:12 millert Exp + */ + +#include + +#include "privs.h" + +/* + * Used by: usr.bin/at + * Used by: libexec/atrun + */ + +/* + * Relinquish privileges temporarily for a setuid or setgid program + * with the option of getting them back later. This is done by + * using POSIX saved user and groups ids. Call RELINQUISH_PRIVS once + * at the beginning of the main program. This will cause all operations + * to be executed with the real userid. When you need the privileges + * of the setuid/setgid invocation, call PRIV_START; when you no longer + * need it, call PRIV_END. Note that it is an error to call PRIV_START + * and not PRIV_END within the same function. + * + * Use RELINQUISH_PRIVS_ROOT(a,b) if your program started out running + * as root, and you want to drop back the effective userid to a + * and the effective group id to b, with the option to get them back + * later. + * + * Problems: Do not use return between PRIV_START and PRIV_END; this + * will cause the program to continue running in an unprivileged + * state. + * + * It is NOT safe to call exec(), system() or popen() with a user- + * supplied program (i.e. without carefully checking PATH and any + * library load paths) with relinquished privileges; the called program + * can acquire them just as easily. Set both effective and real userid + * to the real userid before calling any of them. + */ + +uid_t real_uid, effective_uid; +gid_t real_gid, effective_gid; + +void +privs_enter(void) +{ + if (seteuid(effective_uid) == -1) + privs_fail("Cannot get user privs"); + if (setegid(effective_gid) == -1) + privs_fail("Cannot get group privs"); +} + +void +privs_exit(void) +{ + if (setegid(real_gid) == -1) + privs_fail("Cannot relinquish group privs"); + if (seteuid(real_uid) == -1) + privs_fail("Cannot relinquish user privs"); +} + +void +privs_relinquish(void) +{ + real_uid = getuid(); + effective_uid = geteuid(); + real_gid = getgid(); + effective_gid = getegid(); + privs_exit(); +} + +void +privs_relinquish_root(uid_t ruid, gid_t rgid) +{ + real_uid = ruid; + real_gid = rgid; + effective_uid = geteuid(); + effective_gid = getegid(); + privs_exit(); +} diff --git a/usr.bin/at/privs.h b/usr.bin/at/privs.h new file mode 100644 index 0000000..4344cbe --- /dev/null +++ b/usr.bin/at/privs.h @@ -0,0 +1,76 @@ +/* $NetBSD: privs.h,v 1.10 2016/03/13 00:33:12 dholland Exp $ */ + +/* + * privs.h - header for privileged operations + * Copyright (C) 1993 Thomas Koenig + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. The name of the author(s) may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: OpenBSD: privs.h,v 1.4 1997/03/01 23:40:12 millert Exp + */ + +#ifndef _PRIVS_H_ +#define _PRIVS_H_ + +/* + * Used by: usr.bin/at + * Used by: libexec/atrun + */ + +/* + * Relinquish privileges temporarily for a setuid or setgid program + * with the option of getting them back later. This is done by + * using POSIX saved user and groups ids. Call RELINQUISH_PRIVS once + * at the beginning of the main program. This will cause all operations + * to be executed with the real userid. When you need the privileges + * of the setuid/setgid invocation, call PRIV_START; when you no longer + * need it, call PRIV_END. Note that it is an error to call PRIV_START + * and not PRIV_END within the same function. + * + * Use RELINQUISH_PRIVS_ROOT(a,b) if your program started out running + * as root, and you want to drop back the effective userid to a + * and the effective group id to b, with the option to get them back + * later. + * + * Problems: Do not use return between PRIV_START and PRIV_END; this + * will cause the program to continue running in an unprivileged + * state. + * + * It is NOT safe to call exec(), system() or popen() with a user- + * supplied program (i.e. without carefully checking PATH and any + * library load paths) with relinquished privileges; the called program + * can acquire them just as easily. Set both effective and real userid + * to the real userid before calling any of them. + */ + +extern uid_t real_uid, effective_uid; +extern gid_t real_gid, effective_gid; + +void privs_relinquish(void); +void privs_relinquish_root(uid_t ruid, gid_t rgid); + +void privs_enter(void); +void privs_exit(void); + +/* caller provides this */ +__dead void privs_fail(const char *msg); + +#endif /* _PRIV_H_ */ diff --git a/usr.bin/at/stime.c b/usr.bin/at/stime.c new file mode 100644 index 0000000..567b848 --- /dev/null +++ b/usr.bin/at/stime.c @@ -0,0 +1,116 @@ +/* $NetBSD: stime.c,v 1.7 2008/07/21 14:19:21 lukem Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "from: @(#)touch.c 8.2 (Berkeley) 4/28/95"; +#endif +__RCSID("$NetBSD: stime.c,v 1.7 2008/07/21 14:19:21 lukem Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include +#include + +#include "stime.h" + +#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0')) + +time_t +stime(char *arg) +{ + struct tm *t; + time_t tmptime; + int yearset; + char *p; + /* Start with the current time. */ + if (time(&tmptime) == (time_t)-1) + err(EXIT_FAILURE, "time"); + + if ((t = localtime(&tmptime)) == NULL) + err(EXIT_FAILURE, "localtime"); + /* [[CC]YY]MMDDhhmm[.SS] */ + if ((p = strchr(arg, '.')) == NULL) + t->tm_sec = 0; /* Seconds defaults to 0. */ + else { + if (strlen(p + 1) != 2) + goto terr; + *p++ = '\0'; + t->tm_sec = ATOI2(p); + } + + yearset = 0; + switch (strlen(arg)) { + case 12: /* CCYYMMDDhhmm */ + t->tm_year = ATOI2(arg) * 100 - TM_YEAR_BASE; + yearset = 1; + /* FALLTHROUGH */ + case 10: /* YYMMDDhhmm */ + if (yearset) { + t->tm_year += ATOI2(arg); + } else { + yearset = ATOI2(arg); + t->tm_year = conv_2dig_year(yearset) - TM_YEAR_BASE; + } + /* FALLTHROUGH */ + case 8: /* MMDDhhmm */ + t->tm_mon = ATOI2(arg); + --t->tm_mon; /* Convert from 01-12 to 00-11 */ + /* FALLTHROUGH */ + case 6: + t->tm_mday = ATOI2(arg); + /* FALLTHROUGH */ + case 4: + t->tm_hour = ATOI2(arg); + /* FALLTHROUGH */ + case 2: + t->tm_min = ATOI2(arg); + break; + default: + goto terr; + } + + t->tm_isdst = -1; /* Figure out DST. */ + tmptime = mktime(t); + if (tmptime == (time_t)-1) { + terr: errx(EXIT_FAILURE, + "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); + } + return tmptime; +} diff --git a/usr.bin/at/stime.h b/usr.bin/at/stime.h new file mode 100644 index 0000000..266953e --- /dev/null +++ b/usr.bin/at/stime.h @@ -0,0 +1,53 @@ +/* $NetBSD: stime.h,v 1.4 2008/04/05 16:26:57 christos Exp $ */ + +/* + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _STIME_H_ +#define _STIME_H_ + +/* + * Convert a 2-digit year to a valid year as: + * 00-68 <-> 2000-2068 + * 69-99 <-> 1969-1999 + * + * Note: We choose the earliest year as 1969 rather than 1970 so that + * dates near the Epoch (Jan 1, 1970 00:00:00 UTC) can be represented + * with 2-digit years in all time zones. This is the convention used + * in parsedate(3), though it is not consistently applied in the + * source tree. + * + * XXX - move this (or something like it) to time.h and use it + * consistently in the tree. + */ +#define conv_2dig_year(y) ((y) < 69 ? (y) + 2000 : (y) + 1900) + +time_t stime(char *); + +#endif /* _STIME_H_ */ -- cgit v1.2.3-60-g2f50