Hello community, here is the log from the commit of package at.1130 for openSUSE:12.2:Update checked in at 2012-12-05 13:56:36 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:12.2:Update/at.1130 (Old) and /work/SRC/openSUSE:12.2:Update/.at.1130.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "at.1130", Maintainer is "" Changes: -------- New Changes file: --- /dev/null 2012-11-30 12:21:47.308011256 +0100 +++ /work/SRC/openSUSE:12.2:Update/.at.1130.new/at.changes 2012-12-05 13:56:38.000000000 +0100 @@ -0,0 +1,518 @@ +------------------------------------------------------------------- +Mon Nov 26 18:11:09 UTC 2012 - opensuse@cboltz.de + +- use /etc/sysconfig/atd variables in atd.service (bnc#780259#c4) + +------------------------------------------------------------------- +Thu Sep 13 21:24:09 UTC 2012 - opensuse@cboltz.de + +- fix atd.service (bnc#780259) + +------------------------------------------------------------------- +Tue Dec 20 19:56:52 UTC 2011 - coolo@suse.com + +- add autoconf as buildrequire to avoid implicit dependency + +------------------------------------------------------------------- +Tue Dec 20 11:26:55 UTC 2011 - coolo@suse.com + +- remove call to suse_update_config (very old work around) + +------------------------------------------------------------------- +Mon Dec 5 19:19:40 UTC 2011 - crrodriguez@opensuse.org + +- Fix rpmlint warnings + +------------------------------------------------------------------- +Mon Dec 5 19:05:48 UTC 2011 - crrodriguez@opensuse.org + +- Support systemd. + +------------------------------------------------------------------- +Sat Sep 17 13:28:30 UTC 2011 - jengelh@medozas.de + +- Remove redundant tags/sections from specfile +- Use %_smp_mflags for parallel build + +------------------------------------------------------------------- +Fri May 13 07:45:00 UTC 2011 - vcizek@novell.com + +- added missing license to distribution (bnc#693355) + +------------------------------------------------------------------- +Tue Apr 19 07:40:28 UTC 2011 - vcizek@novell.com + +- wrong jobdir mtime handling fixed (bnc#680113) + thanks to Ingo Schwarze + +------------------------------------------------------------------- +Tue Apr 5 15:36:24 UTC 2011 - vcizek@novell.com + +- fixed atd-atrm race condition (bnc#679857) + +------------------------------------------------------------------- +Tue Mar 1 15:33:34 UTC 2011 - vcizek@novell.com + +- fixed bug introduced with at-3.1.8-tomorrow.patch (bnc#672586) + +------------------------------------------------------------------- +Mon Feb 7 16:10:28 CET 2011 - jslaby@suse.de + +- source pm-utils functions in suspend/resume script to avoid + errors + +------------------------------------------------------------------- +Tue Feb 1 09:49:43 UTC 2011 - vcizek@novell.com + +- at now shifts jobs with passed time without a date to tomorrow + (bnc#668485) + +------------------------------------------------------------------- +Wed Nov 10 12:51:25 UTC 2010 - coolo@novell.com + +- own parent directories + +------------------------------------------------------------------- +Tue Sep 28 04:53:33 UTC 2010 - cristian.rodriguez@opensuse.org + +- /etc/at.deny has wrong account name [bnc#632250] + +------------------------------------------------------------------- +Tue Jul 20 20:29:11 UTC 2010 - cristian.rodriguez@opensuse.org + +- wake up atd after suspend [bnc#592349] + +------------------------------------------------------------------- +Sat Jul 17 02:24:46 UTC 2010 - cristian.rodriguez@opensuse.org + +- improve spec file +- Should Recommend smtp_daemon + +------------------------------------------------------------------- +Wed Nov 18 17:18:44 UTC 2009 - mseben@novell.com + +- added pam conversion function (reworked pam.patch) fate#306386 + +------------------------------------------------------------------- +Tue Nov 3 19:09:06 UTC 2009 - coolo@novell.com + +- updated patches to apply with fuzz=0 + +------------------------------------------------------------------- +Thu Aug 27 12:16:43 CEST 2009 - mseben@novell.com + +- closedir.patch renamed to leak-fix.patch and added others fixs + of resource leaks (bnc#533454) + +------------------------------------------------------------------- +Thu Aug 13 20:50:51 UTC 2009 - mseben@novell.com + +- added closedir.patch fix missing call of closedir() (bnc#523346) + +------------------------------------------------------------------- +Thu May 14 15:59:43 CEST 2009 - puzel@suse.cz + +- added at-3.1.8-pam-session-as-root.patch (bnc#329210, bnc#408986) + +------------------------------------------------------------------- +Mon Mar 2 16:52:17 CET 2009 - sebo@suse.de + +- added cleanup_perm.patch to fix permissions for unlink (bnc#478733) + +------------------------------------------------------------------- +Thu Feb 12 14:52:56 CET 2009 - mseben@suse.cz + +- fixed nice level of queues : queue-nice-level.patch [bnc#225463] + +------------------------------------------------------------------- +Thu Jan 8 10:38:35 CET 2009 - prusnak@suse.cz + +- corrected selinux.patch [bnc#463521] + +------------------------------------------------------------------- +Wed Oct 8 18:34:53 CEST 2008 - bwalle@suse.de + +- Fix documentation directory in at(1). + +------------------------------------------------------------------- +Mon Sep 1 13:52:04 CEST 2008 - puzel@suse.cz + +- enabled SELinux support [Fate#303662] + +------------------------------------------------------------------- +Tue Apr 8 17:32:59 CEST 2008 - mrueckert@suse.de + +- add at-3.1.8_massive_batch.patch: (bnc#347126) + properly handle sighup when multiple jobs are submitted at the + same time + +------------------------------------------------------------------- +Fri May 11 15:09:08 CEST 2007 - mrueckert@suse.de + +- remove postfix from the build requires. (#225469) + +------------------------------------------------------------------- +Thu Mar 29 10:37:51 CEST 2007 - meissner@suse.de + +- buildrequires flex,bison + +------------------------------------------------------------------- +Mon Mar 19 17:07:09 CET 2007 - mrueckert@suse.de + +- readd at-3.1.8-pam.diff: (#222563) + The breaking part of the setreuid(daemon_uid,daemon_uid) in + perm.c. uid 25 can not write audit messages. As upstream removed + the pam code in perm.c aswell, we do the same here. + +------------------------------------------------------------------- +Mon Dec 18 18:21:06 CET 2006 - ro@suse.de + +- added sysconfig variables ATD_BATCH_INTERVAL + and ATD_LOADAVG (fate#301318) + +------------------------------------------------------------------- +Tue Nov 28 17:17:39 CET 2006 - mrueckert@suse.de + +- remove at-3.1.8-pam.diff it just breaks at. + +------------------------------------------------------------------- +Tue Nov 21 11:36:25 CET 2006 - ro@suse.de + +- added PRIV_START/END calls around pam_start sections (#222412) + +------------------------------------------------------------------- +Fri Sep 1 14:17:31 CEST 2006 - kukuk@suse.de + +- Add pam_loginuid.so to atd.pamd + +------------------------------------------------------------------- +Wed Jan 25 21:34:30 CET 2006 - mls@suse.de + +- converted neededforbuild to BuildRequires + +------------------------------------------------------------------- +Fri Jan 13 00:09:32 CET 2006 - schwab@suse.de + +- Don't strip binaries. + ++++ 321 more lines (skipped) ++++ between /dev/null ++++ and /work/SRC/openSUSE:12.2:Update/.at.1130.new/at.changes New: ---- at-3.1.8-atrm-race.patch at-3.1.8-bison.patch at-3.1.8-cleanup_perm.patch at-3.1.8-delete_r.patch at-3.1.8-denylist.patch at-3.1.8-documentation-dir.patch at-3.1.8-eal3-manpages.patch at-3.1.8-formatbugs.patch at-3.1.8-jobdir-mtime.patch at-3.1.8-joblist.patch at-3.1.8-leak-fix.patch at-3.1.8-massive_batch.patch at-3.1.8-pam-session-as-root.patch at-3.1.8-pam.patch at-3.1.8-pie.patch at-3.1.8-queue-nice-level.patch at-3.1.8-selinux.patch at-3.1.8-tomorrow.patch at-3.1.8-ttime.patch at-3.1.8.patch at.changes at.sleep at.spec at_3.1.8-11.tar.gz atd.init atd.pamd atd.service sysconfig.atd ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ at.spec ++++++ # # spec file for package at # # Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # Name: at BuildRequires: autoconf BuildRequires: bison BuildRequires: flex BuildRequires: libselinux-devel BuildRequires: pam-devel Url: ftp://ftp.debian.org/debian/pool/main/a/at Version: 3.1.8 Release: 0 Summary: A Job Manager License: GPL-2.0+ Group: System/Daemons Source: at_3.1.8-11.tar.gz Source1: atd.init Source2: atd.pamd Source3: sysconfig.atd Source4: at.sleep Source5: http://0pointer.de/public/systemd-units/atd.service Patch0: %{name}-%{version}.patch Patch1: %{name}-%{version}-bison.patch Patch2: %{name}-%{version}-delete_r.patch Patch3: %{name}-%{version}-ttime.patch Patch4: %{name}-%{version}-joblist.patch Patch5: %{name}-%{version}-selinux.patch Patch6: %{name}-%{version}-pie.patch Patch7: %{name}-%{version}-eal3-manpages.patch Patch8: %{name}-%{version}-formatbugs.patch Patch9: %{name}-%{version}-pam.patch Patch10: %{name}-%{version}-massive_batch.patch Patch11: %{name}-%{version}-documentation-dir.patch Patch12: %{name}-%{version}-queue-nice-level.patch # PATCH-FIX-UPSTREAM cleanup_perm fix permissions for unlink (bnc#478733) Patch13: %{name}-%{version}-cleanup_perm.patch # PATCH-FIX-UPSTREAM pam-session-as-root (bnc#408986, bnc#239210) Patch14: %{name}-%{version}-pam-session-as-root.patch # PATCH-FIX-UPSTREAM clean-up opened descriptors (bnc#533454, bnc#523346) Patch15: %{name}-%{version}-leak-fix.patch #PATCH-FIX-OPENSUSE add proper system users to the deny list Patch16: at-3.1.8-denylist.patch #PATCH-FIX-UPSTREAM plan jobs with past time to tomorrow (bnc#672586) Patch17: %{name}-%{version}-tomorrow.patch #PATCH-FIX-UPSTREAM race condition of atrm against job execution (bnc#679857) Patch18: %{name}-%{version}-atrm-race.patch #PATCH-FIX-UPSTREAM wrong mtime handling of jobdir (bnc#680113) Patch19: %{name}-%{version}-jobdir-mtime.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build PreReq: %{_sbindir}/useradd %{_sbindir}/groupadd %fillup_prereq %insserv_prereq PreReq: permissions Recommends: smtp_daemon %if 0%{?suse_version} > 1140 BuildRequires: systemd %{?systemd_requires} %define has_systemd 1 %endif %description This program allows you to run jobs at specified times. %prep %setup -q %patch0 %patch1 %patch2 %patch3 %patch4 %patch5 %patch6 %patch7 %patch8 %patch9 %patch10 %patch11 %patch12 %patch13 %patch14 %patch15 %patch16 %patch17 -p1 %patch18 %patch19 %build rm -fv y.tab.c y.tab.h lex.yy.c lex.yy.o y.tab.o autoconf export SENDMAIL=%{_sbindir}/sendmail %configure \ --with-pam \ --with-selinux \ --with-daemon_username=at \ --with-daemon_groupname=at make %{?_smp_mflags} %install mkdir -p $RPM_BUILD_ROOT/etc/{init.d,pam.d} mkdir -p $RPM_BUILD_ROOT/usr/{bin,sbin,share/man/man{1,5,8}} mkdir -p $RPM_BUILD_ROOT/var/adm/fillup-templates export CFLAGS="$RPM_OPT_FLAGS" export SENDMAIL=%{_sbindir}/sendmail make install IROOT=$RPM_BUILD_ROOT # Don't install docs here in this way mkdir docs mv $RPM_BUILD_ROOT/%{_prefix}/doc/at/* docs/ install %SOURCE1 $RPM_BUILD_ROOT/etc/init.d/atd ln -sf ../../etc/init.d/atd $RPM_BUILD_ROOT%{_sbindir}/rcatd install -m644 %SOURCE2 $RPM_BUILD_ROOT/etc/pam.d/atd install -m644 %SOURCE3 $RPM_BUILD_ROOT/var/adm/fillup-templates %{__install} -D -m 0755 %{S:4} %{buildroot}%{_sysconfdir}/pm/sleep.d/99%{name} %if 0%{?has_systemd} install -D -m 0644 %{S:5} %{buildroot}%{_unitdir}/atd.service %endif %pre %{_sbindir}/groupadd -g 25 -o -r at 2> /dev/null || : %{_sbindir}/useradd -r -o -g at -u 25 -s /bin/bash -c "Batch jobs daemon" -d /var/spool/atjobs at 2> /dev/null || : %if 0%{?has_systemd} %service_add_pre atd.service %endif %preun %stop_on_removal atd %if 0%{?has_systemd} %service_del_preun atd.service %endif %post # update hack # the rcscript used to be /etc/init.d/at if [ -f etc/init.d/at ] ; then rm -f etc/init.d/at %{insserv_cleanup} fi %{fillup_and_insserv -n atd atd } %set_permissions /usr/bin/at %verifyscript %verify_permissions -e /usr/bin/at %if 0%{?has_systemd} %service_add_post atd.service %endif %postun %restart_on_update atd %insserv_cleanup %if 0%{?has_systemd} %service_del_postun atd.service %endif %files %defattr(-,root,root) %doc Problems Copyright COPYING README ChangeLog timespec %config(noreplace) /etc/at.deny %dir %{_sysconfdir}/pm %dir %{_sysconfdir}/pm/sleep.d %config %{_sysconfdir}/pm/sleep.d/99%{name} %{_sbindir}/rcatd %config /etc/init.d/atd %config %attr(644,root,root) /etc/pam.d/atd %verify(not mode) %attr(4750,root,trusted) %{_bindir}/at %{_bindir}/atq %{_bindir}/atrm %{_bindir}/batch %{_mandir}/man?/* %{_sbindir}/atd %{_sbindir}/atrun %attr(700,at,at) %dir /var/spool/atspool %attr(700,at,at) %dir /var/spool/atjobs %attr(600,at,at) /var/spool/atjobs/.SEQ /var/adm/fillup-templates/sysconfig.atd %if 0%{?has_systemd} %{_unitdir}/atd.service %endif %changelog ++++++ at-3.1.8-atrm-race.patch ++++++ Copyright (c) 2011 Ingo Schwarze <ischwarze@astaro.com> This patch is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. --- atd.c 2011-02-25 12:40:46.000000000 +0100 +++ atd.c.new 2011-02-25 14:59:44.000000000 +0100 @@ -291,16 +291,16 @@ run_file(const char *filename, uid_t uid newname[0] = '='; /* We try to make a hard link to lock the file. If we fail, then - * somebody else has already locked it (a second atd?); log the + * somebody else has already locked or deleted it; log the * fact and return. */ if (link(filename, newname) == -1) { - if (errno == EEXIST) { - syslog(LOG_WARNING, "trying to execute job %.100s twice",filename); - return; - } else { - perr("Can't link execution file"); - } + syslog(LOG_WARNING, + (errno == EEXIST ? "trying to execute job %.100s twice" + : "Can't link execution file %.100s: %m"), + filename); + free(newname); + return; } /* If something goes wrong between here and the unlink() call, * the job gets restarted as soon as the "=" entry is cleared ++++++ at-3.1.8-bison.patch ++++++ --- parsetime.y.orig +++ parsetime.y @@ -63,6 +63,7 @@ now : NOW time_or_not : time | + ; time : hr24clock_hr_min | hr24clock_hr_min timezone_name @@ -112,6 +113,7 @@ date : month_name day_number inc_or_dec : increment | decrement + ; increment : '+' inc_number inc_period { @@ -287,6 +289,8 @@ month_number : INT free($1); } } + ; + day_number : INT { exectm.tm_mday = -1; ++++++ at-3.1.8-cleanup_perm.patch ++++++ --- panic.c.orig +++ panic.c @@ -58,8 +58,11 @@ panic(char *a) /* Something fatal has happened, print error message and exit. */ fprintf(stderr, "%s: %s\n", namep, a); - if (fcreated) + if (fcreated){ + PRIV_START unlink(atfile); + PRIV_END + } exit(EXIT_FAILURE); } ++++++ at-3.1.8-delete_r.patch ++++++ --- at.1.in.orig +++ at.1.in @@ -9,7 +9,7 @@ at, batch, atq, atrm - queue, examine o .IR queue ] .RB [ -f .IR file ] -.RB [ -mldbv ] +.RB [ -mldrbv ] .B TIME .br .B "at -c" @@ -219,8 +219,8 @@ rather than standard input. Is an alias for .B atq. .TP -.B -d -Is an alias for +.B -d, -r +Are aliases for .B atrm. .TP .TP --- at.c.orig +++ at.c @@ -692,7 +692,7 @@ main(int argc, char **argv) char *pgm; int program = AT; /* our default program */ - char *options = "q:f:MmvldhVc"; /* default options for at */ + char *options = "q:f:MmvldrhVc"; /* default options for at */ int disp_version = 0; time_t timer; struct passwd *pwe; @@ -765,6 +765,7 @@ main(int argc, char **argv) break; case 'd': + case 'r': if (program != AT) usage(); --- panic.c.orig +++ panic.c @@ -92,6 +92,7 @@ usage(void) /* Print usage and exit. */ fprintf(stderr, "Usage: at [-V] [-q x] [-f file] [-m] time\n" + " at [-V] -r job [job ...]\n" " atq [-V] [-q x]\n" " atrm [-V] [-q x] job ...\n" " batch [-V] [-f file] [-m]\n"); ++++++ at-3.1.8-denylist.patch ++++++ --- at.deny.orig +++ at.deny @@ -1,24 +1,12 @@ -alias -backup +root bin daemon -ftp -games -gnats -guest -irc lp mail +news +uucp +games man +wwwrun +ftp nobody -operator -proxy -qmaild -qmaill -qmailp -qmailq -qmailr -qmails -sync -sys -www-data ++++++ at-3.1.8-documentation-dir.patch ++++++ --- at.1.in.orig +++ at.1.in @@ -117,7 +117,7 @@ and to run a job at 1am tomorrow, you wo .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/packages/at/timespec . .PP For both .BR at " and " batch , ++++++ at-3.1.8-eal3-manpages.patch ++++++ --- /dev/null +++ at.allow.5 @@ -0,0 +1,36 @@ +.Id $Id: at.allow.5,v 1.1 1997/09/28 20:00:28 ig25 Exp $ +.TH AT.ALLOW 5 "Sep 1997" "" "Linux Programmer's Manual" +.SH NAME +at.allow, at.deny - determine who can submit jobs via at or batch +.SH DESCRIPTION +The +.I /etc/at.allow +and +.I /etc/at.deny +files determine which user can submit commands for later execution via +.BR at (1) +or +.BR batch (1) . +.PP +The format of the files is a list of usernames, one on each line. Whitespace +is not permitted. +.PP +The superuser may always use +.BR at . +.PP +If the file +.I /etc/at.allow +exists, only usernames mentioned in it are allowed to use +.BR at . +.PP +If +.I /etc/at.allow +does not exist, +.I /etc/at.deny +is checked. +.SH "SEE ALSO" +.BR at (1), +.BR atrun (1), +.BR cron (8), +.BR crontab (1), +.BR atd (8). --- /dev/null +++ at.deny.5 @@ -0,0 +1,36 @@ +.Id $Id: at.allow.5,v 1.1 1997/09/28 20:00:28 ig25 Exp $ +.TH AT.ALLOW 5 "Sep 1997" "" "Linux Programmer's Manual" +.SH NAME +at.allow, at.deny - determine who can submit jobs via at or batch +.SH DESCRIPTION +The +.I /etc/at.allow +and +.I /etc/at.deny +files determine which user can submit commands for later execution via +.BR at (1) +or +.BR batch (1) . +.PP +The format of the files is a list of usernames, one on each line. Whitespace +is not permitted. +.PP +The superuser may always use +.BR at . +.PP +If the file +.I /etc/at.allow +exists, only usernames mentioned in it are allowed to use +.BR at . +.PP +If +.I /etc/at.allow +does not exist, +.I /etc/at.deny +is checked. +.SH "SEE ALSO" +.BR at (1), +.BR atrun (1), +.BR cron (8), +.BR crontab (1), +.BR atd (8). ++++++ at-3.1.8-formatbugs.patch ++++++ --- atd.c.orig +++ atd.c @@ -293,7 +293,7 @@ run_file(const char *filename, uid_t uid if (buf.st_nlink > 2) { perr("Someboy is trying to run a linked script for job %8lu (%.500s)", - filename); + jobno, filename); } if ((fflags = fcntl(fd_in, F_GETFD)) < 0) perr("Error in fcntl"); --- daemon.h.orig +++ daemon.h @@ -5,12 +5,12 @@ void #ifdef HAVE_ATTRIBUTE_NORETURN __attribute__((noreturn)) #endif -pabort (const char *fmt, ...); +pabort (const char *fmt, ...) __attribute__((__format__(printf,1,2))); void #ifdef HAVE_ATTRIBUTE_NORETURN __attribute__((noreturn)) #endif -perr (const char *fmt, ...); +perr (const char *fmt, ...) __attribute__((__format__(printf,1,2))); extern int daemon_debug; --- panic.h.orig +++ panic.h @@ -26,7 +26,9 @@ void #ifdef HAVE_ATTRIBUTE_NORETURN __attribute__((noreturn)) #endif -perr(const char *a, ...); +perr(const char *a, ...) +__attribute__((__format__(printf,1,2))) +; void #ifdef HAVE_ATTRIBUTE_NORETURN __attribute__((noreturn)) ++++++ at-3.1.8-jobdir-mtime.patch ++++++ Copyright (c) 2009 Ingo Schwarze <ischwarze@astaro.com> This patch is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Index: atd.c =================================================================== --- atd.c.orig +++ atd.c @@ -792,7 +792,7 @@ run_loop() if (stat(".", &buf) == -1) perr("Cannot stat " ATJOB_DIR); - if (nothing_to_do && buf.st_mtime <= last_chg) + if (nothing_to_do && buf.st_mtime == last_chg) return next_job; last_chg = buf.st_mtime; ++++++ at-3.1.8-joblist.patch ++++++ --- at.c.orig +++ at.c @@ -133,8 +133,10 @@ static void sigc(int signo); static void alarmc(int signo); static char *cwdname(void); static void writefile(time_t runtimer, char queue); -static void list_jobs(void); +static void list_jobs(long *, int); static time_t ttime(const char *arg); +static int in_job_list(long, long *, int); +static long *get_job_list(int, char *[], int *); /* Signal catching functions */ @@ -526,8 +528,20 @@ writefile(time_t runtimer, char queue) return; } +static int +in_job_list(long job, long *joblist, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (job == joblist[i]) + return 1; + + return 0; +} + static void -list_jobs() +list_jobs(long *joblist, int len) { /* List all a user's jobs in the queue, by looping through ATJOB_DIR, * or everybody's if we are root @@ -566,6 +580,10 @@ list_jobs() if (sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm) != 3) continue; + /* If jobs are given, only list those jobs */ + if (joblist && !in_job_list(jobno, joblist, len)) + continue; + if (atqueue && (queue != atqueue)) continue; @@ -743,6 +761,28 @@ terr: "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); } +static long * +get_job_list(int argc, char *argv[], int *joblen) +{ + int i, len; + long *joblist; + char *ep; + + joblist = NULL; + len = argc; + if (len > 0) { + joblist = (long *) mymalloc(len * sizeof(*joblist)); + for (i = 0; i < argc; i++) { + errno = 0; + if ((joblist[i] = strtol(argv[i], &ep, 10)) < 0 || + ep == argv[i] || *ep != '\0' || errno) + panic("invalid job number"); + } + } + + *joblen = len; + return joblist; +} /* Global functions */ @@ -769,9 +809,13 @@ main(int argc, char **argv) char *options = "q:f:t:MmvldrhVc"; /* default options for at */ int disp_version = 0; time_t timer; + long *joblist; + int joblen; struct passwd *pwe; struct group *ge; + joblist = NULL; + joblen = 0; timer = -1; RELINQUISH_PRIVS @@ -901,7 +945,9 @@ main(int argc, char **argv) case ATQ: REDUCE_PRIV(daemon_uid, daemon_gid) - list_jobs(); + if (queue_set == 0) + joblist = get_job_list(argc - optind, argv + optind, &joblen); + list_jobs(joblist, joblen); break; case ATRM: --- panic.c.orig +++ panic.c @@ -95,6 +95,8 @@ usage(void) " at [-V] -c job [job ...]\n" " at [-V] -r job [job ...]\n" " at [-V] [-f file] -t [[CC]YY]MMDDhhmm[.SS]\n" + " at [-V] -l -q queuename\n" + " at [-V] -l [job ...]\n" " atq [-V] [-q x]\n" " atrm [-V] [-q x] job ...\n" " batch [-V] [-f file] [-m]\n"); ++++++ at-3.1.8-leak-fix.patch ++++++ --- at.c.orig +++ at.c @@ -600,6 +600,9 @@ list_jobs(long *joblist, int len) else printf("%ld\t%s %c\n", jobno, timestr, queue); } + + closedir(spool); + PRIV_END } @@ -676,6 +679,11 @@ process_jobs(int argc, char **argv, int while ((ch = getc(fp)) != EOF) { putchar(ch); } + PRIV_START + if (fp!=NULL) { + fclose(fp); + } + PRIV_END } break; @@ -687,7 +695,13 @@ process_jobs(int argc, char **argv, int } } } - } + } + + PRIV_START + if (spool!=NULL) { + closedir(spool); + } + PRIV_END } /* delete_jobs */ #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; ++++++ at-3.1.8-massive_batch.patch ++++++ --- atd.c.orig +++ atd.c @@ -137,9 +137,10 @@ static char rcsid[] = "$Id: atd.c,v 1.28 static double load_avg = LOADAVG_MX; static time_t now; static time_t last_chg; -static int nothing_to_do; +static int nothing_to_do = 0; unsigned int batch_interval; static int run_as_daemon = 0; +static int hupped = 0; static volatile sig_atomic_t term_signal = 0; @@ -152,9 +153,10 @@ set_term(int dummy) } RETSIGTYPE -sdummy(int dummy) +set_hup(int dummy) { - /* Empty signal handler */ + hupped = 1; + nothing_to_do = 0; return; } @@ -790,6 +792,7 @@ run_loop() return next_job; last_chg = buf.st_mtime; + hupped = 0; if ((spool = opendir(".")) == NULL) perr("Cannot read " ATJOB_DIR); @@ -1014,7 +1017,7 @@ main(int argc, char *argv[]) */ sigaction(SIGHUP, NULL, &act); - act.sa_handler = sdummy; + act.sa_handler = set_hup; sigaction(SIGHUP, &act, NULL); sigaction(SIGTERM, NULL, &act); @@ -1030,9 +1033,10 @@ main(int argc, char *argv[]) do { now = time(NULL); next_invocation = run_loop(); - if (next_invocation > now) { + if ((next_invocation > now) && (!hupped)) { sleep(next_invocation - now); } + hupped = 0; } while (!term_signal); daemon_cleanup(); exit(EXIT_SUCCESS); ++++++ at-3.1.8-pam-session-as-root.patch ++++++ --- atd.c.orig +++ atd.c @@ -612,11 +612,13 @@ run_file(const char *filename, uid_t uid unlink(filename); #ifdef WITH_PAM + PRIV_START 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); + PRIV_END #endif /* The job is now finished. We can delete its input file. @@ -737,11 +739,13 @@ run_file(const char *filename, uid_t uid waitpid(mail_pid, (int *) NULL, 0); } #ifdef WITH_PAM + PRIV_START 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); + PRIV_END #endif } exit(EXIT_SUCCESS); ++++++ at-3.1.8-pam.patch ++++++ --- Makefile.in.orig +++ Makefile.in @@ -28,6 +28,7 @@ YACC = @YACC@ LEX = @LEX@ LEXLIB = @LEXLIB@ SELINUXLIB = @SELINUXLIB@ +PAMLIB = @PAMLIB@ CC = @CC@ CFLAGS = @CFLAGS@ @@ -73,7 +74,7 @@ at: $(ATOBJECTS) $(LN_S) -f at atrm atd: $(RUNOBJECTS) - $(CC) $(CFLAGS) -o atd -pie $(RUNOBJECTS) $(LIBS) $(SELINUXLIB) + $(CC) $(CFLAGS) -o atd -pie $(RUNOBJECTS) $(LIBS) $(SELINUXLIB) $(PAMLIB) y.tab.c y.tab.h: parsetime.y $(YACC) -d parsetime.y --- atd.c.orig +++ atd.c @@ -93,6 +93,17 @@ int selinux_enabled=0; #include <selinux/av_permissions.h> #endif +#ifdef WITH_PAM +#include <security/pam_appl.h> +static pam_handle_t *pamh = 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_close_session(pamh, PAM_SILENT); \ + pam_end(pamh, retcode); exit(1); \ + } +#endif + /* Local headers */ #include "privs.h" @@ -102,6 +113,10 @@ int selinux_enabled=0; #include "getloadavg.h" #endif +#ifndef LOG_ATD +#define LOG_ATD LOG_DAEMON +#endif + /* Macros */ #define BATCH_INTERVAL_DEFAULT 60 @@ -195,6 +210,47 @@ 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 + +#ifdef WITH_PAM +static int +cron_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + struct pam_message**m = msgm; + int i; + + for (i = 0; i < num_msg; i++) { + switch (m[i]->msg_style) { + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + if (m[i]->msg != NULL) { + syslog (LOG_NOTICE, "%s", m[i]->msg); + } + break; + default: + break; + } + } + return (0); +} + +static const struct pam_conv conv = { + cron_conv, NULL +}; +#endif + static void run_file(const char *filename, uid_t uid, gid_t gid) { @@ -217,6 +273,9 @@ run_file(const char *filename, uid_t uid int ngid; char queue; unsigned long jobno; +#ifdef WITH_PAM + int retcode; +#endif sscanf(filename, "%c%5lx", &queue, &jobno); @@ -361,6 +420,23 @@ run_file(const char *filename, uid_t uid fstat(fd_out, &buf); size = buf.st_size; +#ifdef WITH_PAM + PRIV_START + 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; + closelog(); + openlog("atd", LOG_PID, LOG_ATD); + PRIV_END +#endif + close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); @@ -372,6 +448,16 @@ run_file(const char *filename, uid_t uid else if (pid == 0) { char *nul = NULL; char **nenvp = &nul; +#ifdef WITH_PAM + char **pam_envp=0L; +#endif + + 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. @@ -394,8 +480,6 @@ run_file(const char *filename, uid_t uid 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)) @@ -485,6 +569,24 @@ 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_SELINUX + if (selinux_enabled>0) { + if (setexeccon(NULL) < 0) { + 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. @@ -498,13 +600,6 @@ run_file(const char *filename, uid_t uid */ waitpid(pid, (int *) NULL, 0); -#ifdef WITH_SELINUX - if (selinux_enabled>0) { - if (setexeccon(NULL) < 0) { - perr("Could not reset exec context for user %s\n", pentry->pw_name); - } - } -#endif /* Send mail. Unlink the output file after opening it, so it * doesn't hang around after the run. */ @@ -514,6 +609,14 @@ run_file(const char *filename, uid_t uid 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); @@ -522,7 +625,31 @@ run_file(const char *filename, uid_t uid if (((send_mail != -1) && (buf.st_size != size)) || (send_mail == 1)) { + int mail_pid = -1; + +#ifdef WITH_PAM PRIV_START + 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); + PRIV_END +#endif + + mail_pid = fork(); + + if ( mail_pid == 0 ) + { + PRIV_START if (initgroups(pentry->pw_name, pentry->pw_gid)) perr("Cannot delete saved userids"); @@ -535,6 +662,47 @@ run_file(const char *filename, uid_t uid 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; + + 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); + } + + 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 + #if defined(SENDMAIL) execl(SENDMAIL, "sendmail", mailname, (char *) NULL); #elif defined(MAILC) @@ -546,7 +714,33 @@ run_file(const char *filename, uid_t uid #endif perr("Exec failed for mail command"); - PRIV_END + exit (-1); + +#ifdef WITH_SELINUX + if (selinux_enabled>0) { + if (setexeccon(NULL) < 0) { + perr("Could not resset exec context for user %s\n", pentry->pw_name); + } + } +#endif + + 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 } exit(EXIT_SUCCESS); } @@ -741,7 +935,7 @@ main(int argc, char *argv[]) #ifdef WITH_SELINUX selinux_enabled=is_selinux_enabled(); -#endif +#endif /* We don't need root privileges all the time; running under uid and gid * daemon is fine. */ @@ -758,12 +952,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; run_as_daemon = 1; --- config.h.in.orig +++ config.h.in @@ -187,3 +187,7 @@ /* Define if you are building with_selinux */ #undef WITH_SELINUX + +/* Define if you are building with_pam */ +#undef WITH_PAM + --- configure.in.orig +++ configure.in @@ -323,4 +323,11 @@ AC_CHECK_LIB(selinux, is_selinux_enabled AC_SUBST(SELINUXLIB) AC_SUBST(WITH_SELINUX) +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_OUTPUT(Makefile atrun atd.8 atrun.8 at.1 batch) --- perm.c.orig +++ perm.c @@ -109,14 +109,15 @@ 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; + int retcode=0; - if (uid == 0) + if (euid == 0) return 1; - if ((pentry = getpwuid(uid)) == NULL) { + if ((pentry = getpwuid(euid)) == NULL) { perror("Cannot access user database"); exit(EXIT_FAILURE); } ++++++ at-3.1.8-pie.patch ++++++ --- Makefile.in.orig +++ Makefile.in @@ -67,13 +67,13 @@ LIST = Filelist Filelist.asc 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) $(SELINUXLIB) + $(CC) $(CFLAGS) -o atd -pie $(RUNOBJECTS) $(LIBS) $(SELINUXLIB) y.tab.c y.tab.h: parsetime.y $(YACC) -d parsetime.y @@ -85,7 +85,7 @@ atrun: atrun.in configure .c.o: - $(CC) -c $(CFLAGS) $(DEFS) $*.c + $(CC) -c $(CFLAGS) -fpie $(DEFS) $*.c install: all $(INSTALL) -m 755 -d $(IROOT)$(etcdir) ++++++ at-3.1.8-queue-nice-level.patch ++++++ --- atd.c.orig +++ atd.c @@ -482,7 +482,7 @@ run_file(const char *filename, uid_t uid if (chdir(ATJOB_DIR) < 0) perr("Cannot chdir to " ATJOB_DIR); - nice((tolower((int) queue) - 'a' + 1) * 2); + nice((tolower((int) queue) - 'a' ) ); if (initgroups(pentry->pw_name, pentry->pw_gid)) perr("Cannot delete saved userids"); ++++++ at-3.1.8-selinux.patch ++++++ --- Makefile.in.orig +++ Makefile.in @@ -27,6 +27,7 @@ LN_S = @LN_S@ YACC = @YACC@ LEX = @LEX@ LEXLIB = @LEXLIB@ +SELINUXLIB = @SELINUXLIB@ CC = @CC@ CFLAGS = @CFLAGS@ @@ -72,7 +73,7 @@ at: $(ATOBJECTS) $(LN_S) -f at atrm atd: $(RUNOBJECTS) - $(CC) $(CFLAGS) -o atd $(RUNOBJECTS) $(LIBS) + $(CC) $(CFLAGS) -o atd $(RUNOBJECTS) $(LIBS) $(SELINUXLIB) y.tab.c y.tab.h: parsetime.y $(YACC) -d parsetime.y --- atd.c.orig +++ atd.c @@ -85,6 +85,14 @@ #include <syslog.h> #endif +#ifdef WITH_SELINUX +#include <selinux/selinux.h> +#include <selinux/get_context_list.h> +int selinux_enabled=0; +#include <selinux/flask.h> +#include <selinux/av_permissions.h> +#endif + /* Local headers */ #include "privs.h" @@ -404,6 +412,76 @@ run_file(const char *filename, uid_t uid chdir("/"); +#ifdef WITH_SELINUX + if (selinux_enabled>0) { + security_context_t file_context=NULL; + security_context_t *context_list=NULL; + security_context_t current_con=NULL; + int retval=0, list_count=0, i; + struct av_decision avd; + char *seuser=NULL, *level=NULL; + + if (getseuserbyname(pentry->pw_name, &seuser, &level)) + perr("getseuserbyname FAILED for %s\n", pentry->pw_name); + + if(getcon(¤t_con)) { + free(seuser); + free(level); + perr("Can't get current context"); + } + list_count = get_ordered_context_list_with_level(seuser, level, current_con, &context_list); + freecon(current_con); + free(seuser); + free(level); + if (list_count == -1) { + if (security_getenforce() > 0) + perr("Couldn't get security context for user %s\n", pentry->pw_name); + else + syslog(LOG_WARNING, "Couldn't get security context for user %s, but in permissive mode", 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 (list_count != -1) { + if (fgetfilecon(STDIN_FILENO, &file_context) < 0) { + if (security_getenforce() > 0) + perr("fgetfilecon FAILED for user %s", pentry->pw_name); + } + + for(i = 0; i < list_count; i++) { + retval = security_compute_av(context_list[i], + file_context, + SECCLASS_FILE, + FILE__ENTRYPOINT, + &avd); + if (!retval && ((FILE__ENTRYPOINT & avd.allowed) == FILE__ENTRYPOINT)) + break; + } + } + freecon(file_context); + if (list_count != -1 && (retval || ((FILE__ENTRYPOINT & avd.allowed) != FILE__ENTRYPOINT))) { + if (security_getenforce()==1) + perr("Not allowed to set exec context for user %s\n", pentry->pw_name); + else + syslog(LOG_WARNING, "Not allowed to set exec context for user %s, but in permissive mode", pentry->pw_name); + } + + if ((list_count != -1 || retval) && setexeccon(context_list[i]) < 0) { + if (security_getenforce()==1) { + perr("Could not set exec context to %s for user %s\n", context_list[i], pentry->pw_name); + } else { + syslog(LOG_ERR, "Could not set exec context to %s for user %s\n", context_list[i], pentry->pw_name); + } + } + freeconary(context_list); + } +#endif + if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0) perr("Exec failed for /bin/sh"); @@ -420,6 +498,13 @@ run_file(const char *filename, uid_t uid */ waitpid(pid, (int *) NULL, 0); +#ifdef WITH_SELINUX + if (selinux_enabled>0) { + if (setexeccon(NULL) < 0) { + perr("Could not reset exec context for user %s\n", pentry->pw_name); + } + } +#endif /* Send mail. Unlink the output file after opening it, so it * doesn't hang around after the run. */ @@ -654,6 +739,9 @@ 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. */ --- config.h.in.orig +++ config.h.in @@ -184,3 +184,6 @@ #undef DEFAULT_BATCH_QUEUE #undef HAVE_ATTRIBUTE_NORETURN + +/* Define if you are building with_selinux */ +#undef WITH_SELINUX --- configure.in.orig +++ configure.in @@ -315,4 +315,12 @@ 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_OUTPUT(Makefile atrun atd.8 atrun.8 at.1 batch) ++++++ at-3.1.8-tomorrow.patch ++++++ diff --git a/parsetime.y b/parsetime.y index ef1ff7f..141d792 100644 --- a/parsetime.y +++ b/parsetime.y @@ -379,7 +379,9 @@ parsetime(int argc, char **argv) exectime -= 3600; } } - if (time_only && (currtime > exectime)) { + /* exectime zeroes its seconds, thus we need +60, + * else "now" will be scheduled to tomorrow */ + if (currtime > exectime + 60) { exectime += 24*3600; } return exectime; ++++++ at-3.1.8-ttime.patch ++++++ --- at.1.in.orig +++ at.1.in @@ -9,7 +9,7 @@ at, batch, atq, atrm - queue, examine o .IR queue ] .RB [ -f .IR file ] -.RB [ -mldrbv ] +.RB [ -mldrbvt ] .B TIME .br .B "at -c" @@ -235,6 +235,9 @@ is set; then, it will be "Thu Feb 20 14: .B -c cats the jobs listed on the command line to standard output. +.TP +.B -t time_arg +Specify the time to run in a format compatible with the touch -t time command. .SH FILES .I @ATJBD@ .br --- at.c.orig +++ at.c @@ -28,6 +28,7 @@ #include <sys/types.h> #include <sys/stat.h> +#include <sys/time.h> #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> @@ -133,6 +134,7 @@ static void alarmc(int signo); static char *cwdname(void); static void writefile(time_t runtimer, char queue); static void list_jobs(void); +static time_t ttime(const char *arg); /* Signal catching functions */ @@ -670,6 +672,78 @@ process_jobs(int argc, char **argv, int } } /* delete_jobs */ +#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; + +static time_t +ttime(const char *arg) +{ + /* + * This is pretty much a copy of stime_arg1() from touch.c. I changed + * the return value and the argument list because it's more convenient + * (IMO) to do everything in one place. - Joe Halpin + */ + struct timeval tv[2]; + time_t now; + struct tm *t; + int yearset; + char *p; + + if (gettimeofday(&tv[0], NULL)) + panic("Cannot get current time"); + + /* Start with the current time. */ + now = tv[0].tv_sec; + if ((t = localtime(&now)) == NULL) + panic("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); + t->tm_year *= 100; + yearset = 1; + /* FALLTHROUGH */ + case 10: /* YYMMDDhhmm */ + if (yearset) { + yearset = ATOI2(arg); + t->tm_year += yearset; + } else { + yearset = ATOI2(arg); + t->tm_year = yearset + 2000; + } + t->tm_year -= 1900; /* Convert to UNIX time. */ + /* FALLTHROUGH */ + case 8: /* MMDDhhmm */ + t->tm_mon = ATOI2(arg); + --t->tm_mon; /* Convert from 01-12 to 00-11 */ + t->tm_mday = ATOI2(arg); + t->tm_hour = ATOI2(arg); + t->tm_min = ATOI2(arg); + break; + default: + goto terr; + } + + t->tm_isdst = -1; /* Figure out DST. */ + tv[0].tv_sec = tv[1].tv_sec = mktime(t); + if (tv[0].tv_sec != -1) + return tv[0].tv_sec; + else +terr: + panic( + "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); +} + + /* Global functions */ void * @@ -692,12 +766,13 @@ main(int argc, char **argv) char *pgm; int program = AT; /* our default program */ - char *options = "q:f:MmvldrhVc"; /* default options for at */ + char *options = "q:f:t:MmvldrhVc"; /* default options for at */ int disp_version = 0; time_t timer; struct passwd *pwe; struct group *ge; + timer = -1; RELINQUISH_PRIVS if ((pwe = getpwnam(DAEMON_USERNAME)) == NULL) @@ -781,6 +856,13 @@ main(int argc, char **argv) options = "q:V"; break; + case 't': + if (program != AT) + usage(); + + timer = ttime(optarg); + break; + case 'b': if (program != AT) usage(); @@ -834,10 +916,16 @@ main(int argc, char **argv) break; case AT: - if (argc > optind) { - timer = parsetime(argc - optind, argv + optind); - } else { - timer = 0; + /* + * If timer is > -1, then the user gave the time with -t. In that + * case, it's already been set. If not, set it now. + */ + if (timer == -1) { + if (argc > optind) { + timer = parsetime(argc - optind, argv + optind); + } else { + timer = 0; + } } if (timer == 0) { --- panic.c.orig +++ panic.c @@ -92,7 +92,9 @@ usage(void) /* Print usage and exit. */ fprintf(stderr, "Usage: at [-V] [-q x] [-f file] [-m] time\n" + " at [-V] -c job [job ...]\n" " at [-V] -r job [job ...]\n" + " at [-V] [-f file] -t [[CC]YY]MMDDhhmm[.SS]\n" " atq [-V] [-q x]\n" " atrm [-V] [-q x] job ...\n" " batch [-V] [-f file] [-m]\n"); ++++++ at-3.1.8.patch ++++++ --- Makefile.in.orig +++ Makefile.in @@ -87,37 +87,35 @@ atrun: atrun.in $(CC) -c $(CFLAGS) $(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) -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) -g $(DAEMON_GROUPNAME) -o $(DAEMON_USERNAME) -m 755 -d $(IROOT)$(ATSPOOL_DIR) + $(INSTALL) -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 -m 600 at.deny $(IROOT)$(etcdir)/ - $(INSTALL) -g root -o root -m 4755 -s at $(IROOT)$(bindir) + test -f $(IROOT)$(etcdir)/at.allow || test -f $(IROOT)$(etcdir)/at.deny || $(INSTALL) -m 600 at.deny $(IROOT)$(etcdir)/ + $(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 -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) -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" <atrun.8>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)/ - 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 at.allow.5 $(IROOT)$(man5dir)/ + $(INSTALL) -m 644 at.deny.5 $(IROOT)$(man5dir)/ + $(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* --- Problems.orig +++ Problems @@ -5,7 +5,7 @@ Possible reasons why at may not run for make -f Makefile.old install -- You may not have a user or group 'daemon' on your system. +- You may not have a user or group 'at' on your system. - If you find numerous 'try again' error messages in your syslog files, you have too many processes running; recompile your kernel for a --- README.orig +++ README @@ -23,7 +23,7 @@ The new one is to start up an atd daemon The old one is to put -* * * * 0,5,10,15,20,25,30,35,40,45,50,55 /usr/lib/atrun +* * * * 0,5,10,15,20,25,30,35,40,45,50,55 /usr/sbin/atrun into root's crontab file (or wherever you put the atrun binary; don't forget to start up cron.) --- atd.c.orig +++ atd.c @@ -1,4 +1,4 @@ -/* +/* * atd.c - run jobs queued by at; run with root privileges. * Copyright (C) 1993, 1994, 1996 Thomas Koenig * @@ -22,7 +22,7 @@ #include "config.h" #endif -/* +/* * /usr/bin/mail aka /usr/bin/mailx require the subject to be * specified on the command line instead of reading it from stdin like * /usr/sbin/sendmail does. For now simply disable MAILC and MAILX, @@ -121,14 +121,14 @@ static int run_as_daemon = 0; static volatile sig_atomic_t term_signal = 0; /* Signal handlers */ -RETSIGTYPE +RETSIGTYPE set_term(int dummy) { term_signal = 1; return; } -RETSIGTYPE +RETSIGTYPE sdummy(int dummy) { /* Empty signal handler */ @@ -156,7 +156,7 @@ release_zombie(int dummy) } return; } - + /* Local functions */ @@ -196,7 +196,7 @@ run_file(const char *filename, uid_t uid */ pid_t pid; int fd_out, fd_in; - char mailbuf[9], jobbuf[9]; + char mailbuf[17], jobbuf[9]; char *mailname = NULL; char *newname; FILE *stream; @@ -290,7 +290,12 @@ run_file(const char *filename, uid_t uid if ((fflags = fcntl(fd_in, F_GETFD)) < 0) perr("Error in fcntl"); - fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC); + /* + ** fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC); + ** What's that? This fcntl() removes the CLOSE_ON_EXEC flag. + */ + if(fcntl(fd_in, F_SETFD, fflags | FD_CLOEXEC) < 0) + perr("Error in fcntl"); /* * If the spool directory is mounted via NFS `atd' isn't able to @@ -299,7 +304,7 @@ run_file(const char *filename, uid_t uid * NFS and works with local file systems. It's not clear where * the bug is located. -Joey */ - if (fscanf(stream, "#!/bin/sh\n# atrun uid=%d gid=%d\n# mail %8s %d", + if (fscanf(stream, "#!/bin/sh\n# atrun uid=%d gid=%d\n# mail %16s %d", &nuid, &ngid, mailbuf, &send_mail) != 4) pabort("File %.500s is in wrong format - aborting", filename); @@ -328,7 +333,7 @@ run_file(const char *filename, uid_t uid perr("Cannot chdir to " ATSPOOL_DIR); /* Create a file to hold the output of the job we are about to run. - * Write the mail header. Complain in case + * Write the mail header. Complain in case */ if (unlink(filename) != -1) { @@ -343,7 +348,7 @@ run_file(const char *filename, uid_t uid write_string(fd_out, "Subject: Output from your job "); write_string(fd_out, jobbuf); write_string(fd_out, "\nTo: "); - write_string(fd_out, mailname); + write_string(fd_out, mailname); write_string(fd_out, "\n\n"); fstat(fd_out, &buf); size = buf.st_size; @@ -394,6 +399,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) @@ -408,7 +416,7 @@ run_file(const char *filename, uid_t uid /* We inherited the master's SIGCHLD handler, which does a non-blocking waitpid. So this blocking one will eventually - return with an ECHILD error. + return with an ECHILD error. */ waitpid(pid, (int *) NULL, 0); @@ -557,7 +565,8 @@ run_loop() /* Something went wrong the last time this was executed. * Let's remove the lockfile and reschedule. */ - strncpy(lock_name, dirent->d_name, sizeof(lock_name)); + strncpy(lock_name, dirent->d_name, sizeof(lock_name)-1); + lock_name[sizeof(lock_name)-1] = 0; lock_name[0] = '='; unlink(lock_name); next_job = now; @@ -591,7 +600,8 @@ run_loop() */ run_batch++; if (strcmp(batch_name, dirent->d_name) > 0) { - strncpy(batch_name, dirent->d_name, sizeof(batch_name)); + strncpy(batch_name, dirent->d_name, sizeof(batch_name)-1); + batch_name[sizeof(batch_name)-1] = 0; batch_uid = buf.st_uid; batch_gid = buf.st_gid; batch_queue = queue; --- configure.in.orig +++ configure.in @@ -126,7 +126,7 @@ else fi AC_MSG_CHECKING(location of spool directory) -if test -d /var/spool/atjobs ; then +if test -d /var/spool ; then sp=/var/spool AC_DEFINE(SPOOLDIR, "/var/spool") AC_MSG_RESULT(Using existing /var/spool/at{jobs|run}) ++++++ at.sleep ++++++ #!/bin/bash . $PM_UTILS_LIBDIR/functions case "$1" in hibernate|suspend) stopservice atd ;; thaw|resume) restartservice atd ;; *) ;; esac exit 0 ++++++ atd.init ++++++ #! /bin/sh # Copyright (c) 1995-2002 SuSE GmbH Nuernberg, Germany. # # Author: Kurt Garloff <feedback@suse.de> # # /etc/init.d/at # # and symbolic its link # # /sbin/rcat # # System startup script for the at daemon # ### BEGIN INIT INFO # Provides: at # Required-Start: $remote_fs $time # Required-Stop: $remote_fs # X-UnitedLinux-Default-Enabled: no # Default-Start: 2 3 5 # Default-Stop: 0 1 6 # Description: Start AT batch job daemon ### END INIT INFO ATD_BIN=/usr/sbin/atd test -x $ATD_BIN || exit 5 ATD_CONFIG=/etc/sysconfig/atd test -r $ATD_CONFIG && source /etc/sysconfig/atd # Shell functions sourced from /etc/rc.status: # rc_check check and set local and overall rc status # rc_status check and set local and overall rc status # rc_status -v ditto but be verbose in local rc status # rc_status -v -r ditto and clear the local rc status # rc_failed set local and overall rc status to failed # rc_failed <num> set local and overall rc status to <num><num> # rc_reset clear local rc status (overall remains) # rc_exit exit appropriate to overall rc status . /etc/rc.status # First reset status of this service rc_reset # Return values acc. to LSB for all commands but status: # 0 - success # 1 - generic or unspecified error # 2 - invalid or excess argument(s) # 3 - unimplemented feature (e.g. "reload") # 4 - insufficient privilege # 5 - program is not installed # 6 - program is not configured # 7 - program is not running # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. case "$1" in start) echo -n "Starting service at daemon" ATD_ARGS="" if [ -n "$ATD_BATCH_INTERVAL" ]; then ATD_ARGS="-b $ATD_BATCH_INTERVAL"; fi if [ -n "$ATD_LOADAVG" ]; then ATD_ARGS="$ATD_ARGS -l $ATD_LOADAVG" fi ## Start daemon with startproc(8). If this fails ## the echo return value is set appropriate. # NOTE: startproc return 0, even if service is # already running to match LSB spec. startproc $ATD_BIN $ATD_ARGS # Remember status and be verbose rc_status -v ;; stop) echo -n "Shutting down service at daemon" ## Stop daemon with killproc(8) and if this fails ## set echo the echo return value. killproc -TERM $ATD_BIN # Remember status and be verbose rc_status -v ;; try-restart) ## Stop the service and if this succeeds (i.e. the ## service was running before), start it again. ## Note: try-restart is not (yet) part of LSB (as of 0.7.5) $0 status >/dev/null && $0 restart # Remember status and be quiet rc_status ;; restart) ## Stop the service and regardless of whether it was ## running or not, start it again. $0 stop $0 start # Remember status and be quiet rc_status ;; force-reload) ## Signal the daemon to reload its config. Most daemons ## do this on signal 1 (SIGHUP). ## If it does not support it, restart. echo -n "Reload service at daemon" ## Otherwise: $0 stop && $0 start rc_status ;; reload) ## Like force-reload, but if daemon does not support ## signalling, do nothing (!) # If it supports signalling: echo -n "Reload service at daemon" ## Otherwise if it does not support reload: rc_failed 3 rc_status -v ;; status) echo -n "Checking for at daemon: " ## Check status with checkproc(8), if process is running ## checkproc will return with exit status 0. # Status has a slightly different for the status command: # 0 - service running # 1 - service dead, but /var/run/ pid file exists # 2 - service dead, but /var/lock/ lock file exists # 3 - service not running # NOTE: checkproc returns LSB compliant status values. checkproc $ATD_BIN rc_status -v ;; *) echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}" exit 1 ;; esac rc_exit ++++++ atd.pamd ++++++ # # The PAM configuration file for the at daemon # # auth sufficient pam_rootok.so auth include common-auth account include common-account password include common-password session include common-session ++++++ atd.service ++++++ [Unit] Description=Execution Queue Daemon After=syslog.target [Service] ExecStart=/bin/bash -c '[ -e /etc/sysconfig/atd ] && . /etc/sysconfig/atd; exec /usr/sbin/atd $${ATD_BATCH_INTERVAL:+-b $$ATD_BATCH_INTERVAL} $${ATD_LOADAVG:+-l $$ATD_LOADAVG}' Type=forking [Install] WantedBy=multi-user.target ++++++ sysconfig.atd ++++++ ## Path: System/At ## Description: minimum interval between start of two batch jobs ## Type: string ## Default: "" ## ServiceRestart: atd # # minimum interval between start of two batch jobs, "" for default # ATD_BATCH_INTERVAL="" ## Path: System/At ## Description: load limiting factor for atd ## Type: string ## Default: "" ## ServiceRestart: atd # load limiting factor for atd, "" for default # ATD_LOADAVG="" -- To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org For additional commands, e-mail: opensuse-commit+help@opensuse.org