From b8fa79b1008b6cedb12283497d8b0ad22831ee29 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Jan 25 2018 09:29:22 +0000 Subject: import at-3.1.13-22.el7_4.2 --- diff --git a/.at.metadata b/.at.metadata new file mode 100644 index 0000000..36647b9 --- /dev/null +++ b/.at.metadata @@ -0,0 +1 @@ +9873e0c38403ef58364912d0b505fd20798fd400 SOURCES/at_3.1.13.orig.tar.gz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb5ef33 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/at_3.1.13.orig.tar.gz diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/at-3.1.10-filter-environment.patch b/SOURCES/at-3.1.10-filter-environment.patch new file mode 100644 index 0000000..55fc669 --- /dev/null +++ b/SOURCES/at-3.1.10-filter-environment.patch @@ -0,0 +1,26 @@ +diff -up at-3.1.10/at.c.filter-environment at-3.1.10/at.c +--- at-3.1.10/at.c.filter-environment 2014-10-02 10:21:01.684890331 +0200 ++++ at-3.1.10/at.c 2014-10-02 10:21:40.678770635 +0200 +@@ -388,6 +388,22 @@ writefile(time_t runtimer, char queue) + int export = 1; + char *eqp; + ++ /* Only accept alphanumerics and underscore in variable names. ++ * Also require the name to not start with a digit. ++ * Some shells don't like other variable names. ++ */ ++ { ++ char *p = *atenv; ++ if (isdigit(*p)) ++ export = 0; ++ for (; *p != '=' && *p != '\0'; ++p) { ++ if (!isalnum(*p) && *p != '_') { ++ export = 0; ++ break; ++ } ++ } ++ } ++ + eqp = strchr(*atenv, '='); + if (ap == NULL) + eqp = *atenv; diff --git a/SOURCES/at-3.1.12-fix_no_export.patch b/SOURCES/at-3.1.12-fix_no_export.patch new file mode 100644 index 0000000..60e093a --- /dev/null +++ b/SOURCES/at-3.1.12-fix_no_export.patch @@ -0,0 +1,15 @@ +diff -up at-3.1.12/at.c.noexport at-3.1.12/at.c +--- at-3.1.12/at.c.noexport 2011-06-10 14:21:04.000000000 +0200 ++++ at-3.1.12/at.c 2011-06-10 14:22:54.247712577 +0200 +@@ -391,8 +391,9 @@ writefile(time_t runtimer, char queue) + unsigned int i; + for (i = 0; i < sizeof(no_export) / sizeof(no_export[0]); i++) { + export = export +- && (strncmp(*atenv, no_export[i], +- (size_t) (eqp - *atenv)) != 0); ++ && ((((size_t) (eqp - *atenv)) != strlen(no_export[i])) ++ ||(strncmp(*atenv, no_export[i],(size_t) (eqp - *atenv)) != 0) ++ ); + } + eqp++; + } diff --git a/SOURCES/at-3.1.12-nowrap.patch b/SOURCES/at-3.1.12-nowrap.patch new file mode 100644 index 0000000..f18167b --- /dev/null +++ b/SOURCES/at-3.1.12-nowrap.patch @@ -0,0 +1,19 @@ +diff -up at-3.1.12/at.c.nowrap at-3.1.12/at.c +--- at-3.1.12/at.c.nowrap 2010-02-18 14:39:50.125518422 +0100 ++++ at-3.1.12/at.c 2010-02-22 13:20:03.817150406 +0100 +@@ -308,10 +308,13 @@ writefile(time_t runtimer, char queue) + if (*ap == ' ') + *ap = '0'; + +- if (stat(atfile, &statbuf) != 0) ++ /*if (stat(atfile, &statbuf) != 0) { + if (errno != ENOENT) + perr("Cannot access " ATJOB_DIR); +- ++ } else { ++ perr("atjob file already exists; bailing"); ++ } ++ */ + /* 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 diff --git a/SOURCES/at-3.1.12-opt_V.patch b/SOURCES/at-3.1.12-opt_V.patch new file mode 100644 index 0000000..d25148d --- /dev/null +++ b/SOURCES/at-3.1.12-opt_V.patch @@ -0,0 +1,17 @@ +diff -up at-3.1.12/at.c.opt_V at-3.1.12/at.c +--- at-3.1.12/at.c.opt_V 2009-11-23 16:11:52.000000000 +0100 ++++ at-3.1.12/at.c 2009-12-02 13:20:29.770215516 +0100 +@@ -853,10 +853,9 @@ main(int argc, char **argv) + */ + + if (disp_version) { +- fprintf(stderr, "at version " VERSION "\n" +- "Please report bugs to the Debian bug tracking system (http://bugs.debian.org/)\n" +- "or contact the maintainers (at@packages.debian.org).\n"); +- exit(EXIT_SUCCESS); ++ fprintf(stderr, "at version " VERSION "\n"); ++ if (argc == 2) ++ exit(EXIT_SUCCESS); + } + + /* select our program diff --git a/SOURCES/at-3.1.12-shell.patch b/SOURCES/at-3.1.12-shell.patch new file mode 100644 index 0000000..617b8f9 --- /dev/null +++ b/SOURCES/at-3.1.12-shell.patch @@ -0,0 +1,55 @@ +diff -up at-3.1.12/at.c.shell at-3.1.12/at.c +--- at-3.1.12/at.c.shell 2009-12-02 13:25:12.706989310 +0100 ++++ at-3.1.12/at.c 2009-12-02 13:26:01.991966200 +0100 +@@ -62,11 +62,8 @@ + #include + #include + +-#ifdef TM_IN_SYS_TIME + #include +-#else + #include +-#endif + + #ifdef HAVE_UNISTD_H + #include +@@ -244,6 +241,12 @@ writefile(time_t runtimer, char queue) + int kill_errno; + int rc; + int mailsize = 128; ++ struct timeval tv; ++ struct timezone tz; ++ long int i; ++ ++ gettimeofday(&tv, &tz); ++ srandom(getpid()+tv.tv_usec); + + /* Install the signal handler for SIGINT; terminate after removing the + * spool file if necessary +@@ -461,6 +464,9 @@ writefile(time_t runtimer, char queue) + fprintf(fp, " || {\n\t echo 'Execution directory " + "inaccessible' >&2\n\t exit 1\n}\n"); + ++ i = random(); ++ fprintf(fp, "${SHELL:-/bin/sh} << \'marcinDELIMITER%08lx\'\n", i); ++ + istty = isatty(fileno(stdin)); + if (istty) { + fprintf(stderr, "at> "); +@@ -477,6 +483,7 @@ writefile(time_t runtimer, char queue) + fprintf(stderr, "\n"); + } + fprintf(fp, "\n"); ++ fprintf(fp, "marcinDELIMITER%08lx\n", i); + if (ferror(fp)) + panic("Output error"); + +@@ -926,7 +933,7 @@ main(int argc, char **argv) + It also alows a warning diagnostic to be printed. Because of the + possible variance, we always output the diagnostic. */ + +- fprintf(stderr, "warning: commands will be executed using /bin/sh\n"); ++ //fprintf(stderr, "warning: commands will be executed using /bin/sh\n"); + + writefile(timer, queue); + break; diff --git a/SOURCES/at-3.1.13-aborted-jobs.patch b/SOURCES/at-3.1.13-aborted-jobs.patch new file mode 100644 index 0000000..7a85b4e --- /dev/null +++ b/SOURCES/at-3.1.13-aborted-jobs.patch @@ -0,0 +1,126 @@ +diff -up at-3.1.13/atd.c.aborted at-3.1.13/atd.c +--- at-3.1.13/atd.c.aborted 2016-04-22 13:30:58.563029540 +0200 ++++ at-3.1.13/atd.c 2017-09-14 16:00:38.109011916 +0200 +@@ -74,6 +74,9 @@ + #include + #endif + ++#include ++#include ++ + /* Local headers */ + + #include "privs.h" +@@ -285,7 +288,7 @@ run_file(const char *filename, uid_t uid + * mail to the user. + */ + pid_t pid; +- int fd_out, fd_in; ++ int fd_out, fd_in, fd_std; + char jobbuf[9]; + char *mailname = NULL; + int mailsize = 128; +@@ -404,6 +407,10 @@ run_file(const char *filename, uid_t uid + + fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC); + ++ if (flock(fd_in, LOCK_EX | LOCK_NB) != 0) ++ perr("Somebody already locked the job %8lu (%.500s) - " ++ "aborting", jobno, filename); ++ + /* + * If the spool directory is mounted via NFS `atd' isn't able to + * read from the job file and will bump out here. The file is +@@ -563,10 +570,7 @@ run_file(const char *filename, uid_t uid + PRIV_END + } + /* We're the parent. Let's wait. +- */ +- close(fd_in); +- +- /* We inherited the master's SIGCHLD handler, which does a ++ We inherited the master's SIGCHLD handler, which does a + non-blocking waitpid. So this blocking one will eventually + return with an ECHILD error. + */ +@@ -583,14 +587,14 @@ run_file(const char *filename, uid_t uid + /* some sendmail implementations are confused if stdout, stderr are + * not available, so let them point to /dev/null + */ +- if ((fd_in = open("/dev/null", O_WRONLY)) < 0) ++ if ((fd_std = open("/dev/null", O_WRONLY)) < 0) + perr("Could not open /dev/null."); +- if (dup2(fd_in, STDOUT_FILENO) < 0) ++ if (dup2(fd_std, STDOUT_FILENO) < 0) + perr("Could not use /dev/null as standard output."); +- if (dup2(fd_in, STDERR_FILENO) < 0) ++ if (dup2(fd_std, STDERR_FILENO) < 0) + perr("Could not use /dev/null as standard error."); +- if (fd_in != STDOUT_FILENO && fd_in != STDERR_FILENO) +- close(fd_in); ++ if (fd_std != STDOUT_FILENO && fd_std != STDERR_FILENO) ++ close(fd_std); + + if (unlink(filename) == -1) + syslog(LOG_WARNING, "Warning: removing output file for job %li failed: %s", +@@ -598,7 +602,12 @@ run_file(const char *filename, uid_t uid + + /* The job is now finished. We can delete its input file. + */ +- chdir(ATJOB_DIR); ++ if (chdir(ATJOB_DIR) != 0) ++ perr("Somebody removed %s directory from under us.", ATJOB_DIR); ++ ++ /* This also removes the flock */ ++ (void)close(fd_in); ++ + unlink(newname); + free(newname); + +@@ -642,7 +651,7 @@ run_file(const char *filename, uid_t uid + PRIV_END + } + else if ( mail_pid == -1 ) { +- perr("fork of mailer failed"); ++ syslog(LOG_ERR, "fork of mailer failed: %m"); + } + else { + /* Parent */ +@@ -738,8 +747,16 @@ run_loop() + /* Skip lock files */ + if (queue == '=') { + if ((buf.st_nlink == 1) && (run_time + CHECK_INTERVAL <= now)) { +- /* Remove stale lockfile FIXME: lock the lockfile, if you fail, it's still in use. */ +- unlink(dirent->d_name); ++ int fd; ++ ++ fd = open(dirent->d_name, O_RDONLY); ++ if (fd != -1) { ++ if (flock(fd, LOCK_EX | LOCK_NB) == 0) { ++ unlink(dirent->d_name); ++ syslog(LOG_NOTICE, "removing stale lock file %s\n", dirent->d_name); ++ } ++ (void)close(fd); ++ } + } + continue; + } +@@ -752,12 +769,17 @@ run_loop() + /* Is the file already locked? + */ + if (buf.st_nlink > 1) { ++ if (run_time < buf.st_mtime) ++ run_time = buf.st_mtime; + if (run_time + CHECK_INTERVAL <= now) { +- + /* Something went wrong the last time this was executed. + * Let's remove the lockfile and reschedule. ++ * We also change the timestamp to avoid rerunning the job more ++ * than once every CHECK_INTERVAL. + */ + strncpy(lock_name, dirent->d_name, sizeof(lock_name)); ++ if (utime(lock_name, 0) < 0) ++ syslog(LOG_ERR, "utime couldn't be set for lock file %s\n", lock_name); + lock_name[sizeof(lock_name)-1] = '\0'; + lock_name[0] = '='; + unlink(lock_name); diff --git a/SOURCES/at-3.1.13-clear-nonjobs.patch b/SOURCES/at-3.1.13-clear-nonjobs.patch new file mode 100644 index 0000000..14fd9ba --- /dev/null +++ b/SOURCES/at-3.1.13-clear-nonjobs.patch @@ -0,0 +1,42 @@ +diff -up at-3.1.13/atd.c.clear-nonjobs at-3.1.13/atd.c +--- at-3.1.13/atd.c.clear-nonjobs 2016-04-20 17:15:00.579327865 +0200 ++++ at-3.1.13/atd.c 2016-04-20 17:18:06.215376744 +0200 +@@ -414,10 +414,22 @@ run_file(const char *filename, uid_t uid + sprintf(fmt, "#!/bin/sh\n# atrun uid=%%d gid=%%d\n# mail %%%ds %%d", + mailsize ); + ++ /* Unlink the file unless there was an error reading it (perhaps ++ * temporary). ++ * If the file has a bogus format there is no reason in trying ++ * to run it again and again. ++ */ + if (fscanf(stream, fmt, +- &nuid, &ngid, mailname, &send_mail) != 4) +- pabort("File %.500s is in wrong format - aborting", +- filename); ++ &nuid, &ngid, mailname, &send_mail) != 4) { ++ if (ferror(stream)) ++ perr("Error reading the job file"); ++ ++ unlink(filename); ++ pabort("File %.500s is in wrong format - aborting", ++ filename); ++ } ++ ++ unlink(filename); + + if (mailname[0] == '-') + pabort("illegal mail name %.300s in job %8lu (%.300s)", mailname, +@@ -427,12 +439,6 @@ run_file(const char *filename, uid_t uid + pabort("Job %8lu (%.500s) - userid %d does not match file uid %d", + jobno, filename, nuid, uid); + +- /* We are now committed to executing this script. Unlink the +- * original. +- */ +- +- unlink(filename); +- + fclose(stream); + if (chdir(ATSPOOL_DIR) < 0) + perr("Cannot chdir to " ATSPOOL_DIR); diff --git a/SOURCES/at-3.1.13-fclose-error.patch b/SOURCES/at-3.1.13-fclose-error.patch new file mode 100644 index 0000000..74d4958 --- /dev/null +++ b/SOURCES/at-3.1.13-fclose-error.patch @@ -0,0 +1,26 @@ +diff -up at-3.1.13/at.c.fclose at-3.1.13/at.c +--- at-3.1.13/at.c.fclose 2016-04-20 17:15:00.584327893 +0200 ++++ at-3.1.13/at.c 2016-04-20 17:15:50.453609665 +0200 +@@ -209,7 +209,11 @@ nextjob() + jobno = (1 + jobno) % 0xfffff; /* 2^20 jobs enough? */ + fprintf(fid, "%05lx\n", jobno); + +- fclose(fid); ++ if (ferror(fid)) ++ jobno = EOF; ++ ++ if (fclose(fid) != 0) ++ jobno = EOF; + return jobno; + } + +@@ -498,7 +502,8 @@ writefile(time_t runtimer, char queue) + if (ferror(stdin)) + panic("Input error"); + +- fclose(fp); ++ if (fclose(fp) != 0) ++ panic("Output error"); + + /* Set the x bit so that we're ready to start executing + */ diff --git a/SOURCES/at-3.1.13-help.patch b/SOURCES/at-3.1.13-help.patch new file mode 100644 index 0000000..8014526 --- /dev/null +++ b/SOURCES/at-3.1.13-help.patch @@ -0,0 +1,15 @@ +diff -up at-3.1.13/at.c.add at-3.1.13/at.c +diff -up at-3.1.13/panic.c.add at-3.1.13/panic.c +--- at-3.1.13/panic.c.add 2012-01-27 13:54:46.216466452 +0100 ++++ at-3.1.13/panic.c 2012-01-27 13:57:35.123747498 +0100 +@@ -92,8 +92,8 @@ usage(void) + { + /* Print usage and exit. + */ +- fprintf(stderr, "Usage: at [-V] [-q x] [-f file] [-mlbv] timespec ...\n" +- " at [-V] [-q x] [-f file] [-mlbv] -t time\n" ++ fprintf(stderr, "Usage: at [-V] [-q x] [-f file] [-mMlbv] timespec ...\n" ++ " at [-V] [-q x] [-f file] [-mMlbv] -t time\n" + " at -c job ...\n" + " atq [-V] [-q x]\n" + " at [ -rd ] job ...\n" diff --git a/SOURCES/at-3.1.13-mailwithhostname.patch b/SOURCES/at-3.1.13-mailwithhostname.patch new file mode 100644 index 0000000..a3e5933 --- /dev/null +++ b/SOURCES/at-3.1.13-mailwithhostname.patch @@ -0,0 +1,62 @@ +diff -up at-3.1.13/atd.c.hostname at-3.1.13/atd.c +--- at-3.1.13/atd.c.hostname 2012-01-12 18:19:36.000000000 +0100 ++++ at-3.1.13/atd.c 2012-01-12 18:52:34.000000000 +0100 +@@ -99,6 +99,10 @@ int selinux_enabled=0; + #define BATCH_INTERVAL_DEFAULT 60 + #define CHECK_INTERVAL 3600 + ++#ifndef MAXHOSTNAMELEN ++#define MAXHOSTNAMELEN 64 ++#endif ++ + /* Global variables */ + + uid_t real_uid, effective_uid; +@@ -116,6 +120,7 @@ static time_t last_chg; + static int nothing_to_do; + unsigned int batch_interval; + static int run_as_daemon = 0; ++static int mail_with_hostname = 0; + + static volatile sig_atomic_t term_signal = 0; + +@@ -297,6 +302,7 @@ run_file(const char *filename, uid_t uid + char fmt[64]; + unsigned long jobno; + int rc; ++ char hostbuf[MAXHOSTNAMELEN]; + #ifdef WITH_PAM + int retcode; + #endif +@@ -451,6 +457,11 @@ run_file(const char *filename, uid_t uid + + write_string(fd_out, "Subject: Output from your job "); + write_string(fd_out, jobbuf); ++ if (mail_with_hostname > 0) { ++ gethostname(hostbuf, MAXHOSTNAMELEN-1); ++ write_string(fd_out, " "); ++ write_string(fd_out, hostbuf); ++ } + write_string(fd_out, "\nTo: "); + write_string(fd_out, mailname); + write_string(fd_out, "\n\n"); +@@ -910,7 +921,7 @@ main(int argc, char *argv[]) + run_as_daemon = 1; + batch_interval = BATCH_INTERVAL_DEFAULT; + +- while ((c = getopt(argc, argv, "sdl:b:f")) != EOF) { ++ while ((c = getopt(argc, argv, "sdnl:b:f")) != EOF) { + switch (c) { + case 'l': + if (sscanf(optarg, "%lf", &load_avg) != 1) +@@ -932,6 +943,10 @@ main(int argc, char *argv[]) + daemon_foreground++; + break; + ++ case 'n': ++ mail_with_hostname=1; ++ break; ++ + case 's': + run_as_daemon = 0; + break; diff --git a/SOURCES/at-3.1.13-makefile.patch b/SOURCES/at-3.1.13-makefile.patch new file mode 100644 index 0000000..edcdff6 --- /dev/null +++ b/SOURCES/at-3.1.13-makefile.patch @@ -0,0 +1,82 @@ +diff -up at-3.1.13/Makefile.in.make at-3.1.13/Makefile.in +--- at-3.1.13/Makefile.in.make 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/Makefile.in 2011-07-29 08:06:28.317600053 +0200 +@@ -65,13 +65,13 @@ LIST = Filelist Filelist.asc + all: at atd atrun + + at: $(ATOBJECTS) +- $(CC) $(CFLAGS) -o at $(ATOBJECTS) $(LIBS) $(LEXLIB) ++ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,now -o at -pie $(ATOBJECTS) $(LIBS) $(LEXLIB) $(SELINUXLIB) $(PAMLIB) + rm -f $(CLONES) + $(LN_S) -f at atq + $(LN_S) -f at atrm + + atd: $(RUNOBJECTS) +- $(CC) $(CFLAGS) -o atd $(RUNOBJECTS) $(LIBS) $(PAMLIB) ++ $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-z,now -o atd -pie $(RUNOBJECTS) $(LIBS) $(SELINUXLIB) $(PAMLIB) + + y.tab.c y.tab.h: parsetime.y + $(YACC) -d parsetime.y +@@ -83,38 +83,41 @@ atrun: atrun.in + configure + + .c.o: +- $(CC) -c $(CFLAGS) $(DEFS) $*.c ++ $(CC) -c $(CFLAGS) -fPIE $(DEFS) $*.c + + install: all +- $(INSTALL) -g root -o root -m 755 -d $(IROOT)$(etcdir) +- $(INSTALL) -g root -o root -m 755 -d $(IROOT)$(bindir) +- $(INSTALL) -g root -o root -m 755 -d $(IROOT)$(sbindir) +- $(INSTALL) -g root -o root -m 755 -d $(IROOT)$(docdir) +- $(INSTALL) -g root -o root -m 755 -d $(IROOT)$(atdocdir) +- $(INSTALL) -g $(DAEMON_GROUPNAME) -o $(DAEMON_USERNAME) -m 755 -d $(IROOT)$(ATSPOOL_DIR) $(IROOT)$(ATJOB_DIR) +- chmod 1770 $(IROOT)$(ATSPOOL_DIR) $(IROOT)$(ATJOB_DIR) ++ $(INSTALL) -m 755 -d $(IROOT)$(etcdir) ++ $(INSTALL) -m 755 -d $(IROOT)$(bindir) ++ $(INSTALL) -m 755 -d $(IROOT)$(sbindir) ++ $(INSTALL) -m 755 -d $(IROOT)$(docdir) ++ $(INSTALL) -m 755 -d $(IROOT)$(atdocdir) ++ $(INSTALL) -m 755 -d $(IROOT)$(etcdir)/pam.d/ ++ $(INSTALL) -g $(DAEMON_GROUPNAME) -o $(DAEMON_USERNAME) -m 755 -d $(IROOT)$(ATSPOOL_DIR) ++ chmod 700 $(IROOT)$(ATJOB_DIR) $(IROOT)$(ATSPOOL_DIR) ++ chown $(DAEMON_USERNAME):$(DAEMON_GROUPNAME) $(IROOT)$(ATJOB_DIR) $(IROOT)$(ATSPOOL_DIR) + touch $(IROOT)$(LFILE) + chmod 600 $(IROOT)$(LFILE) + chown $(DAEMON_USERNAME):$(DAEMON_GROUPNAME) $(IROOT)$(LFILE) +- test -f $(IROOT)$(etcdir)/at.allow || test -f $(IROOT)$(etcdir)/at.deny || $(INSTALL) -o root -g $(DAEMON_GROUPNAME) -m 640 at.deny $(IROOT)$(etcdir)/ +- $(INSTALL) -g $(DAEMON_GROUPNAME) -o $(DAEMON_USERNAME) -m 6755 at $(IROOT)$(bindir) ++ test -f $(IROOT)$(etcdir)/at.allow || test -f $(IROOT)$(etcdir)/at.deny || $(INSTALL) -m 600 at.deny $(IROOT)$(etcdir)/ ++ $(INSTALL) -o $(INSTALL_ROOT_USER) -g $(DAEMON_GROUPNAME) pam_atd $(IROOT)$(etcdir)/pam.d/atd ++ $(INSTALL) -m 4755 at $(IROOT)$(bindir) + $(LN_S) -f at $(IROOT)$(bindir)/atq + $(LN_S) -f at $(IROOT)$(bindir)/atrm +- $(INSTALL) -g root -o root -m 755 batch $(IROOT)$(bindir) +- $(INSTALL) -d -o root -g root -m 755 $(IROOT)$(man1dir) +- $(INSTALL) -d -o root -g root -m 755 $(IROOT)$(man5dir) +- $(INSTALL) -d -o root -g root -m 755 $(IROOT)$(man8dir) +- $(INSTALL) -g root -o root -m 755 atd $(IROOT)$(sbindir) +- $(INSTALL) -g root -o root -m 755 atrun $(IROOT)$(sbindir) +- $(INSTALL) -g root -o root -m 644 at.1 $(IROOT)$(man1dir)/ ++ $(INSTALL) -m 755 batch $(IROOT)$(bindir) ++ $(INSTALL) -d -m 755 $(IROOT)$(man1dir) ++ $(INSTALL) -d -m 755 $(IROOT)$(man5dir) ++ $(INSTALL) -d -m 755 $(IROOT)$(man8dir) ++ $(INSTALL) -m 755 atd $(IROOT)$(sbindir) ++ $(INSTALL) -m 755 atrun $(IROOT)$(sbindir) ++ $(INSTALL) -m 644 at.1 $(IROOT)$(man1dir)/ + cd $(IROOT)$(man1dir) && $(LN_S) -f at.1 atq.1 && $(LN_S) -f at.1 batch.1 && $(LN_S) -f at.1 atrm.1 +- $(INSTALL) -g root -o root -m 644 atd.8 $(IROOT)$(man8dir)/ ++ $(INSTALL) -m 644 atd.8 $(IROOT)$(man8dir)/ + sed "s,\$${exec_prefix},$(exec_prefix),g" tmpman +- $(INSTALL) -g root -o root -m 644 tmpman $(IROOT)$(man8dir)/atrun.8 ++ $(INSTALL) -m 644 tmpman $(IROOT)$(man8dir)/atrun.8 + rm -f tmpman +- $(INSTALL) -g root -o root -m 644 at.allow.5 $(IROOT)$(man5dir)/ ++ $(INSTALL) -m 644 at.allow.5 $(IROOT)$(man5dir)/ + cd $(IROOT)$(man5dir) && $(LN_S) -f at.allow.5 at.deny.5 +- $(INSTALL) -g root -o root -m 644 $(DOCS) $(IROOT)$(atdocdir) ++ $(INSTALL) -m 644 $(DOCS) $(IROOT)$(atdocdir) + rm -f $(IROOT)$(mandir)/cat1/at.1* $(IROOT)$(mandir)/cat1/batch.1* \ + $(IROOT)$(mandir)/cat1/atq.1* + rm -f $(IROOT)$(mandir)/cat1/atd.8* diff --git a/SOURCES/at-3.1.13-nitpicks.patch b/SOURCES/at-3.1.13-nitpicks.patch new file mode 100644 index 0000000..3582593 --- /dev/null +++ b/SOURCES/at-3.1.13-nitpicks.patch @@ -0,0 +1,121 @@ +diff -up at-3.1.13/at.1.in.nit at-3.1.13/at.1.in +--- at-3.1.13/at.1.in.nit 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/at.1.in 2011-07-28 13:04:41.398174737 +0200 +@@ -126,7 +126,7 @@ and to run a job at 1am tomorrow, you wo + .B at 1am tomorrow. + .PP + The definition of the time specification can be found in +-.IR @prefix@/share/doc/at/timespec . ++.IR @prefix@/share/doc/at-@VERSION@/timespec . + .PP + For both + .BR at " and " batch , +@@ -204,7 +204,7 @@ queue for + .BR batch . + Queues with higher letters run with increased niceness. The special + queue "=" is reserved for jobs which are currently running. +-.P ++ + If a job is submitted to a queue designated with an uppercase letter, the + job is treated as if it were submitted to batch at the time of the job. + Once the time is reached, the batch processing rules with respect to load +@@ -248,7 +248,7 @@ is an alias for + .TP + .B \-v + Shows the time the job will be executed before reading the job. +-.P ++ + Times displayed will be in the format "Thu Feb 20 14:50:00 1997". + .TP + .B +diff -up at-3.1.13/atd.c.nit at-3.1.13/atd.c +--- at-3.1.13/atd.c.nit 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/atd.c 2011-07-28 13:01:31.577967025 +0200 +@@ -83,6 +83,9 @@ + #include "getloadavg.h" + #endif + ++#ifndef LOG_ATD ++#define LOG_ATD LOG_DAEMON ++#endif + /* Macros */ + + #define BATCH_INTERVAL_DEFAULT 60 +@@ -194,6 +197,18 @@ myfork() + + #define fork myfork + #endif ++#undef ATD_MAIL_PROGRAM ++#undef ATD_MAIL_NAME ++#if defined(SENDMAIL) ++#define ATD_MAIL_PROGRAM SENDMAIL ++#define ATD_MAIL_NAME "sendmail" ++#elif defined(MAILC) ++#define ATD_MAIL_PROGRAM MAILC ++#define ATD_MAIL_NAME "mail" ++#elif defined(MAILX) ++#define ATD_MAIL_PROGRAM MAILX ++#define ATD_MAIL_NAME "mailx" ++#endif + + static void + run_file(const char *filename, uid_t uid, gid_t gid) +@@ -271,6 +286,9 @@ run_file(const char *filename, uid_t uid + free(newname); + return; + } ++ ++ (void) setsid(); //own session for process ++ + /* Let's see who we mail to. Hopefully, we can read it from + * the command file; if not, send it to the owner, or, failing that, + * to root. +@@ -433,6 +451,9 @@ run_file(const char *filename, uid_t uid + if (setuid(uid) < 0) + perr("Cannot set user id"); + ++ if (SIG_ERR == signal(SIGCHLD, SIG_DFL)) ++ perr("Cannot reset signal handler to default"); ++ + chdir("/"); + + if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0) +@@ -501,6 +522,9 @@ run_file(const char *filename, uid_t uid + if (setuid(uid) < 0) + perr("Cannot set user id"); + ++ if (SIG_ERR == signal(SIGCHLD, SIG_DFL)) ++ perr("Cannot reset signal handler to default"); ++ + chdir ("/"); + + #if defined(SENDMAIL) +@@ -615,6 +639,7 @@ run_loop() + * Let's remove the lockfile and reschedule. + */ + strncpy(lock_name, dirent->d_name, sizeof(lock_name)); ++ lock_name[sizeof(lock_name)-1] = '\0'; + lock_name[0] = '='; + unlink(lock_name); + next_job = now; +@@ -649,6 +674,7 @@ run_loop() + run_batch++; + if (strcmp(batch_name, dirent->d_name) > 0) { + strncpy(batch_name, dirent->d_name, sizeof(batch_name)); ++ batch_name[sizeof(batch_name)-1] = '\0'; + batch_uid = buf.st_uid; + batch_gid = buf.st_gid; + batch_queue = queue; +@@ -723,11 +749,7 @@ main(int argc, char *argv[]) + + RELINQUISH_PRIVS_ROOT(daemon_uid, daemon_gid) + +-#ifndef LOG_CRON +-#define LOG_CRON LOG_DAEMON +-#endif +- +- openlog("atd", LOG_PID, LOG_CRON); ++ openlog("atd", LOG_PID, LOG_ATD); + + opterr = 0; + errno = 0; diff --git a/SOURCES/at-3.1.13-pam.patch b/SOURCES/at-3.1.13-pam.patch new file mode 100644 index 0000000..0bb3116 --- /dev/null +++ b/SOURCES/at-3.1.13-pam.patch @@ -0,0 +1,426 @@ +diff -up at-3.1.13/at.c.pam at-3.1.13/at.c +--- at-3.1.13/at.c.pam 2012-04-19 16:50:57.491000001 +0200 ++++ at-3.1.13/at.c 2012-04-19 16:50:57.505000001 +0200 +@@ -141,18 +141,13 @@ sigc(int signo) + /* If the user presses ^C, remove the spool file and exit + */ + if (fcreated) { +- /* + PRIV_START +- ++ /* + We need the unprivileged uid here since the file is owned by the real + (not effective) uid. + */ +- setregid(real_gid, effective_gid); +- unlink(atfile); +- setregid(effective_gid, real_gid); +- /* ++ unlink(atfile); + PRIV_END +- */ + } + exit(EXIT_FAILURE); + } +@@ -318,26 +313,19 @@ writefile(time_t runtimer, char queue) + * bit. Yes, this is a kluge. + */ + cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR); +- seteuid(real_uid); ++ if ((seteuid(effective_uid)) < 0) ++ perr("Error in seteuid: %s", errno); + if ((fd = open(atfile, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, S_IRUSR)) == -1) + perr("Cannot create atjob file %.500s", atfile); +- seteuid(effective_uid); + + if ((fd2 = dup(fd)) < 0) + perr("Error in dup() of job file"); + +- /* + if (fchown(fd2, real_uid, real_gid) != 0) +- perr("Cannot give away file"); +- */ ++ perr("Cannot give real_uid and real_gid the file"); + + PRIV_END + +- /* We no longer need suid root; now we just need to be able to write +- * to the directory, if necessary. +- */ +- +- REDUCE_PRIV(daemon_uid, daemon_gid) + /* We've successfully created the file; let's set the flag so it + * gets removed in case of an interrupt or error. + */ +@@ -661,7 +649,7 @@ process_jobs(int argc, char **argv, int + We need the unprivileged uid here since the file is owned by the real + (not effective) uid. + */ +- setregid(real_gid, effective_gid); ++ PRIV_START + + if (queue == '=') { + fprintf(stderr, "Warning: deleting running job\n"); +@@ -670,8 +658,8 @@ process_jobs(int argc, char **argv, int + perr("Cannot unlink %.500s", dirent->d_name); + rc = EXIT_FAILURE; + } ++ PRIV_END + +- setregid(effective_gid, real_gid); + done = 1; + + break; +@@ -681,7 +669,7 @@ process_jobs(int argc, char **argv, int + FILE *fp; + int ch; + +- setregid(real_gid, effective_gid); ++ PRIV_START + fp = fopen(dirent->d_name, "r"); + + if (fp) { +@@ -694,7 +682,7 @@ process_jobs(int argc, char **argv, int + perr("Cannot open %.500s", dirent->d_name); + rc = EXIT_FAILURE; + } +- setregid(effective_gid, real_gid); ++ PRIV_END + } + break; + +diff -up at-3.1.13/atd.c.pam at-3.1.13/atd.c +--- at-3.1.13/atd.c.pam 2012-04-19 16:50:57.498000001 +0200 ++++ at-3.1.13/atd.c 2012-04-19 16:52:37.209000138 +0200 +@@ -111,7 +111,7 @@ static int run_as_daemon = 0; + + static volatile sig_atomic_t term_signal = 0; + +-#ifdef HAVE_PAM ++#ifdef WITH_PAM + #include + + static pam_handle_t *pamh = NULL; +@@ -120,15 +120,7 @@ static const struct pam_conv conv = { + NULL + }; + +-#define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \ +- fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \ +- syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \ +- pam_end(pamh, retcode); exit(1); \ +- } +-#define PAM_END { retcode = pam_close_session(pamh,0); \ +- pam_end(pamh,retcode); } +- +-#endif /* HAVE_PAM */ ++#endif /* WITH_PAM */ + + /* Signal handlers */ + RETSIGTYPE +@@ -235,7 +227,7 @@ run_file(const char *filename, uid_t uid + char fmt[64]; + unsigned long jobno; + int rc; +-#ifdef HAVE_PAM ++#ifdef WITH_PAM + int retcode; + #endif + +@@ -395,17 +387,11 @@ run_file(const char *filename, uid_t uid + fstat(fd_out, &buf); + size = buf.st_size; + +-#ifdef HAVE_PAM +- PRIV_START +- retcode = pam_start("atd", pentry->pw_name, &conv, &pamh); +- PAM_FAIL_CHECK; +- retcode = pam_acct_mgmt(pamh, PAM_SILENT); +- PAM_FAIL_CHECK; +- retcode = pam_open_session(pamh, PAM_SILENT); +- PAM_FAIL_CHECK; +- retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); +- PAM_FAIL_CHECK; +- PRIV_END ++#ifdef WITH_PAM ++ AT_START_PAM; ++ AT_OPEN_PAM_SESSION; ++ closelog(); ++ openlog("atd", LOG_PID, LOG_ATD); + #endif + + close(STDIN_FILENO); +@@ -419,7 +405,14 @@ run_file(const char *filename, uid_t uid + else if (pid == 0) { + char *nul = NULL; + char **nenvp = &nul; ++ char **pam_envp=0L; + ++ PRIV_START ++#ifdef WITH_PAM ++ pam_envp = pam_getenvlist(pamh); ++ if ( ( pam_envp != 0L ) && (pam_envp[0] != 0L) ) ++ nenvp = pam_envp; ++#endif + /* Set up things for the child; we want standard input from the + * input file, and standard output and error sent to our output file. + */ +@@ -438,8 +431,6 @@ run_file(const char *filename, uid_t uid + close(fd_in); + close(fd_out); + +- PRIV_START +- + nice((tolower((int) queue) - 'a' + 1) * 2); + + if (initgroups(pentry->pw_name, pentry->pw_gid)) +@@ -458,7 +449,16 @@ run_file(const char *filename, uid_t uid + + if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0) + perr("Exec failed for /bin/sh"); +- ++#ifdef WITH_PAM ++ if ( ( nenvp != &nul ) && (pam_envp != 0L) && (*pam_envp != 0L)) ++ { ++ for( nenvp = pam_envp; *nenvp != 0L; nenvp++) ++ free(*nenvp); ++ free( pam_envp ); ++ nenvp = &nul; ++ pam_envp=0L; ++ } ++#endif + PRIV_END + } + /* We're the parent. Let's wait. +@@ -471,14 +471,6 @@ run_file(const char *filename, uid_t uid + */ + waitpid(pid, (int *) NULL, 0); + +-#ifdef HAVE_PAM +- PRIV_START +- pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); +- retcode = pam_close_session(pamh, PAM_SILENT); +- pam_end(pamh, retcode); +- PRIV_END +-#endif +- + /* Send mail. Unlink the output file after opening it, so it + * doesn't hang around after the run. + */ +@@ -509,8 +501,20 @@ run_file(const char *filename, uid_t uid + unlink(newname); + free(newname); + ++#ifdef ATD_MAIL_PROGRAM + if (((send_mail != -1) && (buf.st_size != size)) || (send_mail == 1)) { ++ int mail_pid = -1; ++#ifdef WITH_PAM ++ AT_START_PAM; ++ AT_OPEN_PAM_SESSION; ++ closelog(); ++ openlog("atd", LOG_PID, LOG_ATD); ++#endif ++ ++ mail_pid = fork(); + ++ if ( mail_pid == 0 ) ++ { + PRIV_START + + if (initgroups(pentry->pw_name, pentry->pw_gid)) +@@ -535,7 +539,21 @@ run_file(const char *filename, uid_t uid + perr("Exec failed for mail command"); + + PRIV_END ++ } ++ else if ( mail_pid == -1 ) { ++ perr("fork of mailer failed"); ++ } ++ else { ++ /* Parent */ ++ waitpid(mail_pid, (int *) NULL, 0); ++ } ++#ifdef WITH_PAM ++ AT_CLOSE_PAM; ++ closelog(); ++ openlog("atd", LOG_PID, LOG_ATD); ++#endif + } ++#endif + exit(EXIT_SUCCESS); + } + +diff -up at-3.1.13/config.h.in.pam at-3.1.13/config.h.in +--- at-3.1.13/config.h.in.pam 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/config.h.in 2012-04-19 16:50:57.506000001 +0200 +@@ -68,8 +68,8 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_NLIST_H + +-/* Define to 1 for PAM support */ +-#undef HAVE_PAM ++/* Define if you are building with_pam */ ++#undef WITH_PAM + + /* Define to 1 if you have the `pstat_getdynamic' function. */ + #undef HAVE_PSTAT_GETDYNAMIC +diff -up at-3.1.13/configure.ac.pam at-3.1.13/configure.ac +--- at-3.1.13/configure.ac.pam 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/configure.ac 2012-04-19 16:50:57.506000001 +0200 +@@ -84,7 +84,7 @@ AC_FUNC_GETLOADAVG + AC_CHECK_FUNCS(getcwd mktime strftime setreuid setresuid sigaction waitpid) + AC_CHECK_HEADERS(security/pam_appl.h, [ + PAMLIB="-lpam" +- AC_DEFINE(HAVE_PAM, 1, [Define to 1 for PAM support]) ++ AC_DEFINE(WITH_PAM, 1, [Define to 1 for PAM support]) + ]) + + dnl Checking for programs +@@ -238,6 +238,13 @@ AC_ARG_WITH(daemon_username, + ) + AC_SUBST(DAEMON_USERNAME) + ++AC_ARG_WITH(pam, ++[ --with-pam Define to enable pam support ], ++AC_DEFINE(WITH_PAM), ++) ++AC_CHECK_LIB(pam, pam_start, PAMLIB='-lpam -lpam_misc') ++AC_SUBST(PAMLIB) ++ + AC_MSG_CHECKING(groupname to run under) + AC_ARG_WITH(daemon_groupname, + [ --with-daemon_groupname=DAEMON_GROUPNAME Groupname to run under (default daemon) ], +diff -up at-3.1.13/perm.c.pam at-3.1.13/perm.c +--- at-3.1.13/perm.c.pam 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/perm.c 2012-04-19 16:53:09.192001742 +0200 +@@ -51,6 +51,14 @@ + #define PRIV_END while(0) + #endif + ++#ifdef WITH_PAM ++#include ++static pam_handle_t *pamh = NULL; ++static const struct pam_conv conv = { ++ NULL ++}; ++#endif ++ + /* Structures and unions */ + + +@@ -108,18 +116,45 @@ user_in_file(const char *path, const cha + int + check_permission() + { +- uid_t uid = geteuid(); ++ uid_t euid = geteuid(), uid=getuid(), egid=getegid(), gid=getgid(); + struct passwd *pentry; + int allow = 0, deny = 1; + +- if (uid == 0) ++ int retcode = 0; ++ if (euid == 0) + return 1; + +- if ((pentry = getpwuid(uid)) == NULL) { ++ if ((pentry = getpwuid(euid)) == NULL) { + perror("Cannot access user database"); + exit(EXIT_FAILURE); + } + ++#ifdef WITH_PAM ++/* ++ * We must check if the atd daemon userid will be allowed to gain the job owner user's ++ * credentials with PAM . If not, the user has been denied at(1) usage, eg. with pam_access. ++ */ ++ if (setreuid(daemon_uid, daemon_uid) != 0) { ++ fprintf(stderr, "cannot set egid: %s", strerror(errno)); ++ exit(1); ++ } ++ if (setregid(daemon_gid, daemon_gid) != 0) { ++ fprintf(stderr, "cannot set euid: %s", strerror(errno)); ++ exit(1); ++ } ++ ++ AT_START_PAM; ++ AT_CLOSE_PAM; ++ if (setregid(gid,egid) != 0) { ++ fprintf(stderr, "cannot set egid: %s", strerror(errno)); ++ exit(1); ++ } ++ if (setreuid(uid,euid) != 0) { ++ fprintf(stderr, "cannot set euid: %s", strerror(errno)); ++ exit(1); ++ } ++#endif ++ + allow = user_in_file(ETCDIR "/at.allow", pentry->pw_name); + if (allow==0 || allow==1) + return allow; +diff -up at-3.1.13/privs.h.pam at-3.1.13/privs.h +--- at-3.1.13/privs.h.pam 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/privs.h 2012-04-19 16:53:46.296016675 +0200 +@@ -144,3 +144,63 @@ extern gid_t real_gid, effective_gid, da + #error "Cannot implement user ID swapping without setreuid or setresuid" + #endif + #endif ++ ++#ifdef WITH_PAM ++/* PAM failed after session was open. */ ++#define PAM_SESSION_FAIL if (retcode != PAM_SUCCESS) \ ++ pam_close_session(pamh,PAM_SILENT); ++ ++/* syslog will be logging error messages */ ++#ifdef HAVE_UNISTD_H ++#include ++#endif ++ ++/* PAM fail even before opening the session */ ++#define PAM_FAIL_CHECK \ ++ do { if (retcode != PAM_SUCCESS) { \ ++ fprintf(stderr,"PAM failure: %s\n",pam_strerror(pamh, retcode)); \ ++ syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \ ++ if (pamh) \ ++ pam_end(pamh, retcode); \ ++ if (setregid(getgid(),getegid()) != 0) { \ ++ fprintf(stderr, "cannot set egid: %s", strerror(errno)); \ ++ exit(1); \ ++ } \ ++ if (setreuid(getuid(),geteuid()) != 0) { \ ++ fprintf(stderr, "cannot set euid: %s", strerror(errno)); \ ++ exit(1); \ ++ } \ ++ exit(1); \ ++ } \ ++ } while (0) \ ++ ++static int pam_session_opened = 0; //global for open session ++ ++#define AT_START_PAM { \ ++ retcode = pam_start("atd", pentry->pw_name, &conv, &pamh); \ ++ PAM_FAIL_CHECK; \ ++ retcode = pam_set_item(pamh, PAM_TTY, "atd"); \ ++ PAM_FAIL_CHECK; \ ++ retcode = pam_acct_mgmt(pamh, PAM_SILENT); \ ++ PAM_FAIL_CHECK; \ ++} ++ ++#define AT_OPEN_PAM_SESSION { \ ++ retcode = pam_open_session(pamh, PAM_SILENT); \ ++ PAM_FAIL_CHECK; \ ++ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); \ ++ PAM_FAIL_CHECK; \ ++ if (retcode == PAM_SUCCESS) \ ++ pam_session_opened = 1; \ ++} ++ ++#define AT_CLOSE_PAM { \ ++ if (pam_session_opened != 0) { \ ++ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); \ ++ pam_close_session(pamh, PAM_SILENT); \ ++ } \ ++ pam_end(pamh, PAM_SUCCESS); \ ++} ++ ++#endif ++ diff --git a/SOURCES/at-3.1.13-selinux.patch b/SOURCES/at-3.1.13-selinux.patch new file mode 100644 index 0000000..255fe2b --- /dev/null +++ b/SOURCES/at-3.1.13-selinux.patch @@ -0,0 +1,165 @@ +diff -up at-3.1.13/atd.c.selinux at-3.1.13/atd.c +--- at-3.1.13/atd.c.selinux 2012-11-01 15:11:21.368772308 +0100 ++++ at-3.1.13/atd.c 2012-11-01 15:13:16.809162818 +0100 +@@ -83,6 +83,14 @@ + #include "getloadavg.h" + #endif + ++#ifdef WITH_SELINUX ++#include ++#include ++int selinux_enabled=0; ++#include ++#include ++#endif ++ + #ifndef LOG_ATD + #define LOG_ATD LOG_DAEMON + #endif +@@ -202,6 +210,68 @@ myfork() + #define ATD_MAIL_NAME "mailx" + #endif + ++#ifdef WITH_SELINUX ++static int set_selinux_context(const char *name, const char *filename) { ++ security_context_t user_context=NULL; ++ security_context_t file_context=NULL; ++ struct av_decision avd; ++ int retval=-1; ++ char *seuser=NULL; ++ char *level=NULL; ++ ++ if (getseuserbyname(name, &seuser, &level) == 0) { ++ retval=get_default_context_with_level(seuser, level, NULL, &user_context); ++ free(seuser); ++ free(level); ++ if (retval) { ++ if (security_getenforce()==1) { ++ perr("execle: couldn't get security context for user %s\n", name); ++ } else { ++ syslog(LOG_ERR, "execle: couldn't get security context for user %s\n", name); ++ return -1; ++ } ++ } ++ } ++ ++ /* ++ * Since crontab files are not directly executed, ++ * crond must ensure that the crontab file has ++ * a context that is appropriate for the context of ++ * the user cron job. It performs an entrypoint ++ * permission check for this purpose. ++ */ ++ if (fgetfilecon(STDIN_FILENO, &file_context) < 0) ++ perr("fgetfilecon FAILED %s", filename); ++ ++ retval = security_compute_av(user_context, ++ file_context, ++ SECCLASS_FILE, ++ FILE__ENTRYPOINT, ++ &avd); ++ freecon(file_context); ++ if (retval || ((FILE__ENTRYPOINT & avd.allowed) != FILE__ENTRYPOINT)) { ++ if (security_getenforce()==1) { ++ perr("Not allowed to set exec context to %s for user %s\n", user_context,name); ++ } else { ++ syslog(LOG_ERR, "Not allowed to set exec context to %s for user %s\n", user_context,name); ++ retval = -1; ++ goto err; ++ } ++ } ++ if (setexeccon(user_context) < 0) { ++ if (security_getenforce()==1) { ++ perr("Could not set exec context to %s for user %s\n", user_context,name); ++ retval = -1; ++ } else { ++ syslog(LOG_ERR, "Could not set exec context to %s for user %s\n", user_context,name); ++ } ++ } ++ err: ++ freecon(user_context); ++ return 0; ++} ++#endif ++ + static void + run_file(const char *filename, uid_t uid, gid_t gid) + { +@@ -446,9 +516,23 @@ run_file(const char *filename, uid_t uid + perr("Cannot reset signal handler to default"); + + chdir("/"); +- ++#ifdef WITH_SELINUX ++ if (selinux_enabled > 0) { ++ if (set_selinux_context(pentry->pw_name, filename) < 0) ++ perr("SELinux Failed to set context\n"); ++ } ++#endif + if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0) + perr("Exec failed for /bin/sh"); ++//add for fedora ++#ifdef WITH_SELINUX ++ if (selinux_enabled>0) ++ if (setexeccon(NULL) < 0) ++ if (security_getenforce()==1) ++ perr("Could not resset exec context for user %s\n", pentry->pw_name); ++#endif ++//end ++//add for fedora + #ifdef WITH_PAM + if ( ( nenvp != &nul ) && (pam_envp != 0L) && (*pam_envp != 0L)) + { +@@ -751,6 +835,10 @@ main(int argc, char *argv[]) + struct passwd *pwe; + struct group *ge; + ++#ifdef WITH_SELINUX ++ selinux_enabled=is_selinux_enabled(); ++#endif ++ + /* We don't need root privileges all the time; running under uid and gid + * daemon is fine. + */ +diff -up at-3.1.13/config.h.in.selinux at-3.1.13/config.h.in +--- at-3.1.13/config.h.in.selinux 2012-11-01 15:11:21.368772308 +0100 ++++ at-3.1.13/config.h.in 2012-11-01 15:11:21.371772392 +0100 +@@ -71,6 +71,9 @@ + /* Define if you are building with_pam */ + #undef WITH_PAM + ++/* Define if you are building with_selinux */ ++#undef WITH_SELINUX ++ + /* Define to 1 if you have the `pstat_getdynamic' function. */ + #undef HAVE_PSTAT_GETDYNAMIC + +diff -up at-3.1.13/configure.ac.selinux at-3.1.13/configure.ac +--- at-3.1.13/configure.ac.selinux 2012-11-01 15:11:21.369772335 +0100 ++++ at-3.1.13/configure.ac 2012-11-01 15:11:21.372772420 +0100 +@@ -266,5 +266,13 @@ AC_ARG_WITH(daemon_groupname, + ) + AC_SUBST(DAEMON_GROUPNAME) + ++AC_ARG_WITH(selinux, ++[ --with-selinux Define to run with selinux], ++AC_DEFINE(WITH_SELINUX), ++) ++AC_CHECK_LIB(selinux, is_selinux_enabled, SELINUXLIB=-lselinux) ++AC_SUBST(SELINUXLIB) ++AC_SUBST(WITH_SELINUX) ++ + AC_CONFIG_FILES(Makefile atrun atd.8 atrun.8 at.1 at.allow.5 batch) + AC_OUTPUT +diff -up at-3.1.13/Makefile.in.selinux at-3.1.13/Makefile.in +--- at-3.1.13/Makefile.in.selinux 2012-11-01 15:11:21.361772115 +0100 ++++ at-3.1.13/Makefile.in 2012-11-01 15:11:21.372772420 +0100 +@@ -39,6 +39,8 @@ LIBS = @LIBS@ + LIBOBJS = @LIBOBJS@ + INSTALL = @INSTALL@ + PAMLIB = @PAMLIB@ ++SELINUXLIB = @SELINUXLIB@ ++ + + CLONES = atq atrm + ATOBJECTS = at.o panic.o perm.o posixtm.o y.tab.o lex.yy.o diff --git a/SOURCES/at-3.1.13-usePOSIXtimers.patch b/SOURCES/at-3.1.13-usePOSIXtimers.patch new file mode 100644 index 0000000..018bae2 --- /dev/null +++ b/SOURCES/at-3.1.13-usePOSIXtimers.patch @@ -0,0 +1,119 @@ +diff -ur -x configure at-3.1.13.orig/atd.c at-3.1.13/atd.c +--- at-3.1.13.orig/atd.c 2011-11-16 11:30:22.424764253 -0500 ++++ at-3.1.13/atd.c 2011-11-16 16:41:12.102831656 -0500 +@@ -815,6 +815,54 @@ + return next_job; + } + ++#ifdef HAVE_CLOCK_GETTIME ++timer_t timer; ++struct itimerspec timeout; ++ ++void timer_setup() ++{ ++ struct sigevent sev; ++ ++ sev.sigev_notify = SIGEV_SIGNAL; ++ sev.sigev_signo = SIGHUP; ++ sev.sigev_value.sival_ptr = &timer; ++ ++ memset(&timeout, 0, sizeof(timeout)); ++ ++ if (timer_create(CLOCK_REALTIME, &sev, &timer) < 0) ++ pabort("unable to create timer"); ++} ++ ++time_t atd_gettime() ++{ ++ struct timespec curtime; ++ ++ clock_gettime(CLOCK_REALTIME, &curtime); ++ ++ return curtime.tv_sec; ++} ++ ++void atd_setalarm(time_t next) ++{ ++ timeout.it_value.tv_sec = next; ++ timer_settime(timer, TIMER_ABSTIME, &timeout, NULL); ++ pause(); ++} ++#else ++void timer_setup() ++{ ++} ++ ++time_t atd_gettime() ++{ ++ return time(NULL); ++} ++ ++void atd_setalarm(time_t next) ++{ ++ sleep(next - atd_gettime()); ++} ++#endif + /* Global functions */ + + int +@@ -835,7 +883,6 @@ + struct sigaction act; + struct passwd *pwe; + struct group *ge; +- + #ifdef WITH_SELINUX + selinux_enabled=is_selinux_enabled(); + #endif +@@ -912,7 +959,7 @@ + sigaction(SIGCHLD, &act, NULL); + + if (!run_as_daemon) { +- now = time(NULL); ++ now = atd_gettime(); + run_loop(); + exit(EXIT_SUCCESS); + } +@@ -935,13 +982,15 @@ + act.sa_handler = set_term; + sigaction(SIGINT, &act, NULL); + ++ timer_setup(); ++ + daemon_setup(); + + do { +- now = time(NULL); ++ now = atd_gettime(); + next_invocation = run_loop(); + if (next_invocation > now) { +- sleep(next_invocation - now); ++ atd_setalarm(next_invocation); + } + } while (!term_signal); + daemon_cleanup(); +diff -ur -x configure at-3.1.13.orig/config.h.in at-3.1.13/config.h.in +--- at-3.1.13.orig/config.h.in 2011-11-16 11:30:22.424764253 -0500 ++++ at-3.1.13/config.h.in 2011-11-16 16:32:44.485426754 -0500 +@@ -38,6 +38,9 @@ + /* Define to 1 if you have the `getloadavg' function. */ + #undef HAVE_GETLOADAVG + ++/* Define to 1 if you have the `clock_gettime' function. */ ++#undef HAVE_TIMER_CREATE ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_GETOPT_H + +diff -ur -x configure at-3.1.13.orig/configure.ac at-3.1.13/configure.ac +--- at-3.1.13.orig/configure.ac 2011-11-16 11:30:22.425764254 -0500 ++++ at-3.1.13/configure.ac 2011-11-16 16:31:29.791561747 -0500 +@@ -274,5 +274,9 @@ + AC_SUBST(SELINUXLIB) + AC_SUBST(WITH_SELINUX) + ++dnl check for POSIX timer functions ++AC_SEARCH_LIBS([timer_create],[rt]) ++AC_CHECK_FUNCS([timer_create]) ++ + AC_CONFIG_FILES(Makefile atrun atd.8 atrun.8 at.1 at.allow.5 batch) + AC_OUTPUT diff --git a/SOURCES/at-3.1.13-utc-dst.patch b/SOURCES/at-3.1.13-utc-dst.patch new file mode 100644 index 0000000..1f72c39 --- /dev/null +++ b/SOURCES/at-3.1.13-utc-dst.patch @@ -0,0 +1,24 @@ +diff -up at-3.1.13/parsetime.y.dst at-3.1.13/parsetime.y +--- at-3.1.13/parsetime.y.dst 2011-06-25 14:43:14.000000000 +0200 ++++ at-3.1.13/parsetime.y 2016-04-20 17:23:24.140171655 +0200 +@@ -476,8 +476,8 @@ parsetime(time_t currtime, int argc, cha + exectm = *localtime(&currtime); + currtime -= exectm.tm_sec; + exectm.tm_sec = 0; +- exectm.tm_isdst = -1; + memcpy(&currtm,&exectm,sizeof(currtm)); ++ exectm.tm_isdst = -1; + time_only = 0; + yearspec = 0; + +@@ -503,8 +503,8 @@ parsetime(time_t currtime, int argc, cha + return 0; + if (isgmt) { + exectime -= timezone; +- if (currtm.tm_isdst && !exectm.tm_isdst) +- exectime -= 3600; ++ if (exectm.tm_isdst) ++ exectime += 3600; + } + if (exectime < currtime) + panic("refusing to create job destined in the past"); diff --git a/SOURCES/atd.init b/SOURCES/atd.init new file mode 100755 index 0000000..2f3fd20 --- /dev/null +++ b/SOURCES/atd.init @@ -0,0 +1,111 @@ +#!/bin/sh +# +# atd Starts/stop the "at" daemon +# +# chkconfig: 345 95 5 +# description: Runs commands scheduled by the "at" command at the time \ +# specified when "at" was run, and runs batch commands when the load \ +# average is low enough. + +### BEGIN INIT INFO +# Provides: atd at batch +# Required-Start: $local_fs +# Required-Stop: $local_fs +# Default-Start: 345 +# Default-Stop: 95 +# Short-Description: Starts/stop the "at" daemon +# Description: Runs commands scheduled by the "at" command at the time +# specified when "at" was run, and runs batch commands when the load +# average is low enough. +### END INIT INFO + +# Source function library. +. /etc/rc.d/init.d/functions + +exec=/usr/sbin/atd +prog="atd" +config=/etc/sysconfig/atd + +[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog + +lockfile=/var/lock/subsys/$prog + +start() { + [ -x $exec ] || exit 5 + [ -f $config ] || exit 6 + echo -n $"Starting $prog: " + daemon $exec $OPTS && success || failure + retval=$? + echo + [ $retval -eq 0 ] && touch $lockfile + return $retval +} + +stop() { + echo -n $"Stopping $prog: " + if [ -n "`pidfileofproc $exec`" ] ; then + killproc $exec + RETVAL=3 + else + failure $"Stopping $prog" + fi + retval=$? + echo + [ $retval -eq 0 ] && rm -f $lockfile + return $retval +} + +restart() { + stop + start +} + +reload() { + restart +} + +force_reload() { + restart +} + +rh_status() { + # run checks to determine if the service is running or use generic status + status $prog +} + +rh_status_q() { + rh_status >/dev/null 2>&1 +} + + +case "$1" in + start) + rh_status_q && exit 0 + $1 + ;; + stop) + rh_status_q || exit 0 + $1 + ;; + restart) + $1 + ;; + reload) + rh_status_q || exit 7 + $1 + ;; + force-reload) + force_reload + ;; + status) + rh_status + ;; + condrestart|try-restart) + rh_status_q || exit 0 + restart + ;; + *) + echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" + exit 2 +esac +exit $? diff --git a/SOURCES/atd.sysconf b/SOURCES/atd.sysconf new file mode 100644 index 0000000..056ce81 --- /dev/null +++ b/SOURCES/atd.sysconf @@ -0,0 +1,9 @@ +# specify additional command line arguments for atd +# +# -l Specifies a limiting load factor, over which batch jobs should not be run, instead of the compile-time +# choice of 0.8. For an SMP system with n CPUs, you will probably want to set this higher than n-1. +# +# -b Specifiy the minimum interval in seconds between the start of two batch jobs (60 default). + +#example: +#OPTS="-l 4 -b 120" diff --git a/SOURCES/atd.systemd b/SOURCES/atd.systemd new file mode 100644 index 0000000..abe24c1 --- /dev/null +++ b/SOURCES/atd.systemd @@ -0,0 +1,11 @@ +[Unit] +Description=Job spooling tools +After=syslog.target systemd-user-sessions.service + +[Service] +EnvironmentFile=/etc/sysconfig/atd +ExecStart=/usr/sbin/atd -f $OPTS +IgnoreSIGPIPE=no + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/pam_atd b/SOURCES/pam_atd new file mode 100644 index 0000000..1fd529e --- /dev/null +++ b/SOURCES/pam_atd @@ -0,0 +1,9 @@ +# The PAM configuration file for the at daemon +# +# +auth required pam_env.so +auth include password-auth +account required pam_access.so +account include password-auth +session required pam_loginuid.so +session include password-auth diff --git a/SPECS/at.spec b/SPECS/at.spec new file mode 100644 index 0000000..d206aec --- /dev/null +++ b/SPECS/at.spec @@ -0,0 +1,263 @@ +%bcond_without pam +%global _hardened_build 1 + +Summary: Job spooling tools +Name: at +Version: 3.1.13 +Release: 22%{?dist}.2 +# http://packages.debian.org/changelogs/pool/main/a/at/current/copyright +# + install-sh is MIT license with changes under Public Domain +License: GPLv3+ and GPLv2+ and ISC and MIT and Public Domain +Group: System Environment/Daemons +URL: http://ftp.debian.org/debian/pool/main/a/at + +Source: http://ftp.debian.org/debian/pool/main/a/at/at_%{version}.orig.tar.gz +# git upstream source git://git.debian.org/git/collab-maint/at.git +Source1: pam_atd +Source2: atd.init +Source3: atd.sysconf +Source5: atd.systemd + +Patch1: at-3.1.13-makefile.patch +Patch2: at-3.1.12-opt_V.patch +Patch3: at-3.1.12-shell.patch +Patch4: at-3.1.13-nitpicks.patch +Patch5: at-3.1.13-pam.patch +Patch6: at-3.1.13-selinux.patch +Patch7: at-3.1.12-nowrap.patch +Patch8: at-3.1.12-fix_no_export.patch +Patch9: at-3.1.13-mailwithhostname.patch +Patch10: at-3.1.13-usePOSIXtimers.patch +Patch11: at-3.1.13-help.patch +Patch12: at-3.1.10-filter-environment.patch +Patch13: at-3.1.13-fclose-error.patch +Patch14: at-3.1.13-clear-nonjobs.patch +Patch15: at-3.1.13-utc-dst.patch +Patch17: at-3.1.13-aborted-jobs.patch + +BuildRequires: fileutils /etc/init.d +BuildRequires: flex flex-static bison autoconf +BuildRequires: libselinux-devel >= 1.27.9 +BuildRequires: perl(Test::Harness) +BuildRequires: perl(Test::More) + +%if %{with pam} +BuildRequires: pam-devel +%endif +Conflicts: crontabs <= 1.5 +# No, I'm not kidding +BuildRequires: smtpdaemon + +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units + +%description +At and batch read commands from standard input or from a specified +file. At allows you to specify that a command will be run at a +particular time. Batch will execute commands when the system load +levels drop to a particular level. Both commands use user's shell. + +You should install the at package if you need a utility for +time-oriented job control. Note: If it is a recurring job that will +need to be repeated at the same time every day/week, etc. you should +use crontab instead. + +%package sysvinit +Summary: SysV init script for at +Group: System Environment/Base +Requires: %{name} = %{version}-%{release} +Requires(post): /sbin/chkconfig + +%description sysvinit +SysV style init script for at. It needs to be installed only if systemd +is not used as the system init process. + +%prep +%setup -q +cp %{SOURCE1} . +%patch1 -p1 -b .make +%patch2 -p1 -b .opt_V +%patch3 -p1 -b .shell +%patch4 -p1 -b .nit +%patch5 -p1 -b .pam +%patch6 -p1 -b .selinux +%patch7 -p1 -b .nowrap +%patch8 -p1 -b .export +%patch9 -p1 -b .mail +%patch10 -p1 -b .posix +%patch11 -p1 -b .help +%patch12 -p1 -b .filter-environment +%patch13 -p1 -b .fclose +%patch14 -p1 -b .clear-nonjobs +%patch15 -p1 -b .dst +%patch17 -p1 -b .aborted-jobs + +%build +# patch9 touches configure.in +autoconf +# clean old pregenerated files +rm -f lex.yy.* y.tab.* +%configure --with-atspool=%{_localstatedir}/spool/at/spool \ + --with-jobdir=%{_localstatedir}/spool/at \ + --with-daemon_username=root \ + --with-daemon_groupname=root \ + --with-selinux \ +%if %{with pam} + --with-pam +%endif + +make + +%install +make install \ + DAEMON_USERNAME=`id -nu`\ + DAEMON_GROUPNAME=`id -ng` \ + DESTDIR=%{buildroot}\ + sbindir=%{buildroot}%{_prefix}/sbin\ + bindir=%{buildroot}%{_bindir}\ + prefix=%{buildroot}%{_prefix}\ + exec_prefix=%{buildroot}%{_prefix}\ + docdir=%{buildroot}/usr/doc\ + mandir=%{buildroot}%{_mandir}\ + etcdir=%{buildroot}%{_sysconfdir} \ + ATJOB_DIR=%{buildroot}%{_localstatedir}/spool/at \ + ATSPOOL_DIR=%{buildroot}%{_localstatedir}/spool/at/spool \ + INSTALL_ROOT_USER=`id -nu` \ + INSTALL_ROOT_GROUP=`id -nu`; + +echo > %{buildroot}%{_sysconfdir}/at.deny +mkdir docs +cp %{buildroot}/%{_prefix}/doc/at/* docs/ + +mkdir -p %{buildroot}%{_sysconfdir}/pam.d +install -m 644 %{SOURCE1} %{buildroot}%{_sysconfdir}/pam.d/atd + +mkdir -p %{buildroot}%{_sysconfdir}/rc.d/init.d +install -m 755 %{SOURCE2} %{buildroot}%{_sysconfdir}/rc.d/init.d/atd + +mkdir -p %{buildroot}/etc/sysconfig +install -m 644 %{SOURCE3} %{buildroot}/etc/sysconfig/atd + +# install systemd initscript +mkdir -p %{buildroot}/%{_unitdir}/ +install -m 644 %{SOURCE5} %{buildroot}/%{_unitdir}/atd.service + +# remove unpackaged files from the buildroot +rm -r %{buildroot}%{_prefix}/doc + +%check +make test + +%post +touch %{_localstatedir}/spool/at/.SEQ +chmod 600 %{_localstatedir}/spool/at/.SEQ +chown daemon:daemon %{_localstatedir}/spool/at/.SEQ +%systemd_post atd.service + +%preun +%systemd_preun atd.service + +%postun +%systemd_postun_with_restart atd.service + +%triggerun -- at < 3.1.12-6 +# Save the current service runlevel info +# User must manually run systemd-sysv-convert --apply atd +# to migrate them to systemd targets +/usr/bin/systemd-sysv-convert --save atd + +# The package is allowed to autostart: +/bin/systemctl enable atd.service >/dev/null 2>&1 + +/sbin/chkconfig --del atd >/dev/null 2>&1 || : +/bin/systemctl try-restart atd.service >/dev/null 2>&1 || : +/bin/systemctl daemon-reload >/dev/null 2>&1 || : + +%triggerpostun -n at-sysvinit -- at < 3.1.12-9 +/sbin/chkconfig --add atd >/dev/null 2>&1 || : + +%files +%doc docs/* +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/at.deny +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/atd +%attr(0700,daemon,daemon) %dir %{_localstatedir}/spool/at +%attr(0600,daemon,daemon) %verify(not md5 size mtime) %ghost %{_localstatedir}/spool/at/.SEQ +%attr(0700,daemon,daemon) %dir %{_localstatedir}/spool/at/spool +%attr(0644,root,root) %config(noreplace) %{_sysconfdir}/pam.d/atd +%{_sbindir}/atrun +%attr(0755,root,root) %{_sbindir}/atd +%{_mandir}/man*/* +%{_bindir}/batch +%{_bindir}/atrm +%{_bindir}/atq +%attr(4755,root,root) %{_bindir}/at +%attr(0644,root,root) /%{_unitdir}/atd.service + +%files sysvinit +%attr(0755,root,root) %{_initrddir}/atd + +%changelog +* Wed Dec 20 2017 Tomáš Mráz - 3.1.13-22.2 +- fix handling of the aborted jobs (due to possibly + temporary conditions) and avoid flooding the syslog + +* Mon May 23 2016 Tomáš Mráz - 3.1.13-22 +- SIGPIPE should not be ignored in atd (#1338039) + +* Wed Apr 20 2016 Tomáš Mráz - 3.1.13-21 +- correct the DST correction when using UTC time specification (#1328832) +- clear non-job files from at dir and test for write error on fclose + to fix bogus syslog messages + +* Mon Jun 22 2015 Tomáš Mráz - 3.1.13-20 +- build the package with hardening flags (PIE, full RELRO) + +* Fri Oct 3 2014 Tomáš Mráz - 3.1.13-18 +- filter environment variables not acceptable in bash input + +* Fri Jan 24 2014 Daniel Mach - 3.1.13-17 +- Mass rebuild 2014-01-24 + +* Thu Jan 09 2014 Marcela Mašláňová - 3.1.13-16 +- the correct solution is remove smp_flags, they don't work properly on ppc with + the option mpower7 +- Related: rhbz#1048745 + +* Mon Jan 06 2014 Marcela Mašláňová - 3.1.13-15 +- remove old changelogs +- ppc fail to rebuild package +- Resolves: rhbz#1048745 + +* Fri Dec 27 2013 Daniel Mach - 3.1.13-14 +- Mass rebuild 2013-12-27 + +* Thu Jul 11 2013 Marcela Mašláňová - 3.1.13-13 +- rebuild with ? in dist +- Resolves: rhbz#983255 + +* Mon Feb 11 2013 Peter Robinson 3.1.13-12 +- Fix patch to fix FTBFS with gcc 4.8 + +* Wed Nov 14 2012 Marcela Mašláňová - 3.1.13-11 +- fix license field again + +* Thu Nov 1 2012 Marcela Mašláňová - 3.1.13-10 +- fix license field +- fix systemd macros in scriptlets part of the specfile +- fix selinux patch to apply without fuzz=2 + +* Fri Jul 27 2012 Fedora Release Engineering - 3.1.13-9 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Tue Apr 17 2012 Marcela Mašláňová - 3.1.13-8 +- at-3.1.13-mailwithhostname.patch in email mention also hostname address +- at-3.1.13-usePOSIXtimers.patch use POSIX timers, so we won't need + pm-utils hack anymore +- at-3.1.13-help.patch update usage +- systemd-user-sessions.service is used in unit file, so the atd should be + started after almost all services are up and running +- 812682 pam support work with new systemd defaults + +* Thu Jan 12 2012 Fedora Release Engineering - 3.1.13-7 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild