diff --git a/.cvsignore b/.cvsignore index ad3673e..e2923c2 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,2 +1 @@ -at_3.1.8-11.tar.gz at-3.1.10.tar.gz diff --git a/at-3.1.10-dont_fork.patch b/at-3.1.10-dont_fork.patch new file mode 100644 index 0000000..1a23686 --- /dev/null +++ b/at-3.1.10-dont_fork.patch @@ -0,0 +1,59 @@ +--- at-3.1.10/daemon.c.dontfork 2005-08-05 05:16:01.000000000 +0200 ++++ at-3.1.10/daemon.c 2006-09-12 13:53:10.000000000 +0200 +@@ -50,7 +50,8 @@ + + static const char *svnid = "$Id$"; + +-int daemon_debug; ++int daemon_debug = 0; ++int daemon_nofork = 0; + + static int + lock_fd(int fd) +@@ -119,15 +120,18 @@ + (open("/dev/null", O_RDWR) != 2)) { + perr("Error redirecting I/O"); + } ++ } ++ if (daemon_nofork) pid = getpid(); ++ else { + pid = fork(); + if (pid == -1) { + perr("Cannot fork"); + } else if (pid != 0) { + exit(0); + } ++ (void) setsid(); + } + old_umask = umask(S_IWGRP | S_IWOTH); +- (void) setsid(); + + PRIV_START + +--- at-3.1.10/atd.8.in.dontfork 2005-08-29 10:08:51.000000000 +0200 ++++ at-3.1.10/atd.8.in 2006-09-12 13:53:10.000000000 +0200 +@@ -10,6 +10,7 @@ + .IR batch_interval ] + .RB [ -d ] + .RB [ -s ] ++.RB [ -n ] + .SH DESCRIPTION + .B atd + runs jobs queued by +@@ -46,6 +47,9 @@ + is installed as + .B @prefix@/sbin/atrun + for backward compatibility. ++.TP 8 ++.B -n ++Don't fork option. + .SH WARNING + .B atd + won't work if its spool directory is mounted via NFS even if +--- at-3.1.10/daemon.h.dontfork 2005-08-05 05:16:01.000000000 +0200 ++++ at-3.1.10/daemon.h 2006-09-12 13:54:43.000000000 +0200 +@@ -14,3 +14,4 @@ + perr (const char *fmt, ...); + + extern int daemon_debug; ++extern int daemon_nofork; diff --git a/at-3.1.10-fix_no_export.patch b/at-3.1.10-fix_no_export.patch new file mode 100644 index 0000000..5a31416 --- /dev/null +++ b/at-3.1.10-fix_no_export.patch @@ -0,0 +1,84 @@ +--- at-3.1.10/at.c.fix 2006-09-12 13:21:16.000000000 +0200 ++++ at-3.1.10/at.c 2006-09-12 13:20:08.000000000 +0200 +@@ -396,8 +396,9 @@ + 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++; + } +--- at-3.1.10/at.1.in.fix 2006-09-12 13:21:16.000000000 +0200 ++++ at-3.1.10/at.1.in 2006-09-12 13:10:28.000000000 +0200 +@@ -42,8 +42,7 @@ + and + .B batch + read commands from standard input or a specified file which are to +-be executed at a later time, using +-.BR /bin/sh . ++be executed at a later time. + .TP 8 + .BR at + executes commands at a specified time. +@@ -244,8 +243,56 @@ + option argument, which must have the same format as specified for the + .BR touch(1) + utility's +-.B -t ++.B \-t + time option argument ([[CC]YY]MMDDhhmm). ++.SH ENVIRONMENT ++.P ++.TP 8 ++.B SHELL ++The value of the SHELL environment variable at the time of ++.B at ++invocation will determine which shell is used to execute the ++.B at ++job commands. If SHELL is unset when ++.B at ++is invoked, the user's login shell will be used; otherwise, ++if SHELL is set when ++.B at ++is invoked, it must contain the path of a shell interpreter ++executable that will be used to run the commands at the specified time. ++.P ++.B at ++will record the values of ++environment variables present at time of ++.B at ++invocation. When the commands are run at the specified time, ++.B at ++will restore these variables to their recorded values . ++These variables are excluded from this processing and are never ++set by ++.B at ++when the commands are run : ++.br ++.BI TERM, ++.BI DISPLAY, ++.BI SHELLOPTS, ++.BI _, ++.BI PPID, ++.BI BASH_VERSINFO, ++.BI EUID, ++.BI UID, ++.BI GROUPS. ++.br ++If the user submitting the ++.B at ++job is not the super-user, variables that alter the behaviour of the ++loader ++.BR ld.so(8), ++such as ++.B LD_LIBRARY_PATH ++, cannot be recorded and restored by ++.B at . ++.P + .SH FILES + .I @ATJBD@ + .br diff --git a/at-3.1.10-instinet.patch b/at-3.1.10-instinet.patch new file mode 100644 index 0000000..fc480cb --- /dev/null +++ b/at-3.1.10-instinet.patch @@ -0,0 +1,245 @@ +--- at-3.1.10/atd.c.instinet 2006-09-12 11:01:10.000000000 +0200 ++++ at-3.1.10/atd.c 2006-09-12 11:24:49.000000000 +0200 +@@ -102,7 +102,7 @@ + static const char *svnid = "$Id$"; + static double load_avg = LOADAVG_MX; + static time_t now; +-static time_t last_chg; ++//static time_t last_chg; + static int nothing_to_do; + unsigned int batch_interval; + static int run_as_daemon = 0; +@@ -197,7 +197,7 @@ + #endif + + static void +-run_file(const char *filename, uid_t uid, gid_t gid) ++run_file(char *filename, uid_t uid, gid_t gid) + { + /* Run a file by by spawning off a process which redirects I/O, + * spawns a subshell, then waits for it to complete and sends +@@ -208,7 +208,7 @@ + char jobbuf[9]; + char *mailname = NULL; + int mailsize = 128; +- char *newname; ++ char newname[256]; + FILE *stream; + int send_mail = 0; + struct stat buf, lbuf; +@@ -242,11 +242,17 @@ + + sprintf(jobbuf, "%8lu", jobno); + +- if ((newname = malloc(strlen(filename) + 1)) == NULL) +- pabort("Job %8lu : out of virtual memory", jobno); ++ if( strlen( filename ) >= sizeof( newname ) - 1 ) ++ pabort("File name too long: %s", filename ); + + strcpy(newname, filename); + ++ newname[0] = '!'; ++ ++ if( rename( filename, newname ) < 0 ) ++ perr( "Error renaming job file." ); ++ ++ filename[0] = '!'; + newname[0] = '='; + + /* We try to make a hard link to lock the file. If we fail, then +@@ -264,14 +270,15 @@ + } + } + /* If something goes wrong between here and the unlink() call, +- * the job gets restarted as soon as the "=" entry is cleared +- * by the main atd loop. +- */ ++ * the job will remain in the "!" queue. ++ * no point in retrying, and need glaring proof that something went wrong ++ */ + + pid = fork(); +- if (pid == -1) ++ if (pid == -1) { ++ unlink(newname); + perr("Cannot fork"); +- ++ } + else if (pid != 0) { + free(mailname); + free(newname); +@@ -284,6 +291,7 @@ + + pentry = getpwuid(uid); + if (pentry == NULL) { ++ unlink(newname); + pabort("Userid %lu not found - aborting job %8lu (%.500s)", + (unsigned long) uid, jobno, filename); + } +@@ -293,35 +301,43 @@ + + PRIV_END + +- if (stream == NULL) ++ if (stream == NULL) { ++ unlink( newname ); + perr("Cannot open input file"); +- +- if ((fd_in = dup(fileno(stream))) < 0) ++ } ++ if ((fd_in = dup(fileno(stream))) < 0) { ++ unlink( newname ); + perr("Error duplicating input file descriptor"); +- +- if (fstat(fd_in, &buf) == -1) ++ } ++ if (fstat(fd_in, &buf) == -1) { ++ unlink( newname ); + perr("Error in fstat of input file descriptor"); +- +- if (lstat(filename, &lbuf) == -1) ++ } ++ if (lstat(filename, &lbuf) == -1) { ++ unlink( newname ); + perr("Error in fstat of input file"); +- +- if (S_ISLNK(lbuf.st_mode)) ++ } ++ if (S_ISLNK(lbuf.st_mode)) { ++ unlink( newname ); + perr("Symbolic link encountered in job %8lu (%.500s) - aborting", + jobno, filename); +- ++ } + if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) || + (lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) || +- (lbuf.st_size != buf.st_size)) ++ (lbuf.st_size != buf.st_size)) { ++ unlink( newname ); + perr("Somebody changed files from under us for job %8lu (%.500s) - " + "aborting", jobno, filename); +- ++ } + if (buf.st_nlink > 2) { ++ unlink( newname ); + perr("Somebody is trying to run a linked script for job %8lu (%.500s)", + jobno, filename); + } +- if ((fflags = fcntl(fd_in, F_GETFD)) < 0) ++ if ((fflags = fcntl(fd_in, F_GETFD)) < 0) { ++ unlink( newname ); + perr("Error in fcntl"); +- ++ } + fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC); + + /* +@@ -335,28 +351,44 @@ + mailsize ); + + if (fscanf(stream, fmt, +- &nuid, &ngid, mailname, &send_mail) != 4) ++ &nuid, &ngid, mailname, &send_mail) != 4) { ++ unlink( newname ); + pabort("File %.500s is in wrong format - aborting", + filename); ++ } + +- if (mailname[0] == '-') ++ if (mailname[0] == '-') { ++ unlink( newname ); + pabort("illegal mail name %.300s in job %8lu (%.300s)", mailname, + jobno, filename); +- +- if (nuid != uid) ++ } ++ if (nuid != uid) { ++ unlink( newname ); + pabort("Job %8lu (%.500s) - userid %d does not match file uid %d", + jobno, filename, nuid, uid); +- ++ } ++ if (ngid != gid) { ++ unlink( newname ); ++ pabort("Job %8lu %.500s - groupid %d does not match file gid %d", ++ jobno, filename, ngid, gid); ++ } + /* We are now committed to executing this script. Unlink the + * original. + */ + + unlink(filename); + ++ /* If we bail out from now on, the job gets stuck in "=" ++ * The main loop should take care of that. ++ */ ++ + fclose(stream); ++ + if (chdir(ATSPOOL_DIR) < 0) + perr("Cannot chdir to " ATSPOOL_DIR); + ++ filename[0] = queue; ++ + /* Create a file to hold the output of the job we are about to run. + * Write the mail header. Complain in case + */ +@@ -466,19 +498,19 @@ + #endif + + /* Send mail. Unlink the output file after opening it, so it +- * doesn't hang around after the run. ++ * doesn't hang around after the run (if we are to send mail). + */ +- stat(filename, &buf); +- if (open(filename, O_RDONLY) != STDIN_FILENO) +- perr("Open of jobfile failed"); +- +- unlink(filename); ++ if( send_mail != -1 ) { ++ stat(filename, &buf); ++ if (open(filename, O_RDONLY) != STDIN_FILENO) ++ perr("Open of jobfile failed"); ++ unlink(filename); ++ } + + /* The job is now finished. We can delete its input file. + */ + chdir(ATJOB_DIR); + unlink(newname); +- free(newname); + + if (((send_mail != -1) && (buf.st_size != size)) || (send_mail == 1)) { + +@@ -508,6 +540,8 @@ + exit(EXIT_SUCCESS); + } + ++#define CHECK_INTERVAL_5MIN 300 ++ + static time_t + run_loop() + { +@@ -537,7 +571,7 @@ + * atrun. + */ + +- next_job = now + CHECK_INTERVAL; ++ next_job = now + CHECK_INTERVAL_5MIN; + if (next_batch == 0) + next_batch = now; + +@@ -548,11 +582,11 @@ + + if (stat(".", &buf) == -1) + perr("Cannot stat " ATJOB_DIR); +- ++/* + if (nothing_to_do && buf.st_mtime <= last_chg) + return next_job; + last_chg = buf.st_mtime; +- ++*/ + if ((spool = opendir(".")) == NULL) + perr("Cannot read " ATJOB_DIR); + diff --git a/at-3.1.10-lexer-parser.patch b/at-3.1.10-lexer-parser.patch new file mode 100644 index 0000000..9280a2e --- /dev/null +++ b/at-3.1.10-lexer-parser.patch @@ -0,0 +1,14 @@ +--- at-3.1.10/parsetime.y.parser 2005-08-05 05:31:04.000000000 +0200 ++++ at-3.1.10/parsetime.y 2006-09-07 12:47:45.000000000 +0200 +@@ -55,8 +55,10 @@ + %% + timespec : spec_base + | spec_base inc_or_dec ++ { ++ time_only = 0; ++ } + ; +- + spec_base : date + | time + { diff --git a/at-3.1.10-makefile.patch b/at-3.1.10-makefile.patch new file mode 100644 index 0000000..5fe5f1b --- /dev/null +++ b/at-3.1.10-makefile.patch @@ -0,0 +1,78 @@ +--- at-3.1.10/Makefile.in.makefile 2006-09-12 08:33:38.000000000 +0200 ++++ at-3.1.10/Makefile.in 2006-09-12 08:44:52.000000000 +0200 +@@ -69,13 +69,13 @@ + all: at atd atrun + + at: $(ATOBJECTS) +- $(CC) $(CFLAGS) -o at -pie $(ATOBJECTS) $(LIBS) $(LEXLIB) ++ $(CC) $(CFLAGS) -o at -pie $(ATOBJECTS) $(LIBS) $(LEXLIB) $(PAMLIB) + rm -f $(CLONES) + $(LN_S) -f at atq + $(LN_S) -f at atrm + + atd: $(RUNOBJECTS) +- $(CC) $(CFLAGS) -o atd -pie $(RUNOBJECTS) $(LIBS) $(PAMLIB) ++ $(CC) $(CFLAGS) -o atd -pie $(RUNOBJECTS) $(LIBS) $(SELINUXLIB) $(PAMLIB) + + y.tab.c y.tab.h: parsetime.y + $(YACC) -d parsetime.y +@@ -90,35 +90,38 @@ + $(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)$(ATJOB_DIR) ++ $(INSTALL) -m 755 -d $(IROOT)$(etcdir)/pam.d ++ $(INSTALL) -g $(DAEMON_GROUPNAME) -o $(DAEMON_USERNAME) -m 755 -d $(IROOT) $(ATSPOOL_DIR) ++ chmod 700 $(IROOT)$(ATSPOOL_DIR) $(IROOT)$(ATJOB_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 -s at $(IROOT)$(bindir) ++ chown $(DAEMON_USERNAME):$(DAEMON_GROUPNAME) $(IROOT)$(ATJOB_DIR) $(IROOT)$(ATSPOOL_DIR) ++ 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 -s 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 -s 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) -m 755 -d $(IROOT)$(man1dir) ++ $(INSTALL) -m 755 -d $(IROOT)$(man5dir) ++ $(INSTALL) -m 755 -d $(IROOT)$(man8dir) ++ $(INSTALL) -m 755 -s 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/at-3.1.10-man-timespec-path.patch b/at-3.1.10-man-timespec-path.patch new file mode 100644 index 0000000..53b0425 --- /dev/null +++ b/at-3.1.10-man-timespec-path.patch @@ -0,0 +1,11 @@ +--- at-3.1.10/at.1.in.path 2005-08-29 10:09:24.000000000 +0200 ++++ at-3.1.10/at.1.in 2006-09-07 11:07:21.000000000 +0200 +@@ -110,7 +110,7 @@ + .B at 1am tomorrow. + .PP + The exact 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 , diff --git a/at-3.1.10-pam.patch b/at-3.1.10-pam.patch new file mode 100644 index 0000000..0df6797 --- /dev/null +++ b/at-3.1.10-pam.patch @@ -0,0 +1,481 @@ +--- at-3.1.10/atd.c.pam 2006-09-12 15:01:55.000000000 +0200 ++++ at-3.1.10/atd.c 2006-09-12 15:26:49.000000000 +0200 +@@ -73,6 +73,42 @@ + #ifdef HAVE_UNISTD_H + #include + #endif ++#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. ++ */ ++ setreuid(daemon_uid, daemon_uid); ++ setregid(daemon_gid, daemon_gid); ++ ++# define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \ ++ fprintf(stderr,"PAM authentication failure: %s\n",pam_strerror(pamh, retcode)); \ ++ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT ); ++ pam_close_session(pamh,PAM_SILENT); \ ++ pam_end(pamh, retcode); \ ++ setregid(gid,egid); \ ++ setreuid(uid,euid); \ ++ return(0); \ ++ } ++ 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; ++ retcode = pam_open_session(pamh, PAM_SILENT); ++ PAM_FAIL_CHECK; ++ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); ++ PAM_FAIL_CHECK; ++ ++ pam_close_session(pamh,PAM_SILENT); ++ pam_end(pamh, PAM_ABORT); ++ ++ setregid(gid,egid); ++ setreuid(uid,euid); ++ ++#endif ++ + + /* Local headers */ + +@@ -83,6 +119,10 @@ + #include "getloadavg.h" + #endif + ++#ifndef LOG_ATD ++#define LOG_ATD LOG_DAEMON ++#endif ++ + /* Macros */ + + #define BATCH_INTERVAL_DEFAULT 60 +@@ -196,6 +236,19 @@ + #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(char *filename, uid_t uid, gid_t gid) + { +@@ -420,6 +473,8 @@ + PAM_FAIL_CHECK; + retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); + PAM_FAIL_CHECK; ++ closelog(); ++ openlog("atd", LOG_PID, LOG_ATD); + PRIV_END + #endif + +@@ -434,6 +489,14 @@ + 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. +@@ -455,8 +518,6 @@ + if (chdir(ATJOB_DIR) < 0) + perr("Cannot chdir to " ATJOB_DIR); + +- PRIV_START +- + nice((tolower((int) queue) - 'a' + 1) * 2); + + if (initgroups(pentry->pw_name, pentry->pw_gid)) +@@ -472,10 +533,93 @@ + perr("Cannot reset signal handler to default"); + + chdir("/"); ++#ifdef WITH_SELINUX ++ if (selinux_enabled>0) { ++ security_context_t user_context=NULL; ++ security_context_t file_context=NULL; ++ int retval=0; ++ struct av_decision avd; ++ char *seuser=NULL; ++ char *level=NULL; ++ ++ if (getseuserbyname(pentry->pw_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", pentry->pw_name); ++ } else { ++ syslog(LOG_ERR, "execle: couldn't get security context for user %s\n", pentry->pw_name); ++ goto out; ++ } ++ } ++ } ++ ++ /* ++ * 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,pentry->pw_name); ++ } else { ++ syslog(LOG_ERR, "Not allowed to set exec context to %s for user %s\n", user_context,pentry->pw_name); ++ goto out; ++ } ++ } ++ ++ if (setexeccon(user_context) < 0) { ++ if (security_getenforce()==1) { ++ ++ perr("Could not set exec context to %s for user %s\n", user_context,pentry->pw_name); ++ } else { ++ syslog(LOG_ERR, "Could not set exec context to %s for user %s\n", user_context,pentry->pw_name); ++ } ++ } ++ out: ++ freecon(user_context); ++ } ++#endif ++ ++ + + if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0) ++ + perr("Exec failed for /bin/sh"); + ++#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 ++ ++#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. +@@ -507,14 +651,43 @@ + unlink(filename); + } + ++#ifdef WITH_PAM ++ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT ); ++ pam_close_session(pamh, PAM_SILENT); ++ pam_end(pamh, PAM_ABORT); ++ closelog(); ++ openlog("atd", LOG_PID, LOG_ATD); ++#endif ++ + /* The job is now finished. We can delete its input file. + */ + chdir(ATJOB_DIR); + unlink(newname); + ++#ifdef ATD_MAIL_PROGRAM + if (((send_mail != -1) && (buf.st_size != size)) || (send_mail == 1)) { +- +- PRIV_START ++ int mail_pid = -1; ++#ifdef WITH_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; ++ retcode = pam_open_session(pamh, PAM_SILENT); ++ PAM_FAIL_CHECK; ++ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); ++ PAM_FAIL_CHECK; ++ /* PAM has now re-opened our log to auth.info ! */ ++ 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)) + perr("Cannot delete saved userids"); +@@ -527,16 +700,81 @@ + + chdir ("/"); + +-#if defined(SENDMAIL) +- execl(SENDMAIL, "sendmail", mailname, (char *) NULL); +-#else +-/*#error "No mail command specified."*/ +- perr("No mail command specified."); ++#ifdef WITH_SELINUX ++ if (selinux_enabled>0) { ++ security_context_t user_context=NULL; ++ security_context_t file_context=NULL; ++ int retval=0; ++ struct av_decision avd; ++ ++ if (get_default_context(pentry->pw_name, NULL, &user_context)) ++ perr("execle: couldn't get security context for user %s\n", pentry->pw_name); ++ /* ++ * 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,pentry->pw_name); ++ } else { ++ syslog(LOG_ERR, "Not allowed to set exec context to %s for user %s\n", user_context,pentry->pw_name); ++ goto out; ++ } ++ } ++ ++ if (setexeccon(user_context) < 0) { ++ if (security_getenforce()==1) { ++ perr("Could not set exec context to %s for user %s\n", user_context,pentry->pw_name); ++ } else { ++ syslog(LOG_ERR, "Could not set exec context to %s for user %s\n", user_context,pentry->pw_name); ++ } ++ } ++ freecon(user_context); ++ } ++#endif ++ ++ execl(ATD_MAIL_PROGRAM, ATD_MAIL_NAME, mailname, (char *) NULL); ++ perr("Exec failed for mail command"); ++ exit(-1); ++#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 +- perr("Exec failed for mail command"); + +- PRIV_END ++ PRIV_END ++ } else ++ if ( mail_pid == -1 ) { ++ perr("fork of mailer failed"); ++ } else { ++ /* Parent */ ++ waitpid(mail_pid, (int *) NULL, 0); ++ ++#ifdef WITH_PAM ++ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT ); ++ pam_close_session(pamh, PAM_SILENT); ++ pam_end(pamh, PAM_ABORT); ++ closelog(); ++ openlog("atd", LOG_PID, LOG_ATD); ++#endif ++ } + } ++#endif + exit(EXIT_SUCCESS); + } + +@@ -736,6 +974,10 @@ + 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. + */ +@@ -752,11 +994,7 @@ + + 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; +--- at-3.1.10/perm.c.pam 2005-08-05 05:16:01.000000000 +0200 ++++ at-3.1.10/perm.c 2006-09-12 15:06:30.000000000 +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 */ + + +@@ -109,18 +117,58 @@ + 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. ++ */ ++ setreuid(daemon_uid, daemon_uid); ++ setregid(daemon_gid, daemon_gid); ++ ++# define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \ ++ fprintf(stderr,"PAM authentication failure: %s\n",pam_strerror(pamh, retcode)); \ ++ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT ); ++ pam_close_session(pamh,PAM_SILENT); \ ++ pam_end(pamh, retcode); \ ++ setregid(gid,egid); \ ++ setreuid(uid,euid); \ ++ return(0); \ ++ } ++ 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; ++ retcode = pam_open_session(pamh, PAM_SILENT); ++ PAM_FAIL_CHECK; ++ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); ++ PAM_FAIL_CHECK; ++ ++ pam_close_session(pamh,PAM_SILENT); ++ pam_end(pamh, PAM_ABORT); ++ ++ setregid(gid,egid); ++ setreuid(uid,euid); ++ ++#endif ++ ++ ++ + allow = user_in_file(ETCDIR "/at.allow", pentry->pw_name); + if (allow==0 || allow==1) + return allow; +--- at-3.1.8/pam_atd.pam 2005-01-25 16:16:41.842416000 -0500 ++++ at-3.1.8/pam_atd 2005-01-25 16:01:10.000000000 -0500 +@@ -0,0 +1,13 @@ ++# ++# The PAM configuration file for the at daemon ++# ++# ++auth sufficient /lib/security/$ISA/pam_rootok.so ++auth required /lib/security/$ISA/pam_stack.so service=system-auth ++auth required pam_env.so ++account required /lib/security/$ISA/pam_stack.so service=system-auth ++session required /lib/security/$ISA/pam_stack.so service=system-auth ++# Sets up user limits, please uncomment and read /etc/security/limits.conf ++# to enable this functionality. ++# session required pam_limits.so ++# +--- at-3.1.10/config.h.in.__ 2006-09-07 18:47:06.000000000 +0200 ++++ at-3.1.10/config.h.in 2006-09-07 18:48:12.000000000 +0200 +@@ -181,3 +181,9 @@ + + #undef HAVE_ATTRIBUTE_NORETURN + #undef HAVE_PAM ++ ++/* Define if you are building with_selinux */ ++#undef WITH_SELINUX ++ ++/* Define if you are building with_pam */ ++#undef WITH_PAM +--- at-3.1.10/configure.in._ 2005-08-05 05:16:02.000000000 +0200 ++++ at-3.1.10/configure.in 2006-09-07 16:21:19.000000000 +0200 +@@ -88,6 +88,9 @@ + if test "$ac_cv_path_SENDMAIL" != "" ; then + AC_DEFINE_UNQUOTED(SENDMAIL,"$ac_cv_path_SENDMAIL") + MAIL_CMD="$ac_cv_path_SENDMAIL" ++#AC_PATH_PROG(GETOPT, getopt, , $PATH:/bin:/usr/bin:/usr/local/bin ) ++#if test "$ac_cv_path_GETOPT" != "" ; then ++#AC_DEFINE_UNQUOTED(GETOPT,"$ac_cv_path_GETOPT") + fi + + AC_SUBST(MAIL_CMD) diff --git a/at-3.1.10-pie.patch b/at-3.1.10-pie.patch new file mode 100644 index 0000000..4087aca --- /dev/null +++ b/at-3.1.10-pie.patch @@ -0,0 +1,27 @@ +--- at-3.1.10/Makefile.in.pie 2006-09-12 08:28:13.000000000 +0200 ++++ at-3.1.10/Makefile.in 2006-09-12 08:30:47.000000000 +0200 +@@ -69,13 +69,13 @@ + all: at atd atrun + + at: $(ATOBJECTS) +- $(CC) $(CFLAGS) -o at $(ATOBJECTS) $(LIBS) $(LEXLIB) ++ $(CC) $(CFLAGS) -o at -pie $(ATOBJECTS) $(LIBS) $(LEXLIB) + rm -f $(CLONES) + $(LN_S) -f at atq + $(LN_S) -f at atrm + + atd: $(RUNOBJECTS) +- $(CC) $(CFLAGS) -o atd $(RUNOBJECTS) $(LIBS) $(PAMLIB) ++ $(CC) $(CFLAGS) -o atd -pie $(RUNOBJECTS) $(LIBS) $(PAMLIB) + + y.tab.c y.tab.h: parsetime.y + $(YACC) -d parsetime.y +@@ -87,7 +87,7 @@ + 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) diff --git a/at-3.1.10-shell.patch b/at-3.1.10-shell.patch new file mode 100644 index 0000000..5a976f0 --- /dev/null +++ b/at-3.1.10-shell.patch @@ -0,0 +1,20 @@ +--- at-3.1.10/at.c.shell 2006-09-12 11:25:31.000000000 +0200 ++++ at-3.1.10/at.c 2006-09-12 12:25:43.000000000 +0200 +@@ -460,6 +460,8 @@ + fprintf(fp, " || {\n\t echo 'Execution directory " + "inaccessible' >&2\n\t exit 1\n}\n"); + ++ fprintf(fp, "${SHELL:-/bin/sh} << `(dd if=/dev/urandom count=200 bs=1 2>/dev/null|LC_ALL=C tr -d -c '[:alnum:]')`\n\n"); ++ + istty = isatty(fileno(stdin)); + if (istty) { + fprintf(stderr, "at> "); +@@ -1037,7 +1039,7 @@ + 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/at-3.1.10-typo.patch b/at-3.1.10-typo.patch new file mode 100644 index 0000000..79d171e --- /dev/null +++ b/at-3.1.10-typo.patch @@ -0,0 +1,56 @@ +--- at-3.1.10/atrun.8.in.typo 2005-08-29 10:08:41.000000000 +0200 ++++ at-3.1.10/atrun.8.in 2006-09-12 10:00:57.000000000 +0200 +@@ -11,7 +11,7 @@ + .B atrun + runs jobs queued by + .BR at(1) . +-It is a shell script containing invoking ++It is a shell script invoking + .B @sbindir@/atd + with the + .I -s +--- at-3.1.10/atd.c.typo 2006-09-12 10:00:57.000000000 +0200 ++++ at-3.1.10/atd.c 2006-09-12 10:07:19.000000000 +0200 +@@ -316,7 +316,7 @@ + "aborting", jobno, filename); + + if (buf.st_nlink > 2) { +- perr("Someboy is trying to run a linked script for job %8lu (%.500s)", ++ perr("Somebody is trying to run a linked script for job %8lu (%.500s)", + jobno, filename); + } + if ((fflags = fcntl(fd_in, F_GETFD)) < 0) +@@ -607,6 +607,7 @@ + * 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; +@@ -623,7 +624,7 @@ + nothing_to_do = 0; + + /* There's a job for later. Note its execution time if it's +- * the earlierst so far. ++ * the earliest so far. + */ + if (run_time > now) { + if (next_job > run_time) { +@@ -641,6 +642,7 @@ + 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; +@@ -683,7 +685,7 @@ + int + main(int argc, char *argv[]) + { +-/* Browse through ATJOB_DIR, checking all the jobfiles wether they should ++/* Browse through ATJOB_DIR, checking all the jobfiles whether they should + * be executed and or deleted. The queue is coded into the first byte of + * the job filename, the date (in minutes since Eon) as a hex number in the + * following eight bytes, followed by a dot and a serial number. A file diff --git a/at-3.1.10-usage.patch b/at-3.1.10-usage.patch new file mode 100644 index 0000000..ec80818 --- /dev/null +++ b/at-3.1.10-usage.patch @@ -0,0 +1,12 @@ +--- at-3.1.10/panic.c.usage 2006-09-07 13:21:23.000000000 +0200 ++++ at-3.1.10/panic.c 2006-09-07 13:24:00.000000000 +0200 +@@ -92,7 +92,8 @@ + /* Print usage and exit. + */ + fprintf(stderr, "Usage: at [-V] [-q x] [-f file] [-mldbv] time\n" +- " at -c job ...\n" ++ " at [-V] [-q x] [-f file] [-m] -t [[CC]YY]MMDDhhmm\n" ++ " at -c job [job...]\n" + " atq [-V] [-q x]\n" + " atrm [-V] job ...\n" + " batch\n"); diff --git a/at-3.1.8-t_option.patch b/at-3.1.8-t_option.patch index d750a48..0bd4e8e 100644 --- a/at-3.1.8-t_option.patch +++ b/at-3.1.8-t_option.patch @@ -1,5 +1,40 @@ ---- at-3.1.10/at.c.t_ 2006-09-12 10:15:56.000000000 +0200 -+++ at-3.1.10/at.c 2006-09-12 10:30:17.000000000 +0200 +--- at-3.1.10/at.1.in.t_opti 2006-09-12 12:48:04.000000000 +0200 ++++ at-3.1.10/at.1.in 2006-09-12 12:45:40.000000000 +0200 +@@ -12,6 +12,16 @@ + .RB [ -mldbv ] + .B TIME + .br ++.B at ++.RB [ -V ] ++.RB [ -q ++.IR queue ] ++.RB [ -f ++.IR file ] ++.RB [ -mldbv ] ++.RB -t ++.IR time_arg ++.br + .B "at -c" + .I job + .RI [ job... ] +@@ -227,6 +237,15 @@ + .B + \-c + cats the jobs listed on the command line to standard output. ++.TP ++.BI \-t " time_arg" ++Submit the job to be run at the time specified by the ++.BI time_arg ++option argument, which must have the same format as specified for the ++.BR touch(1) ++utility's ++.B -t ++time option argument ([[CC]YY]MMDDhhmm). + .SH FILES + .I @ATJBD@ + .br +--- at-3.1.10/at.c.t_ 2006-09-12 10:15:56.000000000 +0200 ++++ at-3.1.10/at.c 2006-09-12 10:30:17.000000000 +0200 @@ -750,6 +750,101 @@ return p; } @@ -102,38 +137,3 @@ int main(int argc, char **argv) { ---- at-3.1.10/at.1.in.t_option 2006-09-12 12:48:04.000000000 +0200 -+++ at-3.1.10/at.1.in 2006-09-12 12:45:40.000000000 +0200 -@@ -12,6 +12,16 @@ - .RB [ -mldbv ] - .B TIME - .br -+.B at -+.RB [ -V ] -+.RB [ -q -+.IR queue ] -+.RB [ -f -+.IR file ] -+.RB [ -mldbv ] -+.RB -t -+.IR time_arg -+.br - .B "at -c" - .I job - .RI [ job... ] -@@ -227,6 +237,15 @@ - .B - \-c - cats the jobs listed on the command line to standard output. -+.TP -+.BI \-t " time_arg" -+Submit the job to be run at the time specified by the -+.BI time_arg -+option argument, which must have the same format as specified for the -+.BR touch(1) -+utility's -+.B -t -+time option argument ([[CC]YY]MMDDhhmm). - .SH FILES - .I @ATJBD@ - .br diff --git a/at.spec b/at.spec index 43ba91c..a819fb2 100644 --- a/at.spec +++ b/at.spec @@ -6,7 +6,7 @@ Summary: Job spooling tools. Name: at Version: 3.1.10 -Release: 1%{?dist} +Release: 2%{?dist} License: GPL Group: System Environment/Daemons Source: http://ftp.debian.org/debian/pool/main/a/at/at-%{major_ver}.tar.gz @@ -31,7 +31,7 @@ Patch20: at-3.1.10-shell.patch #Patch22: at-selinux.patch #Patch22: at-3.1.10-selinux.patch Patch23: at-3.1.10-pie.patch -Patch24: at-3.1.8-t_opti.patch +Patch24: at-3.1.8-t_option.patch Patch25: at-3.1.10-usage.patch Patch26: at-3.1.10-fix_no_export.patch #Patch27: at-3.1.8-pam.patch @@ -201,7 +201,7 @@ fi %attr(4755,root,root) %{_bindir}/at %changelog -* Thu Sep 07 2006 Marcela Maslanova - 3.1.10-1.fc6 +* Tue Oct 24 2006 Marcela Maslanova - 3.1.10-2 - new version from upstream 3.1.10 * Thu Aug 23 2006 Marcela Maslanova - 3.1.8-82.fc6 diff --git a/sources b/sources index 6266f36..2dd5781 100644 --- a/sources +++ b/sources @@ -1,2 +1 @@ -81dbae5162aaa8a398a81424d6631c77 at_3.1.8-11.tar.gz a020a2ec32e1d629c0eef91e5728efad at-3.1.10.tar.gz