[Pkg-cron-devel] [pkg-cron] 03/03: Add files missing after merge (?)

Javier Fernandez-Sanguino Pen~a jfs at moszumanska.debian.org
Fri Oct 24 14:34:37 UTC 2014


This is an automated email from the git hooks/post-receive script.

jfs pushed a commit to branch master
in repository pkg-cron.

commit 79fc5634b5af71c1c6a73692c96fe79586b85d87
Author: Javier Fernandez-Sanguino <jfs at debian.org>
Date:   Fri Oct 24 16:27:25 2014 +0200

    Add files missing after merge (?)
---
 debian/README.debian                               |  37 ++
 debian/cron-se.dirs                                |   2 +
 debian/cron-se.install                             |   3 +
 debian/cron-se.overrides                           |   2 +
 debian/cron-se.postinst                            |  21 +
 debian/cron-se.postrm                              |  20 +
 debian/cron-se.preinst                             |  11 +
 debian/cron-se.prerm                               |  12 +
 debian/examples/stats-cron.pl                      | 357 +++++++++++++++
 .../proper_use_streerno_bug_470587.diff            | 153 +++++++
 .../patches-from-bts/sensible_editor_482284.diff   |  12 +
 debian/patches/features/add-helpmsg-to-new-crontab |  62 +++
 .../features/allow-running-cron-in-foreground      |  51 +++
 debian/patches/features/auditlog-support           |  82 ++++
 debian/patches/features/backport-envparser         | 148 +++++++
 debian/patches/features/better-debugging-support   |  90 ++++
 debian/patches/features/confirm-crontab-deletion   |  94 ++++
 debian/patches/features/control-header-output      |  53 +++
 .../patches/features/crontab-refuse-eof-without-nl |  43 ++
 .../patches/features/debian-logging-configuration  | 204 +++++++++
 debian/patches/features/debian-paths-and-commands  |  84 ++++
 debian/patches/features/debian-specific-issues     |  38 ++
 debian/patches/features/dont-die-on-missing-dirs   |  84 ++++
 debian/patches/features/dont-fail-on-missing-MTA   |  58 +++
 debian/patches/features/iso-time-format            |  60 +++
 debian/patches/features/mailcmd-dont-timeout       | 447 +++++++++++++++++++
 debian/patches/features/no-argument-is-stdin       |  23 +
 debian/patches/features/option-log-completed-jobs  |  77 ++++
 debian/patches/features/pam-env-support            |  69 +++
 debian/patches/features/pam-support                |  99 +++++
 debian/patches/features/properly-handle-time-skips | 486 +++++++++++++++++++++
 .../patches/features/recover-from-broken-symlinks  |  65 +++
 debian/patches/features/run-on-reboot              |  56 +++
 .../features/security-make-crontab-setgid-crontab  | 377 ++++++++++++++++
 debian/patches/features/selinux-support            | 304 +++++++++++++
 debian/patches/features/set-contenttype-in-mail    | 131 ++++++
 .../patches/features/support-for-drop.d-directory  | 334 ++++++++++++++
 debian/patches/features/swap-both-uid-and-gid      |  36 ++
 debian/patches/fixes/abort-crontabs-with-errors    |  39 ++
 debian/patches/fixes/allow-crontab-by-users        |  36 ++
 debian/patches/fixes/allow-editors-with-tmpfiles   | 311 +++++++++++++
 debian/patches/fixes/check-for-broken-command      |  26 ++
 debian/patches/fixes/check-for-full-disk           |  53 +++
 debian/patches/fixes/compilation-issues            |  23 +
 .../fixes/correct-flag-setting-in-crontab-entry    |  48 ++
 debian/patches/fixes/correct-use-of-error-messages | 152 +++++++
 debian/patches/fixes/crontab-entry-parsing         |  38 ++
 debian/patches/fixes/crontab-file-parsing          |  59 +++
 debian/patches/fixes/crontab-time-parsing          |  22 +
 .../patches/fixes/dont-give-root-on-repeated-edits |  53 +++
 debian/patches/fixes/dont-log-temp-files           |  17 +
 debian/patches/fixes/drop-privileges               | 119 +++++
 debian/patches/fixes/general-coding-errors         | 161 +++++++
 debian/patches/fixes/general-platform-issues       | 194 ++++++++
 debian/patches/fixes/handle-escapes-in-commands    |  48 ++
 debian/patches/fixes/limit-args-for-commands       |  35 ++
 debian/patches/fixes/make-it-buildable             |  66 +++
 debian/patches/fixes/memory-management-issues      | 300 +++++++++++++
 .../patches/fixes/missing-or-broken-defs-and-decls |  27 ++
 debian/patches/fixes/parse-envvars-correctly       | 156 +++++++
 debian/patches/fixes/prevent-tmpfiles-attack       | 113 +++++
 debian/patches/fixes/proper-handling-of-stdstreams |  68 +++
 .../patches/fixes/properly-wait-for-spawned-editor |  93 ++++
 .../patches/fixes/protect-against-buffer-overflows | 387 ++++++++++++++++
 .../patches/fixes/root-does-not-override-allowdeny |  40 ++
 .../patches/fixes/set-umask-while-editing-crontab  |  33 ++
 debian/patches/fixes/signal-handling-issues        |  89 ++++
 .../fixes/tolerate-empty-editor-and-visual-envs    |  28 ++
 debian/patches/fixes/use-stdlib-for-time           |  61 +++
 debian/patches/fixes/various-mail-fixes            |  97 ++++
 debian/patches/other/DEAD-CODE                     |  18 +
 debian/patches/other/changes-to-cron-8             | 158 +++++++
 debian/patches/other/changes-to-crontab-1          | 170 +++++++
 debian/patches/other/changes-to-crontab-5          | 268 ++++++++++++
 debian/patches/other/changes-to-upstream-README    |  17 +
 debian/patches/series                              |  62 +++
 debian/standard.daily                              | 134 ++++++
 debian/standard.monthly                            |   4 +
 78 files changed, 8108 insertions(+)

diff --git a/debian/README.debian b/debian/README.debian
new file mode 100644
index 0000000..d74b9a2
--- /dev/null
+++ b/debian/README.debian
@@ -0,0 +1,37 @@
+cron for DEBIAN
+----------------------
+
+This is the Debian GNU/Linux prepackaged version of Paul Vixie's cron
+subsystem.
+
+Debian's cron development is being done on Alioth:
+http://svn.debian.org/wsvn/pkg-cron
+
+This package was put together by Ian Jackson <iwj10 at cus.cam.ac.uk>,
+from the standard sources to 3.0pl1, as posted to comp.sources.unix.
+Ian obtained them from
+src.doc.ic.ac.uk:/usenet/comp.sources.unix/volume27/vixie-cron.
+
+The changes are essentially the configuration for Debian Linux in the
+Makefile and pathnames.h, and the addition of support for the Debian
+package maintenance scheme in the form of various files (now in the
+debian directory).
+
+File locations that are different than that indicated in 
+the cron distributions README:
+
+user crontabs: /var/spool/cron/crontabs/*
+log file:      /var/log/cron.log
+allow file:    /etc/cron.allow
+deny file:     /etc/cron.deny
+
+Note that the location of the log file can be changed via syslog.conf.
+
+1998: Added reading of crontab fragments from /etc/cron.d to support
+other Debian package cron requirements. Files follow /etc/crontab
+format (i.e. with user field), must meet run-parts(8) naming
+convention (alphanumeric, underscore, hyphen only).
+
+This package is now maintained by Javier Fernández-Sanguino Peña
+<jfs at computer.org> and Christian Kastner <debian at kvr.at>.
+
diff --git a/debian/cron-se.dirs b/debian/cron-se.dirs
new file mode 100644
index 0000000..ca882bb
--- /dev/null
+++ b/debian/cron-se.dirs
@@ -0,0 +1,2 @@
+usr/bin
+usr/sbin
diff --git a/debian/cron-se.install b/debian/cron-se.install
new file mode 100644
index 0000000..ba2fab1
--- /dev/null
+++ b/debian/cron-se.install
@@ -0,0 +1,3 @@
+b-cron-se/cron usr/sbin
+b-cron-se/crontab usr/bin
+b-cron-se/cron-se usr/share/lintian/overrides
\ No newline at end of file
diff --git a/debian/cron-se.overrides b/debian/cron-se.overrides
new file mode 100644
index 0000000..15360f4
--- /dev/null
+++ b/debian/cron-se.overrides
@@ -0,0 +1,2 @@
+cron-se: binary-without-manpage cron
+cron-se: binary-without-manpage crontab
diff --git a/debian/cron-se.postinst b/debian/cron-se.postinst
new file mode 100644
index 0000000..5f1661e
--- /dev/null
+++ b/debian/cron-se.postinst
@@ -0,0 +1,21 @@
+#!/bin/sh
+set -e
+
+# Fixup crontab binary, directory and files for new group 'crontab'.
+
+if ! dpkg-statoverride --list /usr/bin/crontab > /dev/null ; then
+    chgrp crontab /usr/bin/crontab
+    chmod g+s /usr/bin/crontab
+fi
+
+if [ -x /etc/init.d/cron ]; then
+	if [ -x /usr/sbin/invoke-rc.d ] ; then
+	       invoke-rc.d cron restart
+	else
+	       /etc/init.d/cron restart
+	fi
+fi
+
+
+
+#DEBHELPER#
diff --git a/debian/cron-se.postrm b/debian/cron-se.postrm
new file mode 100644
index 0000000..de7c179
--- /dev/null
+++ b/debian/cron-se.postrm
@@ -0,0 +1,20 @@
+#!/bin/sh
+set -e
+
+if [ remove = "$1" ]; then
+    dpkg-divert --package cron-se --remove --rename \
+        --divert /usr/sbin/cron.cron /usr/sbin/cron
+    dpkg-divert --package cron-se --remove --rename \
+        --divert /usr/bin/crontab.cron /usr/bin/crontab
+fi
+
+# Restart non-se cron
+if [ -x /etc/init.d/cron ]; then
+	if [ -x /usr/sbin/invoke-rc.d ] ; then
+	       invoke-rc.d cron restart
+	else
+	       /etc/init.d/cron restart
+	fi
+fi
+
+#DEBHELPER#
diff --git a/debian/cron-se.preinst b/debian/cron-se.preinst
new file mode 100644
index 0000000..e9bea18
--- /dev/null
+++ b/debian/cron-se.preinst
@@ -0,0 +1,11 @@
+#!/bin/sh
+set -e
+
+if [ install = "$1"  ]; then
+    dpkg-divert --package cron-se --add --rename \
+        --divert /usr/sbin/cron.cron /usr/sbin/cron
+    dpkg-divert --package cron-se --add --rename \
+        --divert /usr/bin/crontab.cron /usr/bin/crontab
+fi
+
+#DEBHELPER#
diff --git a/debian/cron-se.prerm b/debian/cron-se.prerm
new file mode 100644
index 0000000..8be5e3f
--- /dev/null
+++ b/debian/cron-se.prerm
@@ -0,0 +1,12 @@
+#!/bin/sh
+set -e
+
+if [ -x /etc/init.d/cron ]; then
+	if [ -x /usr/sbin/invoke-rc.d ] ; then
+	       invoke-rc.d cron stop
+	else
+	       /etc/init.d/cron stop
+	fi
+fi
+
+#DEBHELPER#
diff --git a/debian/examples/stats-cron.pl b/debian/examples/stats-cron.pl
new file mode 100644
index 0000000..0427eb8
--- /dev/null
+++ b/debian/examples/stats-cron.pl
@@ -0,0 +1,357 @@
+#!/usr/bin/perl -w
+#
+# Generate stats of Cron messages sent to syslog
+#
+#
+# This script can be used to generate per-user and per-task 
+# statistics in order to determine how much time do cron tasks take
+# and audit cron use. It might be useful to debug issues related
+# to cron tasks that take too much time to run, or overlap, or get executed 
+# too fast..
+#
+# Hint: In some systems, cron tasks might not properly use lockfiles to
+# prevent themselves from being run twice in a row and some "strange"
+# things might happen if the system is overloaded and a cron task takes
+# more than expected. And, no, this is not something that Cron should
+# prevent (for more information see Debian bug #194805).
+#
+# In order for this script to work 
+#
+# together with the logging enhancements included
+# in Debian's vixie cron (3.0pl1-95) that make it possible to log 
+# when do cron tasks end.
+# 
+#
+# How to use:
+# - Modify /etc/init.d/cron so that the calls to cron pass the '-L 2'
+#   argument
+#   (Hint: change lines 27 and 47 so that they end with '-- -L 2 $LSBNAMES'
+#   instead of '-- $LSBNAMES')
+#   In Debian you need cron-3.0pl1-95 or later.
+#   Note: future versions of cron might use an /etc/default/cron file
+#   to provide arguments to cron. 
+#
+# - Review /etc/syslog.conf to determine where does the output of the cron
+#   facility goes to (might be /var/log/syslog together with other messages
+#   but you can also configure syslog to store them at /var/log/cron.log)
+#
+# - Run the script (by default it will read input /var/log/syslog but you
+#   can point to other file using the '-f' switch) and review the output
+#
+# - (Optionally) If you want to analyse log files for a long period
+#   concatenate different log files, extract all CRON related entries
+#   to a file and process that.
+#  
+#   You could do, for example, this:
+#
+#   zcat -f /var/log/syslog* | grep CRON >cron-log ;  \
+#              perl stats-cron.pl -f cron-log
+#   
+#
+# This program is copyright 2006 by Javier Fernandez-Sanguino <jfs at debian.org>
+#
+#    This program 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.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program; if not, write to the Free Software
+#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+# For more information please see
+#  http://www.gnu.org/licenses/licenses.html#GPL
+
+# TODO:
+# - Print time internal of file analysis (from 'XXX' to 'XXX') based on the
+#   first and the last log entry read.
+# 
+# - Detect overlaped entries for the same task (start of an entry before the
+#   previous one finished)
+#
+# - Make it possible to filter by users
+#
+# - Consider adapting to other log formats (other cron programs? Solaris?) by
+#   separating analysis and extraction in the code and making it possible
+#   to switch to different analysis methods.
+
+
+# Required modules
+eval 'use Parse::Syslog';
+if ($@) {
+	print STDERR "ERROR: Parse::Syslog not installed, please install this Perl library\n";
+	print STDERR "ERROR: (in Debian it is provided by the 'libparse-syslog-perl' package)\n";
+	exit 1;
+}
+use Parse::Syslog;
+use Getopt::Std;
+# Parse command line
+getopts('d:hvf:');
+$opt_d = 0 if ! defined ($opt_d) ;
+
+if ( $opt_h ) {
+	print "Usage: $ARGV[0] [-dhv] [-f syslog file]";
+	exit 1;
+}
+
+# Note: in Debian's default syslog configuration log messages are 
+# sent to /var/log/syslog but you might have edited it to use
+# /var/log/cron.log instead. Which, BTW, is more efficient because
+# we do not need to parse the syslog to extract only cron messages.
+my $LOGFILE = $opt_f || "/var/log/syslog";
+
+# Sanity checks
+if ( ! -r $LOGFILE ) {
+	print STDERR "ERROR: Cannot read logfile $LOGFILE";
+}
+
+my $parser = Parse::Syslog->new( $LOGFILE);
+print STDERR "Starting parse of file $LOGFILE\n" if $opt_v;
+while(my $log = $parser->next) {
+	if ( $log->{program} =~ /CRON/ ) {
+		print STDERR "DEBUG: Found syslog entry: $log->{pid}\n" if $opt_d;
+# We extract the entries with the same text but with 'CMD' (start)
+# and 'END' (end) to check if it's the same we use the PID, the
+# PID of END (generated by the parent process) is PID-1 of CMD
+		if ($log->{text} =~ /CMD \(/) {
+			add_entry($log->{timestamp},$log->{text},$log->{pid});
+		}
+		if ($log->{text} =~ /END \(/) {
+			clear_entry($log->{timestamp},$log->{text},$log->{pid});
+		}
+	}
+}
+print STDERR "Finished parse of file $LOGFILE\n" if $opt_v;
+
+
+# Analysis, we find all entries with a start and stop timestamp 
+# and print them
+generate_analysis();
+
+# Stats:
+# - average time of execution of cron jobs
+# - cronjob which executed slowest
+# - cronjob which executed fastes
+# - cronjobs which start before they finish
+print_stats();
+
+exit 0;
+
+sub find_user {
+# Extract a user from a cron entry
+	my ($text) = @_;
+	my $user = "";
+	if ( $text =~ /^\((.*?)\)/ ) {
+		$user = $1;
+	} 
+	return $user;
+}
+
+sub find_prg {
+# Extract a program from a cron entry
+	my ($text) = @_;
+	my $prg = "";
+	if ( $text =~ /(CM|EN)D\s*\((.*)\s*\)\s*$/ ) {
+		$prg = $2;
+	}
+	return $prg;
+}
+
+sub add_entry {
+# Get a syslog entry and add it to the table of entries for analysis
+	my ($time, $text, $pid) = @_;
+	my ($user, $prg);
+	print STDERR "DEBUG: Entering add_entry with @_\n" if $opt_d; 
+	$user = find_user($text);
+	if ( ! defined ($user) ) {
+		print STDERR "WARN: Cannot find user for cron job (pid $pid)\n";
+		return;
+	}
+	$prg  = find_prg($text);
+	if ( ! defined ($prg) ) {
+		print STDERR "WARN: Cannot find program for cron job (pid $pid)\n";
+		return;
+	}
+	my $value = $pid."-".$time;
+	print STDERR "DEBUG: Adding cronjob of user $user to list: $prg\n" if $opt_d;
+	add_cron_entry($user, $prg, $value);
+	$cron_entries{$user}{$prg}{'count'}++;
+	return;
+}
+
+sub clear_entry {
+# Get a syslog entry, find the start entry and add the timestamp difference
+# to the list of timestamps for that user
+#
+	my ($timestamp, $text, $pid) = @_;
+	my ($user, $prg, $entry, $count);
+	my @array; my @stack;
+	print STDERR "DEBUG: Entering clear_entry with @_\n" if $opt_d; 
+	$user = find_user($text);
+	if ( $user eq "" ) {
+		print STDERR "WARN: Cannot find user for cron job (pid $pid)\n";
+		return;
+	}
+	$prg  = find_prg($text);
+	if ( $prg eq "" ) {
+		print STDERR "WARN: Cannot find program for cron job (pid $pid)\n";
+		return;
+	}
+	if ( ! defined ( $cron_entries{$user}{$prg}{'item'} ) ) {
+		print STDERR "WARN: End entry without start entry (pid $pid)\n";
+		return;
+	}
+	@array = split(':', $cron_entries{$user}{$prg}{'item'});
+	$count = $#array + 1 ;
+	print STDERR "DEBUG: $count cron entries for $user, task '$prg'\n" if $opt_d;
+	my $finish = 0;
+	while ( $finish == 0 ) {
+		$entry = pop @array;
+		last if ! defined ($entry) ;
+	# Pop all entries and look for one whose pid is ours -1
+		my ($spid, $stimestamp) =  split ("-", $entry);
+		print  STDERR "DEBUG: Comparing entry $spid to $pid\n" if $opt_d;
+		if  ( $pid-$spid <= 1 ) {
+			my $timediff =  $timestamp-$stimestamp;
+			print STDERR "DEBUG: Entries match, time difference of $timediff\n" if $opt_d ;
+			$cron_entries{$user}{$prg}{'finished'}++;
+			if (defined ( $cron_times{$user}{$prg} ) ) { 
+				$cron_times{$user}{$prg} = join(":", $cron_times{$user}{$prg}, $timediff);
+			} else {
+				$cron_times{$user}{$prg} = $timediff;
+			}
+			$finish = 1;
+		} else {
+			print STDERR "DEBUG: Pushing entry $spid into stack\n" if $opt_d;
+			push @stack, $entry;
+		}
+	}
+	# Push all remaining entries to the stack
+	$cron_entries{$user}{$prg}{'item'}="";
+	$count = $#array + 1 ;
+	if ($opt_d) {
+		print STDERR "DEBUG: Restoring all entries (size: array $count";
+		$count = $#stack + 1 ;
+		print STDERR ", stack $count)\n";
+	}
+	print STDERR "DEBUG: Total finished tasks: $cron_entries{$user}{$prg}{'finished'} out of $cron_entries{$user}{$prg}{'count'}\n" if defined $cron_entries{$user}{$prg}{'finished'} && $opt_d;
+	print STDERR "DEBUG: Unmatched now: $cron_entries{$user}{$prg}{'item'}\n" if $opt_d;
+	while ( $entry = pop @array ) {
+		add_cron_entry($user, $prg, $entry);
+	}
+	while ( $entry = pop @stack ) {
+		add_cron_entry($user, $prg, $entry);
+	}
+	print STDERR "DEBUG: Finish execution of clear_entry\n" if $opt_d;
+	return;
+}
+
+sub add_cron_entry {
+	my ($user, $prg, $entry) = @_;
+	if ( defined ($cron_entries{$user}{$prg}) &&  $cron_entries{$user}{$prg} ne "" ) { 
+		$cron_entries{$user}{$prg}{'item'} = join(":", $cron_entries{$user}{$prg}{'item'}, $entry);
+	} else {
+		$cron_entries{$user}{$prg}{'item'} = $entry;
+	}
+}
+
+sub count_unmatched {
+	my ($user, $prg) = @_;
+	my ($count, @array);
+	return 0 if ! defined ( $cron_entries{$user}{$prg}{'item'} ); 
+	@array = split(':', $cron_entries{$user}{$prg}{'item'});
+	$count = $#array + 1 ;
+	return $count;
+}
+
+sub find_average {
+	my ($user, $prg) = @_;
+	my ($average, $count, $total, @array, $entry);
+	$total = 0 ;
+	return -1 if ! defined ( $cron_times{$user}{$prg} ); 
+	@array = split(':', $cron_times{$user}{$prg});
+	$count = $#array + 1 ;
+	while ( defined ( $entry = pop @array ) ) {
+		$total += $entry;
+	}
+	$average = $total / $count;
+	return $average;
+}
+
+sub find_minimum {
+	my ($user, $prg) = @_;
+	my ($minimum, @array, $entry);
+	$minimum = -1;
+	return -1 if ! defined ( $cron_times{$user}{$prg} ); 
+	@array = split(':', $cron_times{$user}{$prg});
+	while ( defined ( $entry = pop @array ) ) {
+		if ( $minimum == -1 ) {
+			$minimum = $entry;
+		} else {
+			$minimum = $entry if $entry < $minimum;
+		}
+	}
+	return $minimum;
+}
+
+sub find_maximum {
+	my ($user, $prg) = @_;
+	my ($maximum, @array);
+	$maximum = -1;
+	return -1 if ! defined ( $cron_times{$user}{$prg} ); 
+	@array = split(':', $cron_times{$user}{$prg});
+	while ( defined ( $entry = pop @array ) ) {
+		if ( $maximum == -1 ) {
+			$maximum = $entry ;
+		} else { 
+			$maximum = $entry if $entry > $maximum;
+		}
+	}
+	return $maximum;
+}
+
+
+
+sub generate_analysis {
+# For each user and program calculate the average time for the task
+	my ($user, $prg);
+	foreach $user (keys %cron_entries) {
+		print STDERR "DEBUG: Calculating data for user '$user'\n" if $opt_d;
+		foreach my $prg ( keys %{$cron_entries{$user}} ) {
+			print STDERR "DEBUG: Calculating data for task '$prg'\n" if $opt_d;
+			my $unmatched = count_unmatched($user, $prg);
+			my $average = find_average($user, $prg);
+			my $minimum = find_minimum($user, $prg);
+			my $maximum = find_maximum($user, $prg);
+			$cron_entries{$user}{$prg}{'unmatched'} = $unmatched;
+			$cron_entries{$user}{$prg}{'average'} = $average;
+			$cron_entries{$user}{$prg}{'minimum'} = $minimum;
+			$cron_entries{$user}{$prg}{'maximum'} = $maximum;
+		}
+	}
+}
+
+sub print_stats {
+# Print information of cron statistics
+	my ($user, $prg);
+	foreach  $user (keys %cron_entries) {
+		print "Cron statistics for user '$user'\n";
+		foreach $prg ( keys %{$cron_entries{$user}} ) {
+			print "\tTask: '$prg'\n";
+			print "\t\tDEBUG: $cron_times{$user}{$prg}\n" if $opt_d;
+			print <<EOF
+\t\tTotal: $cron_entries{$user}{$prg}{'count'}
+\t\tFinished: $cron_entries{$user}{$prg}{'finished'}
+\t\tUnmatched: $cron_entries{$user}{$prg}{'unmatched'}
+\t\tAvg time: $cron_entries{$user}{$prg}{'average'}
+\t\tMin time: $cron_entries{$user}{$prg}{'minimum'}
+\t\tMax time: $cron_entries{$user}{$prg}{'maximum'}
+EOF
+		}
+	}
+}
diff --git a/debian/patches-from-bts/proper_use_streerno_bug_470587.diff b/debian/patches-from-bts/proper_use_streerno_bug_470587.diff
new file mode 100644
index 0000000..0acc0a3
--- /dev/null
+++ b/debian/patches-from-bts/proper_use_streerno_bug_470587.diff
@@ -0,0 +1,153 @@
+diff -u cron-3.0pl1/misc.c cron-3.0pl1/misc.c
+--- cron-3.0pl1/misc.c
++++ cron-3.0pl1/misc.c
+@@ -203,8 +203,7 @@
+ 			fprintf(stderr, "%s: created\n", CRONDIR);
+ 			stat(CRONDIR, &sb);
+ 		} else {
+-			fprintf(stderr, "%s: ", CRONDIR);
+-			perror("mkdir");
++			fprintf(stderr, "%s: mkdir: %s\n", CRONDIR, strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
+ 	}
+@@ -214,8 +213,7 @@
+ 		exit(ERROR_EXIT);
+ 	}
+ 	if (chdir(CRONDIR) < OK) {
+-		fprintf(stderr, "cannot chdir(%s), bailing out.\n", CRONDIR);
+-		perror(CRONDIR);
++		fprintf(stderr, "%s: chdir: %s\n", CRONDIR, strerror(errno));
+ 		exit(ERROR_EXIT);
+ 	}
+ 
+@@ -227,8 +225,7 @@
+ 			fprintf(stderr, "%s: created\n", SPOOL_DIR);
+ 			stat(SPOOL_DIR, &sb);
+ 		} else {
+-			fprintf(stderr, "%s: ", SPOOL_DIR);
+-			perror("mkdir");
++			fprintf(stderr, "%s: mkdir: %s\n", SPOOL_DIR, strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
+ 	}
+@@ -507,9 +504,8 @@
+ 	if (LogFD < OK) {
+ 		LogFD = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600);
+ 		if (LogFD < OK) {
+-			fprintf(stderr, "%s: can't open log file\n",
+-				ProgramName);
+-			perror(LOG_FILE);
++			fprintf(stderr, "%s: %s: open: %s\n",
++				ProgramName, LOG_FILE, strerror(errno));
+ 		} else {
+ 			(void) fcntl(LogFD, F_SETFD, 1);
+ 		}
+diff -u cron-3.0pl1/crontab.c cron-3.0pl1/crontab.c
+--- cron-3.0pl1/crontab.c
++++ cron-3.0pl1/crontab.c
+@@ -326,8 +326,7 @@
+ 		if (errno == ENOENT) 
+ 			fprintf(stderr, "no crontab for %s\n", User);
+ 		else {
+-                        fprintf(stderr, "%s/", CRONDIR);
+-			perror(n);
++                        fprintf(stderr, "%s/: fopen: %s\n", n, strerror(errno));
+                 }
+ 		exit(ERROR_EXIT);
+ 	} else if ((fd=fileno(f))==-1) {
+@@ -413,8 +412,7 @@
+ 		if (errno == ENOENT)
+ 			fprintf(stderr, "no crontab for %s\n", User);
+ 		else {
+-                        fprintf(stderr, "%s/", CRONDIR);
+-			perror(n);
++                        fprintf(stderr, "%s/: unlink: %s\n", CRONDIR, strerror(errno));
+                 }
+ 		exit(ERROR_EXIT);
+ 	}
+@@ -583,8 +581,7 @@
+ 	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+ 	if (!(f = fopen(n, "r"))) {
+ 		if (errno != ENOENT) {
+-                        fprintf(stderr, "%s/", CRONDIR);
+-			perror(n);
++                        fprintf(stderr, "%s/: fdopen: %s", n, strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
+ 		fprintf(stderr, "no crontab for %s - using an empty one\n",
+@@ -875,14 +872,12 @@
+ 	um = umask(077);
+ 	fd = mkstemp(tn);
+ 	if (fd < 0) {
+-                fprintf(stderr, "%s/", CRONDIR);
+-		perror(tn);
++                fprintf(stderr, "%s/: mkstemp: %s\n", CRONDIR, strerror(errno));
+ 		return(-2);
+ 	}
+ 	tmp = fdopen(fd, "w+");
+ 	if (!tmp) {
+-                fprintf(stderr, "%s/", CRONDIR);
+-		perror(tn);
++                fprintf(stderr, "%s/: fdopen: %s\n", CRONDIR, strerror(errno));
+ 		return (-2);
+ 	}
+ 	(void) umask(um);
+@@ -903,9 +898,8 @@
+ 		putc(ch, tmp);
+ 
+ 	if (ferror(tmp) || fflush(tmp) || fsync(fd)) {
+-		fprintf(stderr, "%s: error while writing new crontab to %s\n",
+-			ProgramName, tn);
+-		perror("Error");
++		fprintf(stderr, "%s: %s: %s\n",
++			ProgramName, tn, strerror(errno));
+ 		fclose(tmp);  unlink(tn);
+ 		return (-2);
+ 	}
+@@ -969,9 +963,8 @@
+         }
+ 
+ 	if (rename(tn, n)) {
+-		fprintf(stderr, "%s: error renaming %s to %s\n",
+-			ProgramName, tn, n);
+-		perror("rename");
++		fprintf(stderr, "%s: %s: rename: %s\n",
++			ProgramName, n, strerror(errno));
+ 		unlink(tn);
+ 		return (-2);
+ 	}
+@@ -994,16 +987,14 @@
+ 	(void) gettimeofday(&tvs[0], &tz);
+ 	tvs[1] = tvs[0];
+ 	if (utimes(SPOOL_DIR, tvs) < OK) {
+-		fprintf(stderr, "crontab: can't update mtime on spooldir\n");
+-                fprintf(stderr, "%s/", CRONDIR);
+-		perror(SPOOL_DIR);
++                fprintf(stderr, "%s/: utimes: %s", CRONDIR, strerror(errno));
++		fputs("crontab: can't update mtime on spooldir\n", stderr);
+ 		return;
+ 	}
+ #else
+ 	if (utime(SPOOL_DIR, NULL) < OK) {
+-		fprintf(stderr, "crontab: can't update mtime on spooldir\n");
+-                fprintf(stderr, "%s/", CRONDIR);
+-		perror(SPOOL_DIR);
++                fprintf(stderr, "%s: utime: %s\n", CRONDIR, strerror(errno));
++		fputs("crontab: can't update mtime on spooldir\n", stderr);
+ 		return;
+ 	}
+ #endif /*USE_UTIMES*/
+diff -u cron-3.0pl1/do_command.c cron-3.0pl1/do_command.c
+--- cron-3.0pl1/do_command.c
++++ cron-3.0pl1/do_command.c
+@@ -342,8 +342,7 @@
+ 			}
+ #endif
+                         execle(shell, shell, "-c", e->cmd, (char *)0, jobenv);
+-			fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
+-			perror("execl");
++			fprintf(stderr, "%s: execle: %s\n", shell, strerror(errno));
+ 			_exit(ERROR_EXIT);
+ 		}
+ 		break;
diff --git a/debian/patches-from-bts/sensible_editor_482284.diff b/debian/patches-from-bts/sensible_editor_482284.diff
new file mode 100644
index 0000000..6480a83
--- /dev/null
+++ b/debian/patches-from-bts/sensible_editor_482284.diff
@@ -0,0 +1,12 @@
+diff -upr cron-3.0pl1.orig/pathnames.h cron-3.0pl1/pathnames.h
+--- cron-3.0pl1.orig/pathnames.h	2008-05-21 10:42:06.064487361 -0500
++++ cron-3.0pl1/pathnames.h	2008-05-21 10:41:34.412450000 -0500
+@@ -75,7 +75,7 @@
+ 			 * environment variable specified.
+ 			 */
+ #if defined(DEBIAN)
+-# define EDITOR "/usr/bin/editor"
++# define EDITOR "/usr/bin/sensible-editor"
+ #elif defined(_PATH_VI)
+ # define EDITOR _PATH_VI
+ #else
diff --git a/debian/patches/features/add-helpmsg-to-new-crontab b/debian/patches/features/add-helpmsg-to-new-crontab
new file mode 100644
index 0000000..4e6d02d
--- /dev/null
+++ b/debian/patches/features/add-helpmsg-to-new-crontab
@@ -0,0 +1,62 @@
+Subject: Add a helpful header to a new crontab
+Author: Javier Fernández-Sanguino Peña <jfs at debian.org>
+Last-Update: 2010-04-11
+
+When creating a new crontab, seed it with helpful instructions (as comments) on
+how to create an entry.
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:57.090560587 +0200
++++ patched/crontab.c	2010-05-06 18:18:57.762561131 +0200
+@@ -549,6 +549,7 @@
+ 	WAIT_T		waiter;
+ 	PID_T		pid, xpid;
+ 	mode_t		um;
++	int             add_help_text = 0;
+ 
+ 	log_it(RealUser, Pid, "BEGIN EDIT", User);
+ 	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+@@ -563,6 +564,7 @@
+ 			perror("/dev/null");
+ 			exit(ERROR_EXIT);
+ 		}
++		add_help_text = 1;
+ 	}
+ 
+ 	um = umask(077);
+@@ -581,6 +583,33 @@
+ 
+ 	Set_LineNum(1)
+ 
++	if (add_help_text) {
++		fprintf(NewCrontab, 
++"# Edit this file to introduce tasks to be run by cron.\n"
++"# \n"
++"# Each task to run has to be defined through a single line\n"
++"# indicating with different fields when the task will be run\n"
++"# and what command to run for the task\n"
++"# \n"
++"# To define the time you can provide concrete values for\n"
++"# minute (m), hour (h), day of month (dom), month (mon),\n"
++"# and day of week (dow) or use '*' in these fields (for 'any')."
++"# \n"
++"# Notice that tasks will be started based on the cron's system\n"
++"# daemon's notion of time and timezones.\n"
++"# \n"
++"# Output of the crontab jobs (including errors) is sent through\n"
++"# email to the user the crontab file belongs to (unless redirected).\n"
++"# \n"
++"# For example, you can run a backup of all your user accounts\n"
++"# at 5 a.m every week with:\n"
++"# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/\n"
++"# \n"
++"# For more information see the manual pages of crontab(5) and cron(8)\n" 
++"# \n"
++"# m h  dom mon dow   command\n" );
++	}
++
+ 	/* ignore the top few comments since we probably put them there.
+ 	 */
+ 	for (x = 0;  x < NHEADER_LINES;  x++) {
diff --git a/debian/patches/features/allow-running-cron-in-foreground b/debian/patches/features/allow-running-cron-in-foreground
new file mode 100644
index 0000000..abde843
--- /dev/null
+++ b/debian/patches/features/allow-running-cron-in-foreground
@@ -0,0 +1,51 @@
+Subject: Allow running cron in foreground
+Last-Update: 2010-04-11
+
+Allow running cron in foreground if one wishes to do so.
+
+Bug-Debian: http://bugs.debian.org/108492
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:54.665561020 +0200
++++ patched/cron.c	2010-05-06 18:18:55.651562056 +0200
+@@ -117,7 +117,7 @@
+ 	if (0) {
+ # endif
+ 		(void) fprintf(stderr, "[%d] cron started\n", getpid());
+-	} else {
++	} else if (!stay_foreground) {
+ 		switch (fork()) {
+ 		case -1:
+ 			log_it("CRON",getpid(),"DEATH","can't fork");
+@@ -464,12 +464,16 @@
+ {
+ 	int	argch;
+ 
++	stay_foreground = 0;
+         lsbsysinit_mode = 0;
+ 
+-	while (EOF != (argch = getopt(argc, argv, "lx:"))) {
++	while (EOF != (argch = getopt(argc, argv, "lfx:"))) {
+ 		switch (argch) {
+ 		default:
+ 			usage();
++		case 'f':
++			stay_foreground = 1;
++			break;
+ 		case 'x':
+ 			if (!set_debug_flags(optarg))
+ 				usage();
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:54.665561020 +0200
++++ patched/cron.h	2010-05-06 18:18:55.651562056 +0200
+@@ -290,6 +290,7 @@
+ time_min clockTime;
+ static long GMToff;
+ 
++int	stay_foreground;
+ int     lsbsysinit_mode;
+ 
+ char    cron_default_mail_charset[MAX_ENVSTR] = "";
diff --git a/debian/patches/features/auditlog-support b/debian/patches/features/auditlog-support
new file mode 100644
index 0000000..d89bb9f
--- /dev/null
+++ b/debian/patches/features/auditlog-support
@@ -0,0 +1,82 @@
+Subject: Auditlog support
+Last-Update: 2010-04-11
+
+Auditlog support.
+Index: patched/Makefile
+===================================================================
+--- patched.orig/Makefile	2010-05-06 18:18:48.837561139 +0200
++++ patched/Makefile	2010-05-06 18:18:53.301142936 +0200
+@@ -55,7 +55,7 @@
+ INCLUDE		=	-I.
+ #INCLUDE	=
+ #<<need getopt()>>
+-LIBS		= $(PAM_LIBS) $(SELINUX_LIBS)
++LIBS		= $(PAM_LIBS) $(SELINUX_LIBS) $(AUDIT_LIBS)
+ #<<optimize or debug?>>
+ OPTIM		=	-O2
+ #OPTIM		=	-g
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:52.595435667 +0200
++++ patched/misc.c	2010-05-06 18:18:53.301435633 +0200
+@@ -36,6 +36,9 @@
+ #include <string.h>
+ #include <fcntl.h>
+ #include <grp.h>
++#ifdef WITH_AUDIT
++#include <libaudit.h>
++#endif
+ #if defined(SYSLOG)
+ # include <syslog.h>
+ #endif
+@@ -461,7 +464,17 @@
+ {
+ 	static int	init = FALSE;
+ 	static FILE	*allow, *deny;
++	int     isallowed;
++
++        /* Root cannot be denied execution of cron jobs even if in the
++	 * 'DENY_FILE' so we return inmediately */
++        if (strcmp(username, ROOT_USER) == 0)
++                return (TRUE);
+ 
++	isallowed = FALSE;
++#if defined(ALLOW_ONLY_ROOT)
++	Debug(DMISC, "only root access is allowed")
++#else
+ 	if (!init) {
+ 		init = TRUE;
+ #if defined(ALLOW_FILE) && defined(DENY_FILE)
+@@ -474,16 +487,24 @@
+ #endif
+ 	}
+ 
+-	if (allow)
+-		return (in_file(username, allow));
+-	if (deny)
+-		return (!in_file(username, deny));
++	if (allow) 
++		isallowed = in_file(username, allow);
++	else
++		isallowed = TRUE; /* Allow access if ALLOW_FILE does not exist */
++	if (deny && !allow)
++		isallowed = !in_file(username, deny);
++#endif
+ 
+-#if defined(ALLOW_ONLY_ROOT)
+-	return (strcmp(username, ROOT_USER) == 0);
+-#else
+-	return TRUE;
++#ifdef WITH_AUDIT
++       /* Log an audit message if the user is rejected */ 
++       if (isallowed == FALSE) {
++               int audit_fd = audit_open();
++               audit_log_user_message(audit_fd, AUDIT_USER_START, "cron deny",
++                       NULL, NULL, NULL, 0);
++               close(audit_fd);
++       }
+ #endif
++	return isallowed;
+ }
+ 
+ 
diff --git a/debian/patches/features/backport-envparser b/debian/patches/features/backport-envparser
new file mode 100644
index 0000000..c225bc0
--- /dev/null
+++ b/debian/patches/features/backport-envparser
@@ -0,0 +1,148 @@
+Subject: Backport the crontab environment parser from 4.1
+Origin: backport, http://ftp.isc.org/isc/cron/cron_4.1.shar
+Last-Update: 2010-04-29
+
+The 3.0 parser is crude and may misparse crontab entries containing equal signs
+(=). This patch backports the parser from the 4.1 release.
+
+Bug-Debian: http://bugs.debian.org/437180
+Index: patched/env.c
+===================================================================
+--- patched.orig/env.c	2010-05-06 18:18:28.216436280 +0200
++++ patched/env.c	2010-05-06 18:19:03.459436043 +0200
+@@ -128,6 +128,17 @@
+ 	return (p);
+ }
+ 
++/* The following states are used by load_env(), traversed in order: */
++enum env_state {
++	NAMEI,		/* First char of NAME, may be quote */
++	NAME,		/* Subsequent chars of NAME */
++	EQ1,		/* After end of name, looking for '=' sign */
++	EQ2,		/* After '=', skipping whitespace */
++	VALUEI,		/* First char of VALUE, may be quote */
++	VALUE,		/* Subsequent chars of VALUE */
++	FINI,		/* All done, skipping trailing whitespace */
++	ERROR,		/* Error */
++};
+ 
+ /* return	ERR = end of file
+  *		FALSE = not an env setting (file was repositioned)
+@@ -140,8 +151,9 @@
+ {
+ 	long	filepos;
+ 	int	fileline;
+-	char	name[MAX_ENVSTR], val[MAX_ENVSTR];
+-	int	fields;
++	enum env_state state;
++	char name[MAX_ENVSTR], val[MAX_ENVSTR];
++	char quotechar, *c, *str;
+ 
+ 	filepos = ftell(f);
+ 	fileline = LineNumber;
+@@ -153,20 +165,90 @@
+ 
+ 	Debug(DPARS, ("load_env, read <%s>\n", envstr))
+ 
+-	name[0] = val[0] = '\0';
+-	fields = sscanf(envstr, "%[^ =] = %[^\n#]", name, val);
+-	if (fields != 2) {
+-		Debug(DPARS, ("load_env, not 2 fields (%d)\n", fields))
++	bzero(name, sizeof name);
++	bzero(val, sizeof val);
++	str = name;
++	state = NAMEI;
++	quotechar = '\0';
++	c = envstr;
++	while (state != ERROR && *c) {
++		switch (state) {
++		case NAMEI:
++		case VALUEI:
++			if (*c == '\'' || *c == '"')
++				quotechar = *c++;
++			state++;
++			/* FALLTHROUGH */
++		case NAME:
++		case VALUE:
++			if (quotechar) {
++				if (*c == quotechar) {
++					state++;
++					c++;
++					break;
++				}
++				if (state == NAME && *c == '=') {
++					state = ERROR;
++					break;
++				}
++			} else {
++				if (state == NAME) {
++					if (isspace((unsigned char)*c)) {
++						c++;
++						state++;
++						break;
++					}
++					if (*c == '=') {
++						state++;
++						break;
++					}
++				}
++			}
++			*str++ = *c++;
++			break;
++
++		case EQ1:
++			if (*c == '=') {
++				state++;
++				str = val;
++				quotechar = '\0';
++			} else {
++				if (!isspace((unsigned char)*c))
++					state = ERROR;
++			}
++			c++;
++			break;
++
++		case EQ2:
++		case FINI:
++			if (isspace((unsigned char)*c))
++				c++;
++			else
++				state++;
++			break;
++
++		default:
++			abort();
++		}
++	}
++	if (state != FINI && !(state == VALUE && !quotechar)) {
++		Debug(DPARS, ("load_env, not an env var, state = %d\n", state))
+ 		fseek(f, filepos, 0);
+ 		Set_LineNum(fileline);
+ 		return (FALSE);
+ 	}
++	if (state == VALUE) {
++		/* End of unquoted value: trim trailing whitespace */
++		c = val + strlen(val);
++		while (c > val && isspace((unsigned char)c[-1]))
++			*(--c) = '\0';
++	}
+ 
+-	/* 2 fields from scanf; looks like an env setting
+-	 */
++	/* 2 fields from parser; looks like an env setting */
+ 
+ 	/*
+-	 * process value string
++	 * This can't overflow because get_string() limited the size of the
++	 * name and val fields.  Still, it doesn't hurt to be careful...
+ 	 */
+ 	/*local*/{
+ 		int	len = strdtb(val);
+@@ -188,7 +270,6 @@
+ 	return (TRUE);
+ }
+ 
+-
+ char *
+ env_get(name, envp)
+ 	register char	*name;
diff --git a/debian/patches/features/better-debugging-support b/debian/patches/features/better-debugging-support
new file mode 100644
index 0000000..b2e8540
--- /dev/null
+++ b/debian/patches/features/better-debugging-support
@@ -0,0 +1,90 @@
+Subject: Better debugging support
+Last-Update: 2010-04-11
+
+Extend debugging options, etc...
+Index: patched/Makefile
+===================================================================
+--- patched.orig/Makefile	2010-05-06 18:18:21.821436206 +0200
++++ patched/Makefile	2010-05-06 18:18:44.879435811 +0200
+@@ -71,9 +71,10 @@
+ #<<want to use a nonstandard CC?>>
+ #CC		=	vcc
+ #<<manifest defines>>
+-DEFS		=
++# Allow override from command line
++DEBUG_DEFS = -DDEBUGGING=0   
+ # The -DUSE_SIGCHLD is needed for the Alpha port
+-DEFS = -DDEBIAN -DUSE_SIGCHLD
++DEFS = -DDEBIAN -DUSE_SIGCHLD $(DEBUG_DEFS)
+ #(SGI IRIX systems need this)
+ #DEFS		=	-D_BSD_SIGNALS -Dconst=
+ #<<the name of the BSD-like install program>>
+Index: patched/config.h
+===================================================================
+--- patched.orig/config.h	2010-05-06 18:18:31.635435778 +0200
++++ patched/config.h	2010-05-06 18:18:44.880437493 +0200
+@@ -29,6 +29,7 @@
+  */
+ 
+ #ifndef DEBUGGING
++#error DEBUGGING not defined
+ #define DEBUGGING 1	/* 1 or 0 -- do you want debugging code built in? */
+ #endif
+ 
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:38.503560917 +0200
++++ patched/cron.c	2010-05-06 18:18:44.880437493 +0200
+@@ -48,7 +48,16 @@
+ 
+ static void
+ usage() {
+-	fprintf(stderr, "usage:  %s [-x debugflag[,...]]\n", ProgramName);
++#if DEBUGGING
++	char **dflags;
++
++	fprintf(stderr, "usage:  %s [-x [", ProgramName);
++	for(dflags = DebugFlagNames; *dflags; dflags++)
++		fprintf(stderr, "%s%s", *dflags, dflags[1] ? "," : "]");
++	fprintf(stderr, "]\n");
++#else
++	fprintf(stderr, "usage: %s\n", ProgramName);
++#endif
+ 	exit(ERROR_EXIT);
+ }
+ 
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:43.421561039 +0200
++++ patched/crontab.c	2010-05-06 18:18:44.880437493 +0200
+@@ -148,6 +148,12 @@
+ 	/*NOTREACHED*/
+ }
+ 	
++#if DEBUGGING
++char *getoptarg = "u:lerix:";
++#else
++char *getoptarg = "u:leri";
++#endif
++
+ 
+ static void
+ parse_args(argc, argv)
+@@ -170,12 +176,16 @@
+ 	}
+ 	Filename[0] = '\0';
+ 	Option = opt_unknown;
+-	while (EOF != (argch = getopt(argc, argv, "u:lerx:"))) {
++
++	while (EOF != (argch = getopt(argc, argv, getoptarg))) {
+ 		switch (argch) {
++#if DEBUGGING
+ 		case 'x':
+ 			if (!set_debug_flags(optarg))
+ 				usage("bad debug option");
++			usage("unrecognized option");
+ 			break;
++#endif
+ 		case 'u':
+ 			if (!(pw = getpwnam(optarg)))
+ 			{
diff --git a/debian/patches/features/confirm-crontab-deletion b/debian/patches/features/confirm-crontab-deletion
new file mode 100644
index 0000000..180ae11
--- /dev/null
+++ b/debian/patches/features/confirm-crontab-deletion
@@ -0,0 +1,94 @@
+Subject: Ask for confirmation when deleting crontab
+Author: Javier Fernández-Sanguino Peña <jfs at debian.org>
+Last-Update: 2010-04-11
+
+Add the ability to request confirmation before deleting a crontab.
+
+Bug-Debian: http://bugs.debian.org/513379
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:56.391036364 +0200
++++ patched/crontab.c	2010-05-06 18:18:57.090560587 +0200
+@@ -60,6 +60,7 @@
+ static	char		Directory[MAX_FNAME];
+ static	FILE		*NewCrontab = NULL;
+ static	int		CheckErrorCount;
++static  int             PromptOnDelete;
+ static	enum opt_t	Option;
+ static	struct passwd	*pw;
+ static	void		list_cmd __P((void)),
+@@ -81,11 +82,12 @@
+ {
+ 	fprintf(stderr, "%s: usage error: %s\n", ProgramName, msg);
+ 	fprintf(stderr, "usage:\t%s [-u user] file\n", ProgramName);
+-	fprintf(stderr, "\t%s [-u user] { -e | -l | -r }\n", ProgramName);
++	fprintf(stderr, "\t%s [ -u user ] [ -i ] { -e | -l | -r }\n", ProgramName);
+ 	fprintf(stderr, "\t\t(default operation is replace, per 1003.2)\n");
+ 	fprintf(stderr, "\t-e\t(edit user's crontab)\n");
+ 	fprintf(stderr, "\t-l\t(list user's crontab)\n");
+ 	fprintf(stderr, "\t-r\t(delete user's crontab)\n");
++        fprintf(stderr, "\t-i\t(prompt before deleting user's crontab)\n");
+ 	exit(ERROR_EXIT);
+ }
+ 
+@@ -175,6 +177,7 @@
+ 	}
+ 	Filename[0] = '\0';
+ 	Option = opt_unknown;
++        PromptOnDelete = 0;
+ 
+ 	while (EOF != (argch = getopt(argc, argv, getoptarg))) {
+ 		switch (argch) {
+@@ -220,6 +223,9 @@
+ 				usage("only one operation permitted");
+ 			Option = opt_edit;
+ 			break;
++		case 'i':
++                        PromptOnDelete = 1;
++			break;
+ 		default:
+ 			usage("unrecognized option");
+ 		}
+@@ -344,9 +350,39 @@
+ static void
+ delete_cmd() {
+ 	char	n[MAX_FNAME];
++        char    q[MAX_TEMPSTR];
++        int     ans;
++	struct stat fsbuf;
+ 
+-	log_it(RealUser, Pid, "DELETE", User);
++        /* Check if the user has a crontab file first */
+ 	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
++	if (stat(n, &fsbuf) < 0) {
++            fprintf(stderr, "no crontab for %s\n", User);
++            exit(ERROR_EXIT);
++	}
++
++        if( PromptOnDelete == 1 )
++        {
++            printf("crontab: really delete %s's crontab? (y/n) ", User);
++            fflush(stdout);
++            ans = 0;
++            q[0] = '\0';
++            while ( ans == 0 ) {
++                (void) fgets(q, sizeof q, stdin);
++                switch (islower(q[0]) ? q[0] : tolower(q[0])) {
++                    case 'y':
++                    case 'n':
++                        ans = 1;
++                        break;
++                    default:
++                        fprintf(stderr, "Please enter Y or N: ");
++                }
++            }
++            if ( (q[0] == 'N') || (q[0] == 'n') )
++                exit(OK_EXIT);
++        }
++
++	log_it(RealUser, Pid, "DELETE", User);
+ 	if (unlink(n)) {
+ 		if (errno == ENOENT)
+ 			fprintf(stderr, "no crontab for %s\n", User);
diff --git a/debian/patches/features/control-header-output b/debian/patches/features/control-header-output
new file mode 100644
index 0000000..4cbddcd
--- /dev/null
+++ b/debian/patches/features/control-header-output
@@ -0,0 +1,53 @@
+Subject: Control output of header in crontab -e
+Last-Update: 2010-04-11
+
+Change the default behaviour of outputting a warning header to only outputting
+it when specifically requested so by setting CRONTAB_NOHEADER=N.
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:52.595435667 +0200
++++ patched/crontab.c	2010-05-06 18:18:56.391036364 +0200
+@@ -292,6 +292,10 @@
+ 	char	n[MAX_FNAME];
+ 	FILE	*f;
+ 	int	ch;
++#ifdef DEBIAN
++	int     x;
++	char    *ctnh;
++#endif
+ 
+ 	log_it(RealUser, Pid, "LIST", User);
+ 	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+@@ -307,6 +311,30 @@
+ 	/* file is open. copy to stdout, close.
+ 	 */
+ 	Set_LineNum(1)
++#ifdef DEBIAN
++	  /* DEBIAN: Don't list header lines unless CRONTAB_NOHEADER is
++	     'N'. */
++	  /* ignore the top few comments since we probably put them there.
++	   */
++	  if (!(ctnh = getenv("CRONTAB_NOHEADER")) ||
++	      toupper(*ctnh) != 'N') 
++	    {
++	    for (x = 0;  x < NHEADER_LINES;  x++) {
++	      ch = get_char(f);
++	      if (EOF == ch)
++		break;
++	      if ('#' != ch) {
++		putchar(ch);
++		break;
++	      }
++	      while (EOF != (ch = get_char(f)))
++		if (ch == '\n')
++		  break;
++	      if (EOF == ch)
++		break;
++	    }
++	  }
++#endif
+ 	while (EOF != (ch = get_char(f)))
+ 		putchar(ch);
+ 	fclose(f);
diff --git a/debian/patches/features/crontab-refuse-eof-without-nl b/debian/patches/features/crontab-refuse-eof-without-nl
new file mode 100644
index 0000000..f77a3c5
--- /dev/null
+++ b/debian/patches/features/crontab-refuse-eof-without-nl
@@ -0,0 +1,43 @@
+Subject: Refuse crontabs missing a newline before EOF
+Author: Christian Kastner <debian at kvr.at
+Last-Update: 2010-04-19
+
+Make crontab(1) refuse to add/replace a crontab with a missing newline before
+EOF.
+
+Bug-Debian: http://bugs.debian.org/79037
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:19:00.402560845 +0200
++++ patched/crontab.c	2010-05-06 18:19:02.287668125 +0200
+@@ -819,6 +819,7 @@
+ 	char	n[MAX_FNAME], envstr[MAX_ENVSTR];
+ 	FILE	*tmp;
+ 	int	ch, eof, fd;
++	int	nl = FALSE;
+ 	entry	*e;
+ 	time_t	now = time(NULL);
+ 	char	**envp = env_init();
+@@ -888,6 +889,8 @@
+ 		switch (load_env(envstr, tmp)) {
+ 		case ERR:
+ 			eof = TRUE;
++			if (envstr[0] == '\0')
++				nl = TRUE;
+ 			break;
+ 		case FALSE:
+ 			e = load_entry(tmp, check_error, pw, envp);
+@@ -905,6 +908,13 @@
+ 		return (-1);
+ 	}
+ 
++	if (nl == FALSE) {
++		fprintf(stderr, "new crontab file is missing newline before "
++				"EOF, can't install.\n");
++		fclose(tmp);  unlink(tn);
++		return (-1);
++	}
++
+ 
+ #ifdef HAS_FCHMOD
+ 	if (fchmod(fileno(tmp), 0600) < OK)
diff --git a/debian/patches/features/debian-logging-configuration b/debian/patches/features/debian-logging-configuration
new file mode 100644
index 0000000..7d337df
--- /dev/null
+++ b/debian/patches/features/debian-logging-configuration
@@ -0,0 +1,204 @@
+Subject: Debian logging configuration
+Last-Update: 2010-04-11
+
+Tweak logging to Debian. Among other (smaller) things:
+  * Log to syslog only
+  * Log broken system crontabs (user crontabs are checked by crontab(1))
+  * Log messages added where Debian considered them nice-to-have
+
+Bug-Debian: http://bugs.debian.org/76625
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:46.637435837 +0200
++++ patched/misc.c	2010-05-06 18:18:50.298436009 +0200
+@@ -281,7 +281,8 @@
+ 			log_it("CRON", getpid(), "DEATH", buf);
+ 			exit(ERROR_EXIT);
+ 		}
+-
++		snprintf(buf, MAX_TEMPSTR, "pidfile fd = %d", fd);
++		log_it("CRON", getpid(), "INFO", buf);
+ 		(void) fcntl(fd, F_SETFD, 1);
+ 	}
+ 
+@@ -293,6 +294,7 @@
+ 	/* abandon fd and fp even though the file is open. we need to
+ 	 * keep it open and locked, but we don't need the handles elsewhere.
+ 	 */
++	
+ }
+ 
+ /* get_char(file) : like getc() but increment LineNumber on newlines
+@@ -458,17 +460,14 @@
+ 	char	*event;
+ 	char	*detail;
+ {
+-	PID_T			pid = xpid;
+ #if defined(LOG_FILE)
++	PID_T			pid = xpid;
+ 	char			*msg;
+ 	TIME_T			now = time((TIME_T) 0);
+ 	register struct tm	*t = localtime(&now);
+ 	int 			msg_size;
+ #endif /*LOG_FILE*/
+ 
+-#if defined(SYSLOG)
+-	static int		syslog_open = 0;
+-#endif
+ 
+ #if defined(LOG_FILE)
+ 	/* we assume that MAX_TEMPSTR will hold the date, time, &punctuation.
+@@ -513,21 +512,24 @@
+ #endif /*LOG_FILE*/
+ 
+ #if defined(SYSLOG)
+-	if (!syslog_open) {
+-		/* we don't use LOG_PID since the pid passed to us by
+-		 * our client may not be our own.  therefore we want to
+-		 * print the pid ourselves.
+-		 */
+-# ifdef LOG_DAEMON
+-		openlog(ProgramName, LOG_PID, LOG_CRON);
++
++
++	    /* we don't use LOG_PID since the pid passed to us by
++	     * our client may not be our own.  therefore we want to
++	     * print the pid ourselves.
++	     */
++	    /* SteveG says: That comment is not consistent with the
++	       code, and makes no sense -- I suspect it's a remnant
++	       of a cut-n-paster... */
++# ifdef LOG_CRON
++	openlog(ProgramName, LOG_PID, LOG_CRON);
+ # else
+-		openlog(ProgramName, LOG_PID);
++	openlog(ProgramName, LOG_PID);
+ # endif
+-		syslog_open = TRUE;		/* assume openlog success */
+-	}
+-
+-	syslog(LOG_INFO, "(%s) %s (%s)\n", username, event, detail);
++	  
++	syslog(LOG_INFO, "(%s) %s (%s)", username, event, detail);
+ 
++	closelog();
+ #endif /*SYSLOG*/
+ 
+ #if DEBUGGING
+@@ -541,10 +543,15 @@
+ 
+ void
+ log_close() {
++#if defined(LOG_FILE)
+ 	if (LogFD != ERR) {
+ 		close(LogFD);
+ 		LogFD = ERR;
+ 	}
++#endif
++#if defined(SYSLOG)
++	closelog();
++#endif
+ }
+ 
+ 
+Index: patched/pathnames.h
+===================================================================
+--- patched.orig/pathnames.h	2010-05-06 18:18:49.631436001 +0200
++++ patched/pathnames.h	2010-05-06 18:18:50.298436009 +0200
+@@ -54,7 +54,7 @@
+ #define	ALLOW_FILE	"allow"		/*-*/
+ #define DENY_FILE	"deny"		/*-*/
+ #endif
+-#define LOG_FILE	"log"		/*-*/
++/* #define LOG_FILE	"log"		  -*/
+ 
+ 			/* where should the daemon stick its PID?
+ 			 */
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:48.877435845 +0200
++++ patched/do_command.c	2010-05-06 18:18:50.325296679 +0200
+@@ -257,9 +257,7 @@
+ 
+ 		/* that's the last thing we'll log.  close the log files.
+ 		 */
+-#ifdef SYSLOG
+-		closelog();
+-#endif
++		log_close();
+ 
+ 		/* get new pgrp, void tty, etc.
+ 		 */
+Index: patched/user.c
+===================================================================
+--- patched.orig/user.c	2010-05-06 18:18:48.877435845 +0200
++++ patched/user.c	2010-05-06 18:18:50.325435826 +0200
+@@ -23,8 +23,11 @@
+  */
+ 
+ 
++#include <syslog.h>
++#include <string.h>
+ #include "cron.h"
+ 
++
+ #ifdef WITH_SELINUX
+ #include <selinux/context.h>
+ #include <selinux/selinux.h>
+@@ -127,6 +130,32 @@
+ #endif
+ 
+ 
++#ifdef DEBIAN
++/* Function used to log errors in crontabs from cron daemon. (User
++   crontabs are checked before they're accepted, but system crontabs
++   are not. */
++static char *err_user=NULL;
++
++void
++crontab_error(msg)
++     char *msg;
++{
++  const char *fn;
++  /* Figure out the file name from the username */
++  if (0 == strcmp(err_user,"*system*")) {
++    syslog(LOG_ERR|LOG_CRON,"Error: %s; while reading %s", msg, SYSCRONTAB);
++  } else if (0 == strncmp(err_user,"*system*",8)) {
++    fn = err_user+8;
++    syslog(LOG_ERR|LOG_CRON,"Error: %s; while reading %s/%s", msg, 
++	   SYSCRONDIR,fn);
++  } else {
++    syslog(LOG_ERR|LOG_CRON, "Error: %s; while reading crontab for user %s",
++	   msg, err_user);
++  }
++}
++
++#endif
++
+ void
+ free_user(u)
+ 	user	*u;
+@@ -230,12 +259,21 @@
+ 			}
+ 			goto done;
+ 		case FALSE:
++#ifdef DEBIAN
++			err_user = fname;
++			e = load_entry(file, crontab_error, pw, envp);
++			err_user = NULL;
++#else
+ 			e = load_entry(file, NULL, pw, envp);
++#endif
+ 			if (e) {
+ 				e->next = u->crontab;
+ 				u->crontab = e;
+ 			} else {
+ 				/* stop processing on syntax error */
++				log_it(u->name, getpid(), "ERROR", "Syntax "
++					"error, this crontab file will be "
++					"ignored"); 
+ 				free_user(u);
+ 				u = NULL;
+ 				goto done;
diff --git a/debian/patches/features/debian-paths-and-commands b/debian/patches/features/debian-paths-and-commands
new file mode 100644
index 0000000..3fe6c60
--- /dev/null
+++ b/debian/patches/features/debian-paths-and-commands
@@ -0,0 +1,84 @@
+Subject: Debian paths and commands
+Last-Update: 2010-04-11
+
+User pathnames and commands specific to the Debian platform.
+TODO: _PATH_DEFPATH_ROOT does not appear to be used (see cron.c)
+
+Bug-Debian: http://bugs.debian.org/482284
+Index: patched/pathnames.h
+===================================================================
+--- patched.orig/pathnames.h	2010-05-06 18:18:22.673435429 +0200
++++ patched/pathnames.h	2010-05-06 18:18:46.636435718 +0200
+@@ -28,7 +28,7 @@
+ 			 * to; SPOOL_DIR, ALLOW_FILE, DENY_FILE, and LOG_FILE
+ 			 * are all relative to this directory.
+ 			 */
+-#define CRONDIR		"/var/cron"
++#define CRONDIR		"/var/spool/cron"
+ #endif
+ 
+ 			/* SPOOLDIR is where the crontabs live.
+@@ -39,7 +39,7 @@
+ 			 * newer than they were last time around (or which
+ 			 * didn't exist last time around...)
+ 			 */
+-#define SPOOL_DIR	"tabs"
++#define SPOOL_DIR	"crontabs"
+ 
+ 			/* undefining these turns off their features.  note
+ 			 * that ALLOW_FILE and DENY_FILE must both be defined
+@@ -47,8 +47,13 @@
+ 			 * LOG_FILE or SYSLOG is defined, we don't log.  If
+ 			 * both are defined, we log both ways.
+ 			 */
++#ifdef DEBIAN
++#define	ALLOW_FILE	"/etc/cron.allow"		/*-*/
++#define DENY_FILE	"/etc/cron.deny"		/*-*/
++#else
+ #define	ALLOW_FILE	"allow"		/*-*/
+ #define DENY_FILE	"deny"		/*-*/
++#endif
+ #define LOG_FILE	"log"		/*-*/
+ 
+ 			/* where should the daemon stick its PID?
+@@ -58,7 +63,7 @@
+ #else
+ # define PIDDIR "/etc/"
+ #endif
+-#define PIDFILE		"%scron.pid"
++#define PIDFILE		"%scrond.pid"
+ 
+ 			/* 4.3BSD-style crontab */
+ #define SYSCRONTAB	"/etc/crontab"
+@@ -66,7 +71,9 @@
+ 			/* what editor to use if no EDITOR or VISUAL
+ 			 * environment variable specified.
+ 			 */
+-#if defined(_PATH_VI)
++#if defined(DEBIAN)
++# define EDITOR "/usr/bin/sensible-editor"
++#elif defined(_PATH_VI)
+ # define EDITOR _PATH_VI
+ #else
+ # define EDITOR "/usr/ucb/vi"
+@@ -79,3 +86,7 @@
+ #ifndef _PATH_DEFPATH
+ # define _PATH_DEFPATH "/usr/bin:/bin"
+ #endif
++
++#ifndef _PATH_DEFPATH_ROOT
++# define _PATH_DEFPATH_ROOT "/usr/sbin:/usr/bin:/sbin:/bin"
++#endif
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:44.201560954 +0200
++++ patched/misc.c	2010-05-06 18:18:46.637435837 +0200
+@@ -234,7 +234,7 @@
+ }
+ 
+ 
+-/* acquire_daemonlock() - write our PID into /etc/cron.pid, unless
++/* acquire_daemonlock() - write our PID into /etc/crond.pid, unless
+  *	another daemon is already running, which we detect here.
+  *
+  * note: main() calls us twice; once before forking, once after.
diff --git a/debian/patches/features/debian-specific-issues b/debian/patches/features/debian-specific-issues
new file mode 100644
index 0000000..cab1094
--- /dev/null
+++ b/debian/patches/features/debian-specific-issues
@@ -0,0 +1,38 @@
+Subject: Debian-specific issues
+Last-Update: 2010-04-11
+
+Fix certain issues apparently specific to building on Debian.
+
+IMPORTANT NOTE: These appear to be *very* bogus and should be inspected
+further, so:
+
+NOT Acked
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:37.114561029 +0200
++++ patched/misc.c	2010-05-06 18:18:44.201560954 +0200
+@@ -667,7 +667,7 @@
+ #endif /*MAIL_DATE*/
+ 
+ 
+-#ifdef HAVE_SAVED_SUIDS
++#ifdef HAVE_SAVED_UIDS
+ static int save_euid;
+ int swap_uids() { save_euid = geteuid(); return seteuid(getuid()); }
+ int swap_uids_back() { return seteuid(save_euid); }
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:33.012435990 +0200
++++ patched/do_command.c	2010-05-06 18:18:44.201560954 +0200
+@@ -117,7 +117,11 @@
+ 	 * use wait() explictly.  so we have to disable the signal (which
+ 	 * was inherited from the parent).
+ 	 */
++#ifdef DEBIAN
++	(void) signal(SIGCHLD, SIG_DFL);
++#else
+ 	(void) signal(SIGCHLD, SIG_IGN);
++#endif
+ #else
+ 	/* on system-V systems, we are ignoring SIGCLD.  we have to stop
+ 	 * ignoring it now or the wait() in cron_pclose() won't work.
diff --git a/debian/patches/features/dont-die-on-missing-dirs b/debian/patches/features/dont-die-on-missing-dirs
new file mode 100644
index 0000000..25e64f7
--- /dev/null
+++ b/debian/patches/features/dont-die-on-missing-dirs
@@ -0,0 +1,84 @@
+Subject: Don't die on missing directories
+Author: Justin Pryzby <justinpryzby at users.sourceforge.net>
+Last-Update: 2010-04-19
+
+cron shouldn't just die when it encounters missing dirs.
+
+Bug-Debian: http://bugs.debian.org/470564
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:18:52.595435667 +0200
++++ patched/database.c	2010-05-06 18:19:01.607560756 +0200
+@@ -78,13 +78,15 @@
+ 	 */
+ 	if (stat(SPOOL_DIR, &statbuf) < OK) {
+ 		log_it("CRON", getpid(), "STAT FAILED", SPOOL_DIR);
+-		(void) exit(ERROR_EXIT);
++		statbuf.st_mtime = 0;
+ 	}
+ 
+ 	/* track system crontab file
+ 	 */
+-	if (stat(SYSCRONTAB, &syscron_stat) < OK)
++	if (stat(SYSCRONTAB, &syscron_stat) < OK) {
++		log_it("CRON", getpid(), "STAT FAILED", SYSCRONTAB);
+ 		syscron_stat.st_mtime = 0;
++	}
+ 
+ #ifdef DEBIAN
+ 	/* Check mod time of SYSCRONDIR. This won't tell us if a file
+@@ -93,7 +95,7 @@
+ 	 */
+ 	if (stat(SYSCRONDIR, &syscrond_stat) < OK) {
+ 		log_it("CRON", getpid(), "STAT FAILED", SYSCRONDIR);
+-		(void) exit(ERROR_EXIT);
++		syscrond_stat.st_mtime = 0;
+ 	}
+ 
+ 	/* If SYSCRONDIR was modified, we know that something is changed and
+@@ -175,10 +177,9 @@
+ 	/* Read all the package crontabs. */
+ 	if (!(dir = opendir(SYSCRONDIR))) {
+ 		log_it("CRON", getpid(), "OPENDIR FAILED", SYSCRONDIR);
+-		(void) exit(ERROR_EXIT);
+ 	}
+ 
+-	while (NULL != (dp = readdir(dir))) {
++	while (dir != NULL && NULL != (dp = readdir(dir))) {
+ 		char	fname[MAXNAMLEN+1],
+ 		        tabname[PATH_MAX+1];
+ 
+@@ -208,7 +209,8 @@
+ 				&statbuf, &new_db, old_db);
+ 
+ 	}
+-	closedir(dir);
++	if (dir)
++		closedir(dir);
+ #endif
+ 
+ 	/* we used to keep this dir open all the time, for the sake of
+@@ -217,10 +219,9 @@
+ 	 */
+ 	if (!(dir = opendir(SPOOL_DIR))) {
+ 		log_it("CRON", getpid(), "OPENDIR FAILED", SPOOL_DIR);
+-		(void) exit(ERROR_EXIT);
+ 	}
+ 
+-	while (NULL != (dp = readdir(dir))) {
++	while (dir != NULL && NULL != (dp = readdir(dir))) {
+ 		char	fname[MAXNAMLEN+1],
+ 			tabname[PATH_MAX+1];
+ 
+@@ -238,7 +239,8 @@
+ 		process_crontab(fname, fname, tabname,
+ 				&statbuf, &new_db, old_db);
+ 	}
+-	closedir(dir);
++	if (dir)
++		closedir(dir);
+ 
+ 	/* if we don't do this, then when our children eventually call
+ 	 * getpwnam() in do_command.c's child_process to verify MAILTO=,
diff --git a/debian/patches/features/dont-fail-on-missing-MTA b/debian/patches/features/dont-fail-on-missing-MTA
new file mode 100644
index 0000000..1cae427
--- /dev/null
+++ b/debian/patches/features/dont-fail-on-missing-MTA
@@ -0,0 +1,58 @@
+Subject: Don't fail silently when MTA is not installed 
+Author: Christian Kastner <debian at kvr.at>
+Last-Update: 2010-04-22
+
+When an MTA is not installed (MAILCMD is not available), the attempted piping
+out job output to the MTA fails fatally when the pipe's buffer is exceeded.
+This patch checks if MAILCMD is available before proceeding to pipe output to
+it.
+
+Bug-Debian: http://bugs.debian.org/577133
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:59.066435924 +0200
++++ patched/do_command.c	2010-05-06 18:18:59.713435868 +0200
+@@ -23,6 +23,8 @@
+ #include "cron.h"
+ #include <signal.h>
+ #include <grp.h>
++#include <sys/stat.h>
++#include <unistd.h>
+ #if defined(sequent)
+ # include <sys/universe.h>
+ #endif
+@@ -492,6 +494,8 @@
+ // status.
+ 	
+ 	long pos;
++	struct stat	mcsb;
++	int		statret;	
+ 
+ 	fseek(tmpout, 0, SEEK_END);
+ 	pos = ftell(tmpout);
+@@ -508,6 +512,17 @@
+ 	else if (!*mailto)
+ 		mailto = NULL;
+ 
++	/* Don't send mail if MAILCMD is not available */
++	if ((statret = stat(MAILCMD, &mcsb)) != 0) {
++		Debug(DPROC|DEXT, ("%s not found, not sending mail\n", MAILCMD))
++		if (pos > 0) {
++			log_it("CRON", getpid(), "info", "No MTA installed, discarding output");
++		}
++		goto mail_finished;
++	} else {
++		Debug(DPROC|DEXT, ("%s found, will send mail\n", MAILCMD))
++	}
++
+ 	register FILE	*mail = NULL;
+ 	register int	bytes = 1;
+ 
+@@ -617,6 +632,7 @@
+ 		log_it(usernm, getpid(), "MAIL", "stream error reading output");
+ 	}
+ 
++mail_finished:
+ 	fclose(tmpout);
+ 
+ 	if (log_level >= 2) {
diff --git a/debian/patches/features/iso-time-format b/debian/patches/features/iso-time-format
new file mode 100644
index 0000000..ec247ff
--- /dev/null
+++ b/debian/patches/features/iso-time-format
@@ -0,0 +1,60 @@
+Subject: Use ISO time format
+
+Use ISO time format
+
+
+Index: cron-3.0pl1.orig/misc.c
+===================================================================
+--- cron-3.0pl1.orig.orig/misc.c	2010-04-10 00:29:48.620013489 +0200
++++ cron-3.0pl1.orig/misc.c	2010-04-10 00:29:53.010888665 +0200
+@@ -660,26 +660,36 @@
+ 
+ 
+ #ifdef MAIL_DATE
+-/* Sat, 27 Feb 93 11:44:51 CST
+- * 123456789012345678901234567
++/* Sat, 27 Feb 1993 11:44:51 -0800 (CST)
++ * 1234567890123456789012345678901234567
+  */
+ char *
+ arpadate(clock)
+ 	time_t *clock;
+ {
+-	time_t t = clock ?*clock :time(0L);
++	static char ret[64];	/* zone name might be >3 chars */
++	time_t t = clock ? *clock : time(NULL);
+ 	struct tm *tm = localtime(&t);
+-	static char ret[30];	/* zone name might be >3 chars */
+-	
+-	(void) snprintf(ret, 30, "%s, %2d %s %2d %02d:%02d:%02d %s",
+-		       DowNames[tm->tm_wday],
+-		       tm->tm_mday,
+-		       MonthNames[tm->tm_mon],
+-		       tm->tm_year,
+-		       tm->tm_hour,
+-		       tm->tm_min,
+-		       tm->tm_sec,
+-		       TZONE(*tm));
++	char *qmark;
++	size_t len;
++	int hours = tm->tm_gmtoff / 3600;
++	int minutes = (tm->tm_gmtoff - (hours * 3600)) / 60;
++
++	if (minutes < 0)
++		minutes = -minutes;
++
++	/* Defensive coding (almost) never hurts... */
++	len = strftime(ret, sizeof(ret), "%a, %e %b %Y %T ????? (%Z)", tm);
++	if (len == 0) {
++		ret[0] = '?';
++		ret[1] = '\0';
++		return ret;
++	}
++	qmark = strchr(ret, '?');
++	if (qmark && len - (qmark - ret) >= 6) {
++		snprintf(qmark, 6, "% .2d%.2d", hours, minutes);
++		qmark[5] = ' ';
++	}
+ 	return ret;
+ }
+ #endif /*MAIL_DATE*/
diff --git a/debian/patches/features/mailcmd-dont-timeout b/debian/patches/features/mailcmd-dont-timeout
new file mode 100644
index 0000000..4e66553
--- /dev/null
+++ b/debian/patches/features/mailcmd-dont-timeout
@@ -0,0 +1,447 @@
+Subject: Don't let mailcmd time out with long running jobs
+Author: Justin Pryzby <justinpryzby at users.sourceforge.net>
+Last-Update: 2010-04-22
+
+Long running cron jobs can cause sendmail (or whatever compatible mailer is
+installed) to time out. By writing children's output to a temporary file 
+and waiting for them to terminate instead, this situation can be avoided.
+
+Bug-Debian: http://bugs.debian.org/155109
+Bug-Debian: http://bugs.debian.org/433615
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:58.396435930 +0200
++++ patched/do_command.c	2010-05-06 18:18:59.066435924 +0200
+@@ -111,12 +111,21 @@
+ }
+ 
+ 
++/*
++ * CROND
++ *  - cron (runs child_process);
++ *    - cron (runs exec sh -c 'tab entry');
++ *    - cron (writes any %-style stdin to the command);
++ *    - mail (popen writes any stdout to mailcmd);
++ */
++
+ static void
+ child_process(e, u)
+ 	entry	*e;
+ 	user	*u;
+ {
+-	int		stdin_pipe[2], stdout_pipe[2];
++	int		stdin_pipe[2];
++	FILE		*tmpout;
+ 	register char	*input_data;
+ 	char		*usernm, *mailto;
+ 	int		children = 0;
+@@ -176,10 +185,14 @@
+ 	(void) signal(SIGCLD, SIG_DFL);
+ #endif /*BSD*/
+ 
+-	/* create some pipes to talk to our future child
++	/* create a pipe to talk to our future child
+ 	 */
+ 	pipe(stdin_pipe);	/* child's stdin */
+-	pipe(stdout_pipe);	/* child's stdout */
++	/* child's stdout */
++	if ((tmpout = tmpfile()) == NULL) {
++		log_it("CRON", getpid(), "error", "create tmpfile");
++		exit(ERROR_EXIT);
++	}
+ 	
+ 	/* since we are a forked process, we can diddle the command string
+ 	 * we were passed -- nobody else is going to use it again, right?
+@@ -270,7 +283,6 @@
+ 		 * appropriate circumstances.
+ 		 */
+ 		close(stdin_pipe[WRITE_PIPE]);
+-		close(stdout_pipe[READ_PIPE]);
+ 
+ 		/* grandchild process.  make std{in,out} be the ends of
+ 		 * pipes opened by our daddy; make stderr go to stdout.
+@@ -278,14 +290,14 @@
+ 		/* Closes are unnecessary -- let dup2() do it */
+ 
+ 		  /* close(STDIN) */; dup2(stdin_pipe[READ_PIPE], STDIN);
+-		  /* close(STDOUT) */;  dup2(stdout_pipe[WRITE_PIPE], STDOUT);
++		  dup2(fileno(tmpout), STDOUT);
+ 		  /* close(STDERR)*/; dup2(STDOUT, STDERR);
+ 
+ 
+-		/* close the pipes we just dup'ed.  The resources will remain.
++		/* close the pipe we just dup'ed.  The resources will remain.
+ 		 */
+ 		close(stdin_pipe[READ_PIPE]);
+-		close(stdout_pipe[WRITE_PIPE]);
++		// Don't do this: fclose(tmpout);
+ 
+ 		/* set our login universe.  Do this in the grandchild
+ 		 * so that the child can invoke /usr/lib/sendmail
+@@ -370,11 +382,10 @@
+ 
+ 	Debug(DPROC, ("[%d] child continues, closing pipes\n", getpid()))
+ 
+-	/* close the ends of the pipe that will only be referenced in the
++	/* close the end of the pipe that will only be referenced in the
+ 	 * grandchild process...
+ 	 */
+ 	close(stdin_pipe[READ_PIPE]);
+-	close(stdout_pipe[WRITE_PIPE]);
+ 
+ 	/*
+ 	 * write, to the pipe connected to child's stdin, any input specified
+@@ -395,11 +406,6 @@
+ 
+ 		Debug(DPROC, ("[%d] child2 sending data to grandchild\n", getpid()))
+ 
+-		/* close the pipe we don't use, since we inherited it and
+-		 * are part of its reference count now.
+-		 */
+-		close(stdout_pipe[READ_PIPE]);
+-
+ 		/* translation:
+ 		 *	\% -> %
+ 		 *	%  -> \n
+@@ -447,167 +453,12 @@
+ 	 * when the grandchild exits, we'll get EOF.
+ 	 */
+ 
+-	Debug(DPROC, ("[%d] child reading output from grandchild\n", getpid()))
+-
+-	/*local*/{
+-		register FILE	*in = fdopen(stdout_pipe[READ_PIPE], "r");
+-		register int	ch = getc(in);
+-
+-		if (ch != EOF) {
+-			register FILE	*mail = NULL;
+-			register int	bytes = 1;
+-			int		status = 0;
+-
+-			Debug(DPROC|DEXT,
+-				("[%d] got data (%x:%c) from grandchild\n",
+-					getpid(), ch, ch))
+-
+-			/* get name of recipient.  this is MAILTO if set to a
+-			 * valid local username; USER otherwise.
+-			 */
+-			if (mailto) {
+-				/* MAILTO was present in the environment
+-				 */
+-				if (!*mailto) {
+-					/* ... but it's empty. set to NULL
+-					 */
+-					mailto = NULL;
+-				}
+-			} else {
+-				/* MAILTO not present, set to USER.
+-				 */
+-				mailto = usernm;
+-			}
+-		
+-			/* if we are supposed to be mailing, MAILTO will
+-			 * be non-NULL.  only in this case should we set
+-			 * up the mail command and subjects and stuff...
+-			 */
+-
+-			if (mailto) {
+-				register char	**env;
+-                        	char    **jobenv = build_env(e->envp); 
+-				auto char	mailcmd[MAX_COMMAND];
+-				auto char	hostname[MAXHOSTNAMELEN];
+-				char    *content_type = env_get("CONTENT_TYPE",jobenv),
+-					*content_transfer_encoding = env_get("CONTENT_TRANSFER_ENCODING",jobenv);
+-
+-
+-				(void) gethostname(hostname, MAXHOSTNAMELEN);
+-				(void) snprintf(mailcmd, sizeof(mailcmd),
+-				    MAILARGS, MAILCMD, mailto);
+-				if (!(mail = cron_popen(mailcmd, "w", e))) {
+-					perror(MAILCMD);
+-					(void) _exit(ERROR_EXIT);
+-				}
+-				fprintf(mail, "From: root (Cron Daemon)\n");
+-				fprintf(mail, "To: %s\n", mailto);
+-				fprintf(mail, "Subject: Cron <%s@%s> %s\n",
+-					usernm, first_word(hostname, "."),
+-					e->cmd);
+-# if defined(MAIL_DATE)
+-				fprintf(mail, "Date: %s\n",
+-					arpadate(&StartTime));
+-# endif /* MAIL_DATE */
+-                               if ( content_type == 0L ) {
+-                                       fprintf(mail, "Content-Type: text/plain; charset=%s\n",
+-                                               cron_default_mail_charset
+-                                              );
+-                               } else {   
+-				    /* user specified Content-Type header.
+-				     * disallow new-lines for security reasons
+-				     * (else users could specify arbitrary mail headers!)
+-				     */
+-				       char *nl=content_type;
+-                                       size_t ctlen = strlen(content_type);
+-
+-                                       while(  (*nl != '\0')
+-                                            && ((nl=strchr(nl,'\n')) != 0L)
+-                                            && (nl < (content_type+ctlen))
+-                                            ) *nl = ' ';
+-                                       fprintf(mail,"Content-Type: %s\n", content_type);
+-                               }
+-                               if ( content_transfer_encoding != 0L ) {
+-                                       char *nl=content_transfer_encoding;
+-                                       size_t ctlen = strlen(content_transfer_encoding);
+-                                       while(  (*nl != '\0')
+-                                            && ((nl=strchr(nl,'\n')) != 0L)
+-                                            && (nl < (content_transfer_encoding+ctlen))
+-                                            ) *nl = ' ';
+-
+-                                       fprintf(mail,"Content-Transfer-Encoding: %s\n", content_transfer_encoding);
+-                               }
+-
+-
+-				for (env = e->envp;  *env;  env++)
+-					fprintf(mail, "X-Cron-Env: <%s>\n",
+-						*env);
+-				fprintf(mail, "\n");
+-
+-				/* this was the first char from the pipe
+-				 */
+-				putc(ch, mail);
+-			}
+-
+-			/* we have to read the input pipe no matter whether
+-			 * we mail or not, but obviously we only write to
+-			 * mail pipe if we ARE mailing.
+-			 */
+-
+-			while (EOF != (ch = getc(in))) {
+-				bytes++;
+-				if (mailto)
+-					putc(ch, mail);
+-			}
+-
+-			/* only close pipe if we opened it -- i.e., we're
+-			 * mailing...
+-			 */
+-
+-			if (mailto) {
+-				Debug(DPROC, ("[%d] closing pipe to mail\n",
+-					getpid()))
+-				/* Note: the pclose will probably see
+-				 * the termination of the grandchild
+-				 * in addition to the mail process, since
+-				 * it (the grandchild) is likely to exit
+-				 * after closing its stdout.
+-				 */
+-				status = cron_pclose(mail);
+-			}
+-
+-			/* if there was output and we could not mail it,
+-			 * log the facts so the poor user can figure out
+-			 * what's going on.
+-			 */
+-			if (mailto && status) {
+-				char buf[MAX_TEMPSTR];
+-
+-				snprintf(buf, MAX_TEMPSTR,
+-			"mailed %d byte%s of output but got status 0x%04x\n",
+-					bytes, (bytes==1)?"":"s",
+-					status);
+-				log_it(usernm, getpid(), "MAIL", buf);
+-			}
+-
+-		} /*if data from grandchild*/
+-
+-		if (log_level >= 2) {
+-			char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
+-
+-			log_it(usernm, getpid(), "END", x);
+-			free(x);
+-		}
+-
+-		Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
+-
+-		fclose(in);	/* also closes stdout_pipe[READ_PIPE] */
+-	}
+-
+ 	/* wait for children to die.
+ 	 */
++	int status = 0;
+ 	for (;  children > 0;  children--)
+ 	{
++		char		msg[256];
+ 		WAIT_T		waiter;
+ 		PID_T		pid;
+ 
+@@ -615,16 +466,165 @@
+ 			getpid(), children))
+ 		pid = wait(&waiter);
+ 		if (pid < OK) {
+-			Debug(DPROC, ("[%d] no more grandchildren--mail written?\n",
+-				getpid()))
++			Debug(DPROC, ("[%d] no more grandchildren\n", getpid()))
+ 			break;
+ 		}
+-		Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x",
++		Debug(DPROC, ("[%d] grandchild #%d finished, status=%04x\n",
+ 			getpid(), pid, WEXITSTATUS(waiter)))
+-		if (WIFSIGNALED(waiter) && WCOREDUMP(waiter))
+-			Debug(DPROC, (", dumped core"))
+-		Debug(DPROC, ("\n"))
++
++		if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
++			status = waiter;
++			snprintf(msg, 256, "grandchild #%d failed with exit "
++				"status %d", pid, WEXITSTATUS(waiter));
++			log_it("CRON", getpid(), "error", msg);
++		} else if (WIFSIGNALED(waiter)) {
++			status = waiter;
++			snprintf(msg, 256, "grandchild #%d terminated by signal"
++				" %d%s", pid, WTERMSIG(waiter),
++				WCOREDUMP(waiter) ? ", dumped core" : "");
++			log_it("CRON", getpid(), "error", msg);
++		} 
+ 	}
++
++// Finally, send any output of the command to the mailer; also, alert
++// the user if their job failed.  Avoid popening the mailcmd until now
++// since sendmail may time out, and to write info about the exit
++// status.
++	
++	long pos;
++
++	fseek(tmpout, 0, SEEK_END);
++	pos = ftell(tmpout);
++	fseek(tmpout, 0, SEEK_SET);
++
++	Debug(DPROC|DEXT, ("[%d] got %ld bytes data from grandchild tmpfile\n",
++				getpid(), (long) pos))
++	if (pos == 0 && status == 0)
++		return;
++
++	// get name of recipient.
++	if (mailto == NULL)
++		mailto = usernm;
++	else if (!*mailto)
++		mailto = NULL;
++
++	register FILE	*mail = NULL;
++	register int	bytes = 1;
++
++	register char	**env;
++	char    	**jobenv = build_env(e->envp); 
++	auto char	mailcmd[MAX_COMMAND];
++	auto char	hostname[MAXHOSTNAMELEN];
++	char    	*content_type = env_get("CONTENT_TYPE",jobenv),
++			*content_transfer_encoding = env_get("CONTENT_TRANSFER_ENCODING",jobenv);
++
++	(void) gethostname(hostname, MAXHOSTNAMELEN);
++	(void) snprintf(mailcmd, sizeof(mailcmd),
++			MAILARGS, MAILCMD, mailto);
++	if (!(mail = cron_popen(mailcmd, "w", e))) {
++		perror(MAILCMD);
++		(void) _exit(ERROR_EXIT);
++	}
++	fprintf(mail, "From: root (Cron Daemon)\n");
++	fprintf(mail, "To: %s\n", mailto);
++	fprintf(mail, "Subject: Cron <%s@%s> %s%s\n",
++			usernm, first_word(hostname, "."),
++			e->cmd, status?" (failed)":"");
++# if defined(MAIL_DATE)
++	fprintf(mail, "Date: %s\n",
++			arpadate(&StartTime));
++# endif /* MAIL_DATE */
++	if ( content_type == 0L ) {
++		fprintf(mail, "Content-Type: text/plain; charset=%s\n",
++				cron_default_mail_charset
++		       );
++	} else {   
++		/* user specified Content-Type header.
++		 * disallow new-lines for security reasons
++		 * (else users could specify arbitrary mail headers!)
++		 */
++		char *nl=content_type;
++		size_t ctlen = strlen(content_type);
++
++		while(  (*nl != '\0')
++				&& ((nl=strchr(nl,'\n')) != 0L)
++				&& (nl < (content_type+ctlen))
++		     ) *nl = ' ';
++		fprintf(mail,"Content-Type: %s\n", content_type);
++	}
++	if ( content_transfer_encoding != 0L ) {
++		char *nl=content_transfer_encoding;
++		size_t ctlen = strlen(content_transfer_encoding);
++		while(  (*nl != '\0')
++				&& ((nl=strchr(nl,'\n')) != 0L)
++				&& (nl < (content_transfer_encoding+ctlen))
++		     ) *nl = ' ';
++
++		fprintf(mail,"Content-Transfer-Encoding: %s\n", content_transfer_encoding);
++	}
++
++	for (env = e->envp;  *env;  env++)
++		fprintf(mail, "X-Cron-Env: <%s>\n",
++				*env);
++	fputc('\n', mail);
++
++	if (WIFEXITED(status) && WEXITSTATUS(status)) {
++		status = WEXITSTATUS(status);
++		fprintf(mail, "command failed with exit status %d\n\n", status);
++	} else if (WIFSIGNALED(status)) {
++		fprintf(mail, "command terminated by signal %d%s\n\n",
++				WTERMSIG(status),
++				WCOREDUMP(status)?", dumped core":"");
++	}
++
++// Append the actual output of the child to the mail
++	
++	char buf[4096];
++	int ret, remain;
++
++	while(1) {
++		if ((ret = fread(buf, 1, sizeof(buf), tmpout)) == 0)
++			break;
++		for (remain = ret; remain != 0; ) {
++			ret = fwrite(buf, 1, remain, mail);
++			if (ret > 0) {
++				remain -= ret;
++				continue;
++			}
++			// XXX error
++			break;
++		}
++	}
++
++	Debug(DPROC, ("[%d] closing pipe to mail\n", getpid()))
++	status = cron_pclose(mail);
++
++	/* if there was output and we could not mail it,
++	 * log the facts so the poor user can figure out
++	 * what's going on.
++	 */
++	if (status) {
++		char buf[MAX_TEMPSTR];
++		snprintf(buf, MAX_TEMPSTR,
++				"mailed %d byte%s of output; "
++				"but got status 0x%04x, "
++				"\n",
++				bytes, (bytes==1)?"":"s", status);
++		log_it(usernm, getpid(), "MAIL", buf);
++	}
++
++	if (ferror(tmpout)) {
++		log_it(usernm, getpid(), "MAIL", "stream error reading output");
++	}
++
++	fclose(tmpout);
++
++	if (log_level >= 2) {
++		char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
++		log_it(usernm, getpid(), "END", x);
++		free(x);
++	}
++
+ #if defined(USE_PAM)
+ 	pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
+ 	retcode = pam_close_session(pamh, PAM_SILENT);
diff --git a/debian/patches/features/no-argument-is-stdin b/debian/patches/features/no-argument-is-stdin
new file mode 100644
index 0000000..7ee6cfa
--- /dev/null
+++ b/debian/patches/features/no-argument-is-stdin
@@ -0,0 +1,23 @@
+Subject: crontab without argument is stdin
+Last-Update: 2010-04-11
+
+If crontab is run without argument then it will read stdin to replace the
+users crontab. This way it is POSIXLY_CORRECT.
+
+Bug-Debian: http://bugs.debian.org/514062
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:57.762561131 +0200
++++ patched/crontab.c	2010-05-06 18:19:00.402560845 +0200
+@@ -109,6 +109,9 @@
+ #if defined(BSD)
+ 	setlinebuf(stderr);
+ #endif
++	if (argv[1] == NULL) {
++		argv[1] = "-";
++	}	
+ 	parse_args(argc, argv);		/* sets many globals, opens a file */
+ 	set_cron_cwd();
+ 	if (!allowed(User)) {
diff --git a/debian/patches/features/option-log-completed-jobs b/debian/patches/features/option-log-completed-jobs
new file mode 100644
index 0000000..ad53c1d
--- /dev/null
+++ b/debian/patches/features/option-log-completed-jobs
@@ -0,0 +1,77 @@
+Subject: Option to log completed jobs
+Last-Update: 2010-04-11
+
+Provide an option to log completed jobs if requested so.
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:55.651562056 +0200
++++ patched/cron.h	2010-05-06 18:18:58.395435796 +0200
+@@ -292,7 +292,7 @@
+ 
+ int	stay_foreground;
+ int     lsbsysinit_mode;
+-
++int     log_level = 1;
+ char    cron_default_mail_charset[MAX_ENVSTR] = "";
+ 
+ # if DEBUGGING
+@@ -308,6 +308,7 @@
+ 		*DowNames[],
+ 		*ProgramName;
+ extern  int     lsbsysinit_mode;
++extern  int     log_level;
+ extern	int	LineNumber;
+ extern	time_t	StartTime;
+ extern  time_min timeRunning;
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:55.651562056 +0200
++++ patched/cron.c	2010-05-06 18:18:58.396435930 +0200
+@@ -467,7 +467,7 @@
+ 	stay_foreground = 0;
+         lsbsysinit_mode = 0;
+ 
+-	while (EOF != (argch = getopt(argc, argv, "lfx:"))) {
++	while (EOF != (argch = getopt(argc, argv, "lfx:L:"))) {
+ 		switch (argch) {
+ 		default:
+ 			usage();
+@@ -481,6 +481,9 @@
+                 case 'l':
+                     lsbsysinit_mode = 1;
+                     break;
++		case 'L':
++		    log_level = atoi(optarg);
++		    break;
+ 		}
+ 	}
+ }
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:54.665561020 +0200
++++ patched/do_command.c	2010-05-06 18:18:58.396435930 +0200
+@@ -248,7 +248,7 @@
+ 		 * the actual user command shell was going to get and the
+ 		 * PID is part of the log message.
+ 		 */
+-		/*local*/{
++		if (log_level >= 1) {
+ 			char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
+ 
+ 			log_it(usernm, getpid(), "CMD", x);
+@@ -592,6 +592,13 @@
+ 
+ 		} /*if data from grandchild*/
+ 
++		if (log_level >= 2) {
++			char *x = mkprints((u_char *)e->cmd, strlen(e->cmd));
++
++			log_it(usernm, getpid(), "END", x);
++			free(x);
++		}
++
+ 		Debug(DPROC, ("[%d] got EOF from grandchild\n", getpid()))
+ 
+ 		fclose(in);	/* also closes stdout_pipe[READ_PIPE] */
diff --git a/debian/patches/features/pam-env-support b/debian/patches/features/pam-env-support
new file mode 100644
index 0000000..9fc88c3
--- /dev/null
+++ b/debian/patches/features/pam-env-support
@@ -0,0 +1,69 @@
+Subject: Support pam_env
+Last-Update: 2010-04-11
+
+Enable use of pam_env for cron's environment.
+
+IMPORTANT NOTE: This currently only (or mostly) affects commands launched by
+crontab entries. Other commands run (such as mail notification via MAILTO) do
+not use this code. This is not really that big of an issue (eg. why would
+anyone force MAILTO via /etc/environment), but it should be documented
+somewhere.
+
+Bug-Debian: http://bugs.debian.org/203737
+Bug-Debian: http://bugs.debian.org/511684
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:47.437435738 +0200
++++ patched/do_command.c	2010-05-06 18:18:48.182560885 +0200
+@@ -46,6 +46,31 @@
+ static void		child_process __P((entry *, user *)),
+ 			do_univ __P((user *));
+ 
++/* Build up the job environment from the PAM environment plus the
++   crontab environment */
++static char ** build_env(char **cronenv)
++{
++        char **jobenv = cronenv;
++#if defined(USE_PAM)
++        char **pamenv = pam_getenvlist(pamh);
++        char *cronvar;
++        int count = 0;
++
++        jobenv = env_copy(pamenv);
++
++        /* Now add the cron environment variables. Since env_set()
++           overwrites existing variables, this will let cron's
++           environment settings override pam's */
++
++        while ((cronvar = cronenv[count++])) {
++                if (!(jobenv = env_set(jobenv, cronvar))) {
++                        syslog(LOG_ERR, "Setting Cron environment variable %s failed", cronvar);
++                        return NULL;
++                }
++        }
++#endif
++    return jobenv;
++}
+ 
+ void
+ do_command(e, u)
+@@ -296,8 +321,8 @@
+ 		/* exec the command.
+ 		 */
+ 		{
+-			char	*shell = env_get("SHELL", e->envp);
+-
++                        char    **jobenv = build_env(e->envp); 
++                        char	*shell = env_get("SHELL", jobenv);
+ # if DEBUGGING
+ 			if (DebugFlags & DTEST) {
+ 				fprintf(stderr,
+@@ -307,7 +332,7 @@
+ 				_exit(OK_EXIT);
+ 			}
+ # endif /*DEBUGGING*/
+-			execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
++                        execle(shell, shell, "-c", e->cmd, (char *)0, jobenv);
+ 			fprintf(stderr, "%s: execle: %s\n", shell, strerror(errno));
+ 			_exit(ERROR_EXIT);
+ 		}
diff --git a/debian/patches/features/pam-support b/debian/patches/features/pam-support
new file mode 100644
index 0000000..83ff337
--- /dev/null
+++ b/debian/patches/features/pam-support
@@ -0,0 +1,99 @@
+Subject: PAM support
+Last-Update: 2010-04-11
+Author: Topi Miettinen <Topi.Miettinen at nic.fi>
+
+General support for PAM. Not available on the Hurd.
+
+Bug-Debian: https://bugs.debian.org/68366
+Bug-Debian: https://bugs.debian.org/67586
+Bug-Debian: https://bugs.debian.org/70028
+Bug-Debian: https://bugs.debian.org/75408
+Index: patched/Makefile
+===================================================================
+--- patched.orig/Makefile	2010-05-06 18:18:44.879435811 +0200
++++ patched/Makefile	2010-05-06 18:18:47.436487807 +0200
+@@ -55,7 +55,7 @@
+ INCLUDE		=	-I.
+ #INCLUDE	=
+ #<<need getopt()>>
+-LIBS		=
++LIBS		= $(PAM_LIBS)
+ #<<optimize or debug?>>
+ OPTIM		=	-O2
+ #OPTIM		=	-g
+@@ -74,7 +74,7 @@
+ # Allow override from command line
+ DEBUG_DEFS = -DDEBUGGING=0   
+ # The -DUSE_SIGCHLD is needed for the Alpha port
+-DEFS = -DDEBIAN -DUSE_SIGCHLD $(DEBUG_DEFS)
++DEFS = -DDEBIAN -DUSE_SIGCHLD $(DEBUG_DEFS) $(PAM_DEFS)
+ #(SGI IRIX systems need this)
+ #DEFS		=	-D_BSD_SIGNALS -Dconst=
+ #<<the name of the BSD-like install program>>
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:44.201560954 +0200
++++ patched/do_command.c	2010-05-06 18:18:47.437435738 +0200
+@@ -29,6 +29,18 @@
+ #if defined(SYSLOG)
+ # include <syslog.h>
+ #endif
++#if defined(USE_PAM)
++#include <security/pam_appl.h>
++static pam_handle_t *pamh = NULL;
++static const struct pam_conv conv = {
++	NULL
++};
++#define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \
++	fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \
++	syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \
++	pam_end(pamh, retcode); exit(1); \
++   }
++#endif
+ 
+ 
+ static void		child_process __P((entry *, user *)),
+@@ -79,6 +91,10 @@
+ 	char		*usernm, *mailto;
+ 	int		children = 0;
+ 
++#if defined(USE_PAM)
++	int		retcode = 0;
++#endif
++
+ 	Debug(DPROC, ("[%d] child_process('%s')\n", getpid(), e->cmd))
+ 
+ 	/* mark ourselves as different to PS command watchers by upshifting
+@@ -172,6 +188,20 @@
+ 		*p = '\0';
+ 	}
+ 
++#if defined(USE_PAM)
++	retcode = pam_start("cron", usernm, &conv, &pamh);
++	PAM_FAIL_CHECK;
++	retcode = pam_set_item(pamh, PAM_TTY, "cron");
++	PAM_FAIL_CHECK;
++	retcode = pam_acct_mgmt(pamh, PAM_SILENT);
++	PAM_FAIL_CHECK;
++	retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT);
++	PAM_FAIL_CHECK;
++	retcode = pam_open_session(pamh, PAM_SILENT);
++	PAM_FAIL_CHECK;
++
++#endif
++
+ 	/* fork again, this time so we can exec the user's command.
+ 	 */
+ 	switch (vfork()) {
+@@ -509,6 +539,11 @@
+ 			Debug(DPROC, (", dumped core"))
+ 		Debug(DPROC, ("\n"))
+ 	}
++#if defined(USE_PAM)
++	pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
++	retcode = pam_close_session(pamh, PAM_SILENT);
++	pam_end(pamh, retcode);
++#endif
+ }
+ 
+ 
diff --git a/debian/patches/features/properly-handle-time-skips b/debian/patches/features/properly-handle-time-skips
new file mode 100644
index 0000000..94fe8f0
--- /dev/null
+++ b/debian/patches/features/properly-handle-time-skips
@@ -0,0 +1,486 @@
+Subject: Properly handle time skips
+Last-Update: 2010-04-11
+
+Properly handle time skips, especially those related to Daylight Savings Time.
+It should be noted that this fix is not yet considered complete.
+
+http://bugs.debian.org/8499
+http://bugs.debian.org/217836
+http://bugs.debian.org/458123
+http://bugs.debian.org/474157
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:49.631436001 +0200
++++ patched/cron.h	2010-05-06 18:18:51.094436073 +0200
+@@ -40,6 +40,13 @@
+ #include "config.h"
+ #include "externs.h"
+ 
++#if SYS_TIME_H
++# include <sys/time.h>
++#else
++# include <time.h>
++#endif
++
++
+ #ifdef WITH_SELINUX
+ #include <selinux/selinux.h>
+ #endif
+@@ -125,6 +132,10 @@
+ 			 LineNumber = ln; \
+ 			}
+ 
++typedef int time_min;
++
++#define SECONDS_PER_MINUTE 60
++
+ #define	FIRST_MINUTE	0
+ #define	LAST_MINUTE	59
+ #define	MINUTE_COUNT	(LAST_MINUTE - FIRST_MINUTE + 1)
+@@ -167,6 +178,8 @@
+ #define	DOM_STAR	0x01
+ #define	DOW_STAR	0x02
+ #define	WHEN_REBOOT	0x04
++#define MIN_STAR	0x08
++#define HR_STAR		0x10
+ } entry;
+ 
+ 			/* the crontab database will be a list of the
+@@ -226,6 +239,8 @@
+ 		allowed __P((char *)),
+ 		strdtb __P((char *));
+ 
++long            get_gmtoff(time_t *, struct tm *);
++
+ char		*env_get __P((char *, char **)),
+ 		*arpadate __P((time_t *)),
+ 		*mkprints __P((unsigned char *, unsigned int)),
+@@ -269,7 +284,11 @@
+ 
+ char	*ProgramName;
+ int	LineNumber;
+-time_t	TargetTime;
++time_t	StartTime;
++time_min timeRunning;
++time_min virtualTime;
++time_min clockTime;
++static long GMToff;
+ 
+ int     lsbsysinit_mode;
+ 
+@@ -287,7 +306,10 @@
+ 		*ProgramName;
+ extern  int     lsbsysinit_mode;
+ extern	int	LineNumber;
+-extern	time_t	TargetTime;
++extern	time_t	StartTime;
++extern  time_min timeRunning;
++extern  time_min virtualTime;
++extern  time_min clockTime;
+ # if DEBUGGING
+ extern	int	DebugFlags;
+ extern	char	*DebugFlagNames[];
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:35.745561147 +0200
++++ patched/entry.c	2010-05-06 18:18:51.094436073 +0200
+@@ -157,6 +157,7 @@
+ 			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
+ 			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+ 			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
++			e->flags |= HR_STAR;
+ 		} else {
+ 			ecode = e_timespec;
+ 			goto eof;
+@@ -164,6 +165,8 @@
+ 	} else {
+ 		Debug(DPARS, ("load_entry()...about to parse numerics\n"))
+ 
++		if (ch == '*')
++			e->flags |= MIN_STAR;
+ 		ch = get_list(e->minute, FIRST_MINUTE, LAST_MINUTE,
+ 			      PPC_NULL, ch, file);
+ 		if (ch == EOF) {
+@@ -174,6 +177,8 @@
+ 		/* hours
+ 		 */
+ 
++		if (ch == '*')
++			e->flags |= HR_STAR;
+ 		ch = get_list(e->hour, FIRST_HOUR, LAST_HOUR,
+ 			      PPC_NULL, ch, file);
+ 		if (ch == EOF) {
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:50.325296679 +0200
++++ patched/do_command.c	2010-05-06 18:18:51.094436073 +0200
+@@ -503,7 +503,7 @@
+ 					e->cmd);
+ # if defined(MAIL_DATE)
+ 				fprintf(mail, "Date: %s\n",
+-					arpadate(&TargetTime));
++					arpadate(&StartTime));
+ # endif /* MAIL_DATE */
+ 				for (env = e->envp;  *env;  env++)
+ 					fprintf(mail, "X-Cron-Env: <%s>\n",
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:49.632435697 +0200
++++ patched/cron.c	2010-05-06 18:18:51.095435790 +0200
+@@ -25,20 +25,15 @@
+ 
+ #include "cron.h"
+ #include <signal.h>
+-#if SYS_TIME_H
+-# include <sys/time.h>
+-#else
+-# include <time.h>
+-#endif
+ 
+ #include <sys/types.h>
+ #include <fcntl.h>
+ 
+ static	void	usage __P((void)),
+ 		run_reboot_jobs __P((cron_db *)),
+-		cron_tick __P((cron_db *)),
+-		cron_sync __P((void)),
+-		cron_sleep __P((void)),
++		find_jobs __P((time_min, cron_db *, int, int)),
++		set_time __P((int)),
++		cron_sleep __P((time_min)),
+ #ifdef USE_SIGCHLD
+ 		sigchld_handler __P((int)),
+ #endif
+@@ -137,23 +132,126 @@
+ 	database.sysd_mtime = (time_t) 0;
+ #endif
+ 	load_database(&database);
++
++	set_time(TRUE);
+ 	run_reboot_jobs(&database);
+-	cron_sync();
++	timeRunning = virtualTime = clockTime;
++
++	/*
++	 * too many clocks, not enough time (Al. Einstein)
++	 * These clocks are in minutes since the epoch (time()/60).
++	 * virtualTime: is the time it *would* be if we woke up
++	 * promptly and nobody ever changed the clock. It is
++	 * monotonically increasing... unless a timejump happens.
++	 * At the top of the loop, all jobs for 'virtualTime' have run.
++	 * timeRunning: is the time we last awakened.
++	 * clockTime: is the time when set_time was last called.
++	 */
+ 	while (TRUE) {
+-# if DEBUGGING
+-		if (!(DebugFlags & DTEST))
+-# endif /*DEBUGGING*/
+-			cron_sleep();
++		time_min timeDiff;
++		int wakeupKind;
++
++		/* ... wait for the time (in minutes) to change ... */
++		do {
++			cron_sleep(timeRunning + 1);
++			set_time(FALSE);
++		} while (clockTime == timeRunning);
++		timeRunning = clockTime;
+ 
+ 		load_database(&database);
+ 
+-		/* do this iteration
++		/*
++		 * ... calculate how the current time differs from
++		 * our virtual clock. Classify the change into one
++		 * of 4 cases
+ 		 */
+-		cron_tick(&database);
++		timeDiff = timeRunning - virtualTime;
+ 
+-		/* sleep 1 minute
+-		 */
+-		TargetTime += 60;
++		Debug(DSCH, ("[%d] pulse: %d = %d - %d\n",
++            	    getpid(), timeDiff, timeRunning, virtualTime));
++
++		/* shortcut for the most common case */
++		if (timeDiff == 1) {
++			virtualTime = timeRunning;
++			find_jobs(virtualTime, &database, TRUE, TRUE);
++		} else {
++			wakeupKind = -1;
++			if (timeDiff > -(3*MINUTE_COUNT))
++				wakeupKind = 0;
++			if (timeDiff > 0)
++				wakeupKind = 1;
++			if (timeDiff > 5)
++				wakeupKind = 2;
++			if (timeDiff > (3*MINUTE_COUNT))
++				wakeupKind = 3;
++
++			switch (wakeupKind) {
++			case 1:
++				/*
++				 * case 1: timeDiff is a small positive number
++				 * (wokeup late) run jobs for each virtual minute
++				 * until caught up.
++				 */
++				Debug(DSCH, ("[%d], normal case %d minutes to go\n",
++				    getpid(), timeRunning - virtualTime))
++				do {
++					if (job_runqueue())
++						sleep(10);
++					virtualTime++;
++					find_jobs(virtualTime, &database, TRUE, TRUE);
++				} while (virtualTime< timeRunning);
++				break;
++
++			case 2:
++				/*
++				 * case 2: timeDiff is a medium-sized positive number,
++				 * for example because we went to DST run wildcard
++				 * jobs once, then run any fixed-time jobs that would
++				 * otherwise be skipped if we use up our minute
++				 * (possible, if there are a lot of jobs to run) go
++				 * around the loop again so that wildcard jobs have
++				 * a chance to run, and we do our housekeeping
++				 */
++				Debug(DSCH, ("[%d], DST begins %d minutes to go\n",
++				    getpid(), timeRunning - virtualTime))
++				/* run wildcard jobs for current minute */
++				find_jobs(timeRunning, &database, TRUE, FALSE);
++	
++				/* run fixed-time jobs for each minute missed */ 
++				do {
++					if (job_runqueue())
++						sleep(10);
++					virtualTime++;
++					find_jobs(virtualTime, &database, FALSE, TRUE);
++					set_time(FALSE);
++				} while (virtualTime< timeRunning &&
++				    clockTime == timeRunning);
++				break;
++	
++			case 0:
++				/*
++				 * case 3: timeDiff is a small or medium-sized
++				 * negative num, eg. because of DST ending just run
++				 * the wildcard jobs. The fixed-time jobs probably
++				 * have already run, and should not be repeated
++				 * virtual time does not change until we are caught up
++				 */
++				Debug(DSCH, ("[%d], DST ends %d minutes to go\n",
++				    getpid(), virtualTime - timeRunning))
++				find_jobs(timeRunning, &database, TRUE, FALSE);
++				break;
++			default:
++				/*
++				 * other: time has changed a *lot*,
++				 * jump virtual time, and run everything
++				 */
++				Debug(DSCH, ("[%d], clock jumped\n", getpid()))
++				virtualTime = timeRunning;
++				find_jobs(timeRunning, &database, TRUE, TRUE);
++			}
++		}
++		/* jobs to be run (if any) are loaded. clear the queue */
++		job_runqueue();
+ 	}
+ }
+ 
+@@ -177,10 +275,14 @@
+ 
+ 
+ static void
+-cron_tick(db)
++find_jobs(vtime, db, doWild, doNonWild)
++	time_min vtime;
+ 	cron_db	*db;
++	int doWild;
++	int doNonWild;
+ {
+- 	register struct tm	*tm = localtime(&TargetTime);
++	time_t   virtualSecond  = vtime * SECONDS_PER_MINUTE;
++	register struct tm 	*tm = gmtime(&virtualSecond);
+ 	register int		minute, hour, dom, month, dow;
+ 	register user		*u;
+ 	register entry		*e;
+@@ -193,8 +295,9 @@
+ 	month = tm->tm_mon +1 /* 0..11 -> 1..12 */ -FIRST_MONTH;
+ 	dow = tm->tm_wday -FIRST_DOW;
+ 
+-	Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d)\n",
+-		getpid(), minute, hour, dom, month, dow))
++	Debug(DSCH, ("[%d] tick(%d,%d,%d,%d,%d) %s %s\n",
++		getpid(), minute, hour, dom, month, dow,
++		doWild?" ":"No wildcard",doNonWild?" ":"Wildcard only"))
+ 
+ 	/* the dom/dow situation is odd.  '* * 1,15 * Sun' will run on the
+ 	 * first and fifteenth AND every Sunday;  '* * * * Sun' will run *only*
+@@ -205,67 +308,65 @@
+ 	for (u = db->head;  u != NULL;  u = u->next) {
+ 		for (e = u->crontab;  e != NULL;  e = e->next) {
+ 			Debug(DSCH|DEXT, ("user [%s:%d:%d:...] cmd=\"%s\"\n",
+-					  env_get("LOGNAME", e->envp),
+-					  e->uid, e->gid, e->cmd))
+-			if (bit_test(e->minute, minute)
+-			 && bit_test(e->hour, hour)
+-			 && bit_test(e->month, month)
+-			 && ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
++			    env_get("LOGNAME", e->envp),
++			    e->uid, e->gid, e->cmd))
++			if (bit_test(e->minute, minute) &&
++			    bit_test(e->hour, hour) &&
++			    bit_test(e->month, month) &&
++			    ( ((e->flags & DOM_STAR) || (e->flags & DOW_STAR))
+ 			      ? (bit_test(e->dow,dow) && bit_test(e->dom,dom))
+-			      : (bit_test(e->dow,dow) || bit_test(e->dom,dom))
+-			    )
+-			   ) {
+-				job_add(e, u);
++			      : (bit_test(e->dow,dow) || bit_test(e->dom,dom)))) {
++				if ((doNonWild && !(e->flags & (MIN_STAR|HR_STAR)))
++				    || (doWild && (e->flags & (MIN_STAR|HR_STAR))))
++					job_add(e, u);
+ 			}
+ 		}
+ 	}
+ }
+ 
+ 
+-/* the task here is to figure out how long it's going to be until :00 of the
+- * following minute and initialize TargetTime to this value.  TargetTime
+- * will subsequently slide 60 seconds at a time, with correction applied
+- * implicitly in cron_sleep().  it would be nice to let cron execute in
+- * the "current minute" before going to sleep, but by restarting cron you
+- * could then get it to execute a given minute's jobs more than once.
+- * instead we have the chance of missing a minute's jobs completely, but
+- * that's something sysadmin's know to expect what with crashing computers..
++/*
++ * Set StartTime and clockTime to the current time.
++ * These are used for computing what time it really is right now.
++ * Note that clockTime is a unix wallclock time converted to minutes.
+  */
+ static void
+-cron_sync() {
+- 	register struct tm	*tm;
++set_time(int initialize)
++{
++    struct tm tm;
++    static int isdst;
+ 
+-	TargetTime = time((time_t*)0);
+-	tm = localtime(&TargetTime);
+-	TargetTime += (60 - tm->tm_sec);
+-}
++    StartTime = time(NULL);
+ 
++    /* We adjust the time to GMT so we can catch DST changes. */
++    tm = *localtime(&StartTime);
++    if (initialize || tm.tm_isdst != isdst) {
++       isdst = tm.tm_isdst;
++       GMToff = get_gmtoff(&StartTime, &tm);
++       Debug(DSCH, ("[%d] GMToff=%ld\n",
++           getpid(), (long)GMToff))
++    }
++    clockTime = (StartTime + GMToff) / (time_t)SECONDS_PER_MINUTE;
++}
+ 
++/*
++ * try to just hit the next minute
++ */
+ static void
+-cron_sleep() {
+-	register int	seconds_to_wait;
++cron_sleep(target)
++	time_min target;
++{
++	time_t t;
++	int seconds_to_wait;
+ 
+-	do {
+-		seconds_to_wait = (int) (TargetTime - time((time_t*)0));
+-		Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
+-			getpid(), TargetTime, seconds_to_wait))
+-
+-		/* if we intend to sleep, this means that it's finally
+-		 * time to empty the job queue (execute it).
+-		 *
+-		 * if we run any jobs, we'll probably screw up our timing,
+-		 * so go recompute.
+-		 *
+-		 * note that we depend here on the left-to-right nature
+-		 * of &&, and the short-circuiting.
+-		 */
+-	} while (seconds_to_wait > 0 && job_runqueue());
++	t = time(NULL) + GMToff;
+ 
+-	while (seconds_to_wait > 0) {
+-		Debug(DSCH, ("[%d] sleeping for %d seconds\n",
+-			getpid(), seconds_to_wait))
+-		seconds_to_wait = (int) sleep((unsigned int) seconds_to_wait);
+-	}
++	seconds_to_wait = (int)(target * SECONDS_PER_MINUTE - t) + 1;
++	Debug(DSCH, ("[%d] TargetTime=%ld, sec-to-wait=%d\n",
++	    getpid(), (long)target*SECONDS_PER_MINUTE, seconds_to_wait))
++
++        if (seconds_to_wait > 0 && seconds_to_wait < 65)
++            sleep((unsigned int) seconds_to_wait);
+ }
+ 
+ 
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:50.298436009 +0200
++++ patched/misc.c	2010-05-06 18:18:51.095435790 +0200
+@@ -651,8 +651,9 @@
+ 	struct tm *tm = localtime(&t);
+ 	char *qmark;
+ 	size_t len;
+-	int hours = tm->tm_gmtoff / 3600;
+-	int minutes = (tm->tm_gmtoff - (hours * 3600)) / 60;
++        long gmtoff = get_gmtoff(&t, tm);
++        int hours = gmtoff / 3600;
++        int minutes = (gmtoff - (hours * 3600)) / 60;
+ 
+ 	if (minutes < 0)
+ 		minutes = -minutes;
+@@ -682,3 +683,38 @@
+ int swap_uids() { return setreuid(geteuid(), getuid()); }
+ int swap_uids_back() { return swap_uids(); }
+ #endif /*HAVE_SAVED_UIDS*/
++
++
++/* Return the offset from GMT in seconds (algorithm taken from sendmail).
++ *
++ * warning:
++ *	clobbers the static storage space used by localtime() and gmtime().
++ *	If the local pointer is non-NULL it *must* point to a local copy.
++ */
++#ifndef HAVE_TM_GMTOFF
++long get_gmtoff(time_t *clock, struct tm *local)
++{
++	struct tm gmt;
++	long offset;
++
++	gmt = *gmtime(clock);
++	if (local == NULL)
++		local = localtime(clock);
++
++	offset = (local->tm_sec - gmt.tm_sec) +
++	    ((local->tm_min - gmt.tm_min) * 60) +
++	    ((local->tm_hour - gmt.tm_hour) * 3600);
++
++	/* Timezone may cause year rollover to happen on a different day. */
++	if (local->tm_year < gmt.tm_year)
++		offset -= 24 * 3600;
++	else if (local->tm_year > gmt.tm_year)
++		offset += 24 * 3600;
++	else if (local->tm_yday < gmt.tm_yday)
++		offset -= 24 * 3600;
++	else if (local->tm_yday > gmt.tm_yday)
++		offset += 24 * 3600;
++
++	return (offset);
++}
++#endif /* HAVE_TM_GMTOFF */
diff --git a/debian/patches/features/recover-from-broken-symlinks b/debian/patches/features/recover-from-broken-symlinks
new file mode 100644
index 0000000..52fb96b
--- /dev/null
+++ b/debian/patches/features/recover-from-broken-symlinks
@@ -0,0 +1,65 @@
+Subject: Recover from broken symlinks in /etc/cron.d
+Author: Christian Kastner <debian at kvr.at
+Last-Update: 2010-04-19
+
+The way the current power-management-friendly change detection logic notices
+changes to /etc/cron.d, broken symlinks do not get added back once they are
+restored again.
+This is only relevant to /etc/cron.d because SPOOL_DIR does not allow symlinks.
+
+Bug-Debian: http://bugs.debian.org/433609
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:19:01.607560756 +0200
++++ patched/database.c	2010-05-06 18:19:02.884526570 +0200
+@@ -126,7 +126,8 @@
+ 			if (stat(syscrond_fname, &syscrond_file_stat) < OK)
+ 				syscrond_file_stat.st_mtime = 0;
+ 
+-			if (syscrond_file_stat.st_mtime != systab->mtime) {
++			if (syscrond_file_stat.st_mtime != systab->mtime ||
++				systab->mtime == 0) {
+ 			        syscrond_change = 1;
+                         }
+ 
+@@ -381,9 +382,38 @@
+             }
+             if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
+ 		/* crontab not accessible?
++
++                   If tabname is a regular file, this error is bad so we skip
++		   it instead of adding it to the new DB. If it's a symlink,
++                   it's most probably just broken, so we emit a warning.
++                   Then we re-add the old crontab to the new DB, but only after
++                   removing all entries and resetting its mtime. Once the link
++                   is fixed, it will get picked up and processed again.
+ 		 */
+-		log_it(fname, getpid(), "CAN'T OPEN", tabname);
+-		goto next_crontab;
++                if (S_ISREG(statbuf->st_mode)) {
++		    log_it(fname, getpid(), "CAN'T OPEN", tabname);
++		    goto next_crontab;
++                } else {
++                    log_it(fname, getpid(), "CAN'T OPEN SYMLINK", tabname);
++
++                    u = find_user(old_db, fname);
++                    if (u != NULL) {
++			Debug(DLOAD, ("\t%s: [using placeholder]\n", fname))
++                        unlink_user(old_db, u);
++
++			if (u->crontab != NULL) {
++                    	    entry *e, *ne;
++			    for (e = u->crontab;  e != NULL;  e = ne) {
++			    	ne = e->next;
++			    	free_entry(e);
++			    }
++			}
++                        u->crontab = NULL;
++                        u->mtime = 0;
++                        link_user(new_db, u);
++                        goto next_crontab;
++                    }
++                }                
+             }
+ 
+             if (fstat(crontab_fd, statbuf) < OK) {
diff --git a/debian/patches/features/run-on-reboot b/debian/patches/features/run-on-reboot
new file mode 100644
index 0000000..94bab7d
--- /dev/null
+++ b/debian/patches/features/run-on-reboot
@@ -0,0 +1,56 @@
+Subject: Proper handling of @reboot entries
+Last-Update: 2010-04-11
+
+cron runs @reboot jobs on restart instead of on reboot. Fix this.
+
+http://bugs.debian.org/74762
+http://bugs.debian.org/77563
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:51.095435790 +0200
++++ patched/cron.c	2010-05-06 18:18:53.954560978 +0200
+@@ -255,6 +255,10 @@
+ 	}
+ }
+ 
++#ifdef DEBIAN
++#include <sys/stat.h>
++#include <fcntl.h>
++#endif
+ 
+ static void
+ run_reboot_jobs(db)
+@@ -262,7 +266,31 @@
+ {
+ 	register user		*u;
+ 	register entry		*e;
++    int rbfd;
++#ifdef DEBIAN
++#define REBOOT_FILE "/var/run/crond.reboot"
++	/* Run on actual reboot, rather than cron restart */
++	if (access(REBOOT_FILE, F_OK) == 0) {
++	        /* File exists, return */
++     	        log_it("CRON", getpid(),"INFO",
++		       "Skipping @reboot jobs -- not system startup");
++	        return;
++	}
++	/* Create the file */
++	if ((rbfd = creat(REBOOT_FILE, S_IRUSR&S_IWUSR)) < 0) {
++		/* Bad news, bail out */
++	        log_it("CRON",getpid(),"DEATH","Can't create reboot check file");
++		exit(0);
++	} else {
++		close(rbfd);
++		log_it("CRON", getpid(),"INFO", "Running @reboot jobs");
++	}
++      
+ 
++        Debug(DMISC, ("[%d], Debian running reboot jobs\n",getpid()));
++    
++#endif
++        Debug(DMISC, ("[%d], vixie running reboot jobs\n", getpid()));
+ 	for (u = db->head;  u != NULL;  u = u->next) {
+ 		for (e = u->crontab;  e != NULL;  e = e->next) {
+ 			if (e->flags & WHEN_REBOOT) {
diff --git a/debian/patches/features/security-make-crontab-setgid-crontab b/debian/patches/features/security-make-crontab-setgid-crontab
new file mode 100644
index 0000000..30661fa
--- /dev/null
+++ b/debian/patches/features/security-make-crontab-setgid-crontab
@@ -0,0 +1,377 @@
+Subject: Make crontab SETGID crontab instead of SETUID root
+Last-Update: 2010-04-11
+
+This reduces the risk of a security incident in connection with crontab(1).
+Nevertheless, Tomi Miettinen's advice in #18333 of not SETing and all but
+instead using sockets should be taken into consideration.
+
+Bug-Debian: http://bugs.debian.org/18333
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:44.880437493 +0200
++++ patched/crontab.c	2010-05-06 18:18:52.595435667 +0200
+@@ -108,7 +108,6 @@
+ 	setlinebuf(stderr);
+ #endif
+ 	parse_args(argc, argv);		/* sets many globals, opens a file */
+-	set_cron_uid();
+ 	set_cron_cwd();
+ 	if (!allowed(User)) {
+                 if ( getuid() != 0 ) {
+@@ -373,12 +372,6 @@
+                 return -1;
+         }
+ 
+-        if (chown(Directory, getuid(), getgid()) < 0) {
+-                perror(Directory);
+-                Directory[0] = '\0';
+-                return -1;
+-        }
+-
+         /* Now create the actual temporary crontab file */
+         if (snprintf(Filename, MAX_FNAME, "%s/crontab", Directory)
+             >= MAX_FNAME) {
+@@ -414,7 +407,7 @@
+ 		perror("fstat");
+ 		return -1;
+ 	}
+-	if (statbuf.st_uid != getuid() || statbuf.st_gid != getgid()) {
++	if (statbuf.st_uid != getuid()) {
+ 		fprintf(stderr, "Temporary crontab no longer owned by you.\n");
+ 		return -1;;
+ 	}
+@@ -568,7 +561,6 @@
+ 		editor = EDITOR;
+ 	}
+ 
+- again:
+ 
+         /*  Close before cleanup_tmp_crontab is called or otherwise
+          *  (on NFS mounted /) will get renamed on unlink */
+@@ -577,12 +569,15 @@
+                 goto fatal;
+ 	}
+ 
++again: /* Loop point for retrying edit after error */
++
+ 	/* Turn off signals. */
+ 	(void)signal(SIGHUP, SIG_IGN);
+ 	(void)signal(SIGINT, SIG_IGN);
+ 	(void)signal(SIGQUIT, SIG_IGN);
+ 
+-
++        /* Give up privileges while editing */
++        swap_uids();
+ 
+ 	switch (pid = fork()) {
+ 	case -1:
+@@ -590,10 +585,14 @@
+ 		goto fatal;
+ 	case 0:
+ 		/* child */
+-		if (setuid(getuid()) < 0) {
+-			perror("setuid(getuid())");
+-			exit(ERROR_EXIT);
+-		}
++                if (setgid(getgid()) < 0) {
++                        perror("setgid(getgid())");
++                        exit(ERROR_EXIT);
++                }
++                if (setuid(getuid()) < 0) {
++                        perror("setuid(getuid())");
++                        exit(ERROR_EXIT);
++                }
+ 		if (chdir("/tmp") < 0) {
+ 			perror("chdir(/tmp)");
+ 			exit(ERROR_EXIT);
+@@ -643,6 +642,9 @@
+ 	(void)signal(SIGQUIT, SIG_DFL);
+ 	(void)signal(SIGTSTP, SIG_DFL);
+ 
++        /* Need privs again */
++        swap_uids_back();
++
+         switch (open_tmp_crontab(&fsbuf)) {
+         case -1:
+                 fprintf(stderr, "Error while editing crontab\n");
+@@ -725,21 +727,12 @@
+ 	time_t	now = time(NULL);
+ 	char	**envp = env_init();
+ 	mode_t	um;
+-	int	saved_uid;
+ 
+ 	if (envp == NULL) {
+ 		fprintf(stderr, "%s: Cannot allocate memory.\n", ProgramName);
+ 		return (-2);
+ 	}
+ 
+-	/* Assume privilege.  This way we can only receive signals on our
+-	   input - the ones listed below (or from root - root's problem, not
+-	   ours). */
+-	saved_uid = getuid();
+-	if (setuid(geteuid()) < 0) {
+-		perror("setuid");
+-		return -2;
+-	}
+ 
+ 	/* Assumes Linux-style signal handlers (takes int, returns void) */
+ 	/* Signal handlers, to ensure we do not leave temp files in the
+@@ -813,22 +806,9 @@
+ 	if (CheckErrorCount != 0) {
+ 		fprintf(stderr, "errors in crontab file, can't install.\n");
+ 		fclose(tmp);  unlink(tn);
+-		/* Give up privilege, in case we loop. */
+-		if (setreuid(saved_uid, -1) < 0)
+-			return (-2);
+ 		return (-1);
+ 	}
+ 
+-#ifdef HAS_FCHOWN
+-	if (fchown(fileno(tmp), ROOT_UID, -1) < OK)
+-#else
+-	if (chown(tn, ROOT_UID, -1) < OK)
+-#endif
+-	{
+-		perror("chown");
+-		fclose(tmp);  unlink(tn);
+-		return (-2);
+-	}
+ 
+ #ifdef HAS_FCHMOD
+ 	if (fchmod(fileno(tmp), 0600) < OK)
+@@ -848,6 +828,15 @@
+ 		return (-2);
+ 	}
+ 
++        /* Root on behalf of another user must set file owner to that user */
++        if (getuid() == ROOT_UID && strcmp(User, RealUser) != 0) {
++            if (chown(tn, pw->pw_uid, -1) != 0) {
++                perror("chown");
++                unlink(tn);
++                return -2;
++            }
++        }
++
+ 	(void) snprintf(n, sizeof(n), CRON_TAB(User));
+ 	if (rename(tn, n)) {
+ 		fprintf(stderr, "%s: %s: rename: %s\n",
+@@ -861,11 +850,6 @@
+ 
+ 	poke_daemon();
+ 
+-	/* Give up privilege, just in case. */
+-	/* Don't need to check for error; nothing happens beyond here but a log entry,
+-	   and the failure message is incorrect after the rename above. */
+-	setreuid(saved_uid, -1);
+-
+ 	return (0);
+ }
+ 
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:18:49.631436001 +0200
++++ patched/database.c	2010-05-06 18:18:52.595435667 +0200
+@@ -24,7 +24,9 @@
+ 
+ 
+ #include "cron.h"
++#define __USE_GNU /* For O_NOFOLLOW */
+ #include <fcntl.h>
++#undef __USE_GNU
+ #include <sys/stat.h>
+ #include <sys/file.h>
+ 
+@@ -337,18 +339,77 @@
+ 		goto next_crontab;
+ 	}
+ 
+-	if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
++        if (pw) {
++            /* Path for user crontabs (including root's!) */
++            if ((crontab_fd = open(tabname, O_RDONLY|O_NOFOLLOW, 0)) < OK) {
+ 		/* crontab not accessible?
+ 		 */
+ 		log_it(fname, getpid(), "CAN'T OPEN", tabname);
+ 		goto next_crontab;
+-	}
++            }
+ 
+-	if (fstat(crontab_fd, statbuf) < OK) {
++            if (fstat(crontab_fd, statbuf) < OK) {
+ 		log_it(fname, getpid(), "FSTAT FAILED", tabname);
+ 		goto next_crontab;
+-	}
++            }
++            /* Check to make sure that the crontab is owned by the correct user
++               (or root) */
++
++            if (statbuf->st_uid != pw->pw_uid &&
++                statbuf->st_uid != ROOT_UID) {
++                log_it(fname, getpid(), "WRONG FILE OWNER", tabname);
++		goto next_crontab;
++            }
++            if (!S_ISREG(statbuf->st_mode) ||
++                statbuf->st_nlink != 1 ||
++                (statbuf->st_mode & 07777) != 0600) {
++                log_it(fname, getpid(), "WRONG INODE INFO", tabname);
++ 		goto next_crontab;
++            }
++        } else {
++            /* System crontab path. These can be symlinks, but the
++               symlink and the target must be owned by root. */
++            if (lstat(tabname, statbuf) < OK) {
++		log_it(fname, getpid(), "LSTAT FAILED", tabname);
++		goto next_crontab;
++            }
++            if (S_ISLNK(statbuf->st_mode) && statbuf->st_uid != ROOT_UID) {
++                log_it(fname, getpid(), "WRONG SYMLINK OWNER", tabname);
++		goto next_crontab;
++            }
++            if ((crontab_fd = open(tabname, O_RDONLY, 0)) < OK) {
++		/* crontab not accessible?
++		 */
++		log_it(fname, getpid(), "CAN'T OPEN", tabname);
++		goto next_crontab;
++            }
+ 
++            if (fstat(crontab_fd, statbuf) < OK) {
++		log_it(fname, getpid(), "FSTAT FAILED", tabname);
++		goto next_crontab;
++            }
++            /* Check to make sure that the crontab is owned by root */
++            if (statbuf->st_uid != ROOT_UID) {
++                log_it(fname, getpid(), "WRONG FILE OWNER", tabname);
++		goto next_crontab;
++            }
++            /* Check to make sure that the crontab is writable only by root */
++            if ((statbuf->st_mode & S_IWGRP) || (statbuf->st_mode & S_IWOTH))  {
++                log_it(fname, getpid(), "WRONG INODE INFO", tabname);
++		goto next_crontab;
++            }
++            /* Technically, we should also check whether the parent dir is
++ 	     * writable, and so on. This would only make proper sense for
++ 	     * regular files; we can't realistically check all possible
++ 	     * security issues resulting from symlinks. We'll just assume that
++ 	     * root will handle responsible when creating them.
++	     */
++        }
++        /*
++         * The link count check is not sufficient (the owner may
++         * delete their original link, reducing the link count back to
++         * 1), but this is all we've got.
++         */
+ 	Debug(DLOAD, ("\t%s:", fname))
+ 	u = find_user(old_db, fname);
+ 	if (u != NULL) {
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:51.875560985 +0200
++++ patched/misc.c	2010-05-06 18:18:52.595435667 +0200
+@@ -35,6 +35,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <fcntl.h>
++#include <grp.h>
+ #if defined(SYSLOG)
+ # include <syslog.h>
+ #endif
+@@ -191,18 +192,29 @@
+ set_cron_cwd()
+ {
+ 	struct stat	sb;
+-
++	mode_t		um;
++	struct group	*gr;
++	
+ 	/* first check for CRONDIR ("/var/cron" or some such)
+ 	 */
+ 	if (stat(CRONDIR, &sb) < OK && errno == ENOENT) {
+ 		perror(CRONDIR);
+-		if (OK == mkdir(CRONDIR, 0700)) {
++
++		/* crontab(1) running SGID crontab shouldn't attempt to create
++		 * directories */
++		if (getuid() != 0 )
++			exit(ERROR_EXIT);
++
++		um = umask(000);
++		if (OK == mkdir(CRONDIR, CRONDIR_MODE)) {
+ 			fprintf(stderr, "%s: created\n", CRONDIR);
+ 			stat(CRONDIR, &sb);
+ 		} else {
+-			fprintf(stderr, "%s: mkdir: %s\n", CRONDIR, strerror(errno));
++			fprintf(stderr, "%s: mkdir: %s\n", CRONDIR,
++				strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
++		(void) umask(um);
+ 	}
+ 	if (!(sb.st_mode & S_IFDIR)) {
+ 		fprintf(stderr, "'%s' is not a directory, bailing out.\n",
+@@ -218,11 +230,33 @@
+ 	 */
+ 	if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) {
+ 		perror(SPOOL_DIR);
+-		if (OK == mkdir(SPOOL_DIR, 0700)) {
++
++		/* crontab(1) running SGID crontab shouldn't attempt to create
++		 * directories */
++		if (getuid() != 0 )
++			exit(ERROR_EXIT);
++
++		um = umask(000);
++		if (OK == mkdir(SPOOL_DIR, SPOOL_DIR_MODE)) {
+ 			fprintf(stderr, "%s: created\n", SPOOL_DIR);
+-			stat(SPOOL_DIR, &sb);
+ 		} else {
+-			fprintf(stderr, "%s: mkdir: %s\n", SPOOL_DIR, strerror(errno));
++			fprintf(stderr, "%s: mkdir: %s\n", SPOOL_DIR,
++				strerror(errno));
++			exit(ERROR_EXIT);
++		}
++		(void) umask(um);
++
++		if (!(gr = getgrnam(SPOOL_DIR_GROUP))) {
++			fprintf(stderr, "%s: getgrnam: %s\n", SPOOL_DIR,
++				strerror(errno));
++			exit(ERROR_EXIT);
++		}
++		if (OK == chown(SPOOL_DIR, -1, gr->gr_gid)) {
++			fprintf(stderr, "%s: chowned\n", SPOOL_DIR);
++				stat(SPOOL_DIR, &sb);
++		} else {
++			fprintf(stderr, "%s: chown: %s\n", SPOOL_DIR,
++			strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
+ 	}
+Index: patched/pathnames.h
+===================================================================
+--- patched.orig/pathnames.h	2010-05-06 18:18:50.298436009 +0200
++++ patched/pathnames.h	2010-05-06 18:18:52.595435667 +0200
+@@ -93,3 +93,25 @@
+ #ifndef _PATH_DEFPATH_ROOT
+ # define _PATH_DEFPATH_ROOT "/usr/sbin:/usr/bin:/sbin:/bin"
+ #endif
++
++
++#ifdef DEBIAN
++#ifndef CRONDIR_MODE
++			/* Create mode for CRONDIR; must be in sync with
++			 * packaging
++			 */
++#define CRONDIR_MODE 0755
++#endif
++#ifndef SPOOL_DIR_MODE
++			/* Create mode for SPOOL_DIR; must be in sync with
++			 * packaging
++			 */
++#define SPOOL_DIR_MODE 01730
++#endif
++#ifndef SPOOL_DIR_GROUP
++			/* Chown SPOOL_DIR to this group (needed by Debian's
++			 * SGID crontab feature)
++			 */ 
++#define SPOOL_DIR_GROUP "crontab"
++#endif
++#endif
diff --git a/debian/patches/features/selinux-support b/debian/patches/features/selinux-support
new file mode 100644
index 0000000..a958776
--- /dev/null
+++ b/debian/patches/features/selinux-support
@@ -0,0 +1,304 @@
+Subject: SELinux support
+Author: Manoj Srivastava <srivasta at debian.org>
+
+Enable SELinux support on Linux-based architectures. Also contains patches from
+Russell Coker <russell at coker.com.au>.
+ 
+Bug-Debian: http://bugs.debian.org/315509
+Bug-Debian: http://bugs.debian.org/279429
+Bug-Debian: http://bugs.debian.org/264320
+Bug-Debian: http://bugs.debian.org/324017
+Bug-Debian: http://bugs.debian.org/325404
+Bug-Debian: http://bugs.debian.org/361458
+Bug-Debian: http://bugs.debian.org/383857
+Index: patched/Makefile
+===================================================================
+--- patched.orig/Makefile	2010-05-06 18:18:47.436487807 +0200
++++ patched/Makefile	2010-05-06 18:18:48.837561139 +0200
+@@ -55,7 +55,7 @@
+ INCLUDE		=	-I.
+ #INCLUDE	=
+ #<<need getopt()>>
+-LIBS		= $(PAM_LIBS)
++LIBS		= $(PAM_LIBS) $(SELINUX_LIBS)
+ #<<optimize or debug?>>
+ OPTIM		=	-O2
+ #OPTIM		=	-g
+@@ -74,7 +74,7 @@
+ # Allow override from command line
+ DEBUG_DEFS = -DDEBUGGING=0   
+ # The -DUSE_SIGCHLD is needed for the Alpha port
+-DEFS = -DDEBIAN -DUSE_SIGCHLD $(DEBUG_DEFS) $(PAM_DEFS)
++DEFS = -DDEBIAN -DUSE_SIGCHLD $(DEBUG_DEFS) $(PAM_DEFS) $(SELINUX_DEFS)
+ #(SGI IRIX systems need this)
+ #DEFS		=	-D_BSD_SIGNALS -Dconst=
+ #<<the name of the BSD-like install program>>
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:30.896560600 +0200
++++ patched/cron.h	2010-05-06 18:18:48.838561166 +0200
+@@ -40,6 +40,13 @@
+ #include "config.h"
+ #include "externs.h"
+ 
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++#endif
++
++#define SYSUSERNAME "root"
++
++
+ 	/* these are really immutable, and are
+ 	 *   defined for symbolic convenience only
+ 	 * TRUE, FALSE, and ERR must be distinct
+@@ -174,6 +181,9 @@
+ 	char		*name;
+ 	time_t		mtime;		/* last modtime of crontab */
+ 	entry		*crontab;	/* this person's crontab */
++#ifdef WITH_SELINUX
++        security_context_t scontext;    /* SELinux security context */
++#endif
+ } user;
+ 
+ typedef	struct _cron_db {
+@@ -220,7 +230,7 @@
+ 		**env_copy __P((char **)),
+ 		**env_set __P((char **, char *));
+ 
+-user		*load_user __P((int, struct passwd *, char *)),
++user		*load_user __P((int, struct passwd *, char *, char *, char *)),
+ 		*find_user __P((cron_db *, char *));
+ 
+ entry		*load_entry __P((FILE *, void (*)(),
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:18:36.431560887 +0200
++++ patched/database.c	2010-05-06 18:18:48.838561166 +0200
+@@ -97,7 +97,7 @@
+ 	new_db.head = new_db.tail = NULL;
+ 
+ 	if (syscron_stat.st_mtime) {
+-		process_crontab("root", "*system*",
++		process_crontab(SYSUSERNAME, "*system*",
+ 				SYSCRONTAB, &syscron_stat,
+ 				&new_db, old_db);
+ 	}
+@@ -261,7 +261,8 @@
+ 		free_user(u);
+ 		log_it(fname, getpid(), "RELOAD", tabname);
+ 	}
+-	u = load_user(crontab_fd, pw, fname);
++
++	u = load_user(crontab_fd, pw, uname, fname, tabname);
+ 	if (u != NULL) {
+ 		u->mtime = statbuf->st_mtime;
+ 		link_user(new_db, u);
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:48.182560885 +0200
++++ patched/do_command.c	2010-05-06 18:18:48.877435845 +0200
+@@ -42,6 +42,11 @@
+    }
+ #endif
+ 
++#ifdef WITH_SELINUX
++#include <selinux/selinux.h>
++/* #include <selinux/get_context_list.h> */
++#endif
++
+ 
+ static void		child_process __P((entry *, user *)),
+ 			do_univ __P((user *));
+@@ -332,6 +337,23 @@
+ 				_exit(OK_EXIT);
+ 			}
+ # endif /*DEBUGGING*/
++#ifdef WITH_SELINUX
++			if (is_selinux_enabled() > 0) {
++			    if (u->scontext != 0L) {
++                                if (setexeccon(u->scontext) < 0) {
++                                    if (security_getenforce() > 0) {
++                                        fprintf(stderr, "Could not set exec context to %s for user  %s\n", u->scontext,u->name);
++                                        _exit(ERROR_EXIT);
++                                    }
++			        }
++                            }
++			    else if(security_getenforce() > 0)
++			    {
++                                fprintf(stderr, "Error, must have a security context for the cron job when in enforcing mode.\nUser %s.\n", u->name);
++                                _exit(ERROR_EXIT);
++			    }
++			}
++#endif
+                         execle(shell, shell, "-c", e->cmd, (char *)0, jobenv);
+ 			fprintf(stderr, "%s: execle: %s\n", shell, strerror(errno));
+ 			_exit(ERROR_EXIT);
+Index: patched/user.c
+===================================================================
+--- patched.orig/user.c	2010-05-06 18:18:32.328436004 +0200
++++ patched/user.c	2010-05-06 18:18:48.877435845 +0200
+@@ -25,6 +25,107 @@
+ 
+ #include "cron.h"
+ 
++#ifdef WITH_SELINUX
++#include <selinux/context.h>
++#include <selinux/selinux.h>
++#include <selinux/flask.h>
++#include <selinux/av_permissions.h>
++#include <selinux/get_context_list.h>
++
++static int get_security_context(char *name, int crontab_fd, security_context_t
++                                *rcontext, char *tabname) {
++    security_context_t *context_list = NULL;
++    security_context_t current_con;
++    int list_count = 0;
++    security_context_t  file_context=NULL;
++    struct av_decision avd;
++    int retval=0;
++    char *seuser = NULL;
++    char *level = NULL;
++    int i;
++
++    if (name != NULL) {
++        if (getseuserbyname(name, &seuser, &level)) {
++            log_it(name, getpid(), "getseuserbyname FAILED", tabname);
++            return (security_getenforce() > 0);
++        }
++    }
++    else
++    {
++        seuser = strdup("system_u");
++    }
++
++    *rcontext = NULL;
++    if(getcon(&current_con)) {
++        log_it(name, getpid(), "Can't get current context", tabname);
++        return -1;
++    }
++    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) {
++            log_it(name, getpid(), "No SELinux security context", tabname);
++            return -1;
++        } else {
++            log_it(name, getpid(),
++                   "No security context but SELinux in permissive mode,"
++                   " continuing", tabname);
++	    return 0;
++        }
++    }
++
++    if (fgetfilecon(crontab_fd, &file_context) < OK) {
++        if (security_getenforce() > 0) {
++            log_it(name, getpid(), "getfilecon FAILED", tabname);
++            freeconary(context_list);
++            return -1;
++        } else {
++            log_it(name, getpid(), "getfilecon FAILED but SELinux in "
++                   "permissive mode, continuing", tabname);
++            *rcontext = strdup(context_list[0]);
++            freeconary(context_list);
++            return 0;
++        }
++    }
++
++    /*
++     * 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.
++     */
++
++    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)) {
++            *rcontext = strdup(context_list[i]);
++            freecon(file_context);
++            freeconary(context_list);
++            return 0;
++        }
++    }
++    freecon(file_context);
++    if (security_getenforce() > 0) {
++        log_it(name, getpid(), "ENTRYPOINT FAILED", tabname);
++        freeconary(context_list);
++        return -1;
++    } else {
++        log_it(name, getpid(), "ENTRYPOINT FAILED but SELinux in permissive mode, continuing", tabname);
++        *rcontext = strdup(context_list[0]);
++        freeconary(context_list);
++    }
++    return 0;
++}
++#endif
++
+ 
+ void
+ free_user(u)
+@@ -37,15 +138,21 @@
+ 		ne = e->next;
+ 		free_entry(e);
+ 	}
++#ifdef WITH_SELINUX
++	if (u->scontext)
++		freecon(u->scontext);
++#endif
+ 	free(u);
+ }
+ 
+ 
+ user *
+-load_user(crontab_fd, pw, name)
++load_user(crontab_fd, pw, uname, fname, tabname)
+ 	int		crontab_fd;
+ 	struct passwd	*pw;		/* NULL implies syscrontab */
+-	char		*name;
++	char		*uname;
++	char		*fname;
++	char		*tabname;
+ {
+ 	char	envstr[MAX_ENVSTR];
+ 	FILE	*file;
+@@ -67,13 +174,31 @@
+ 		errno = ENOMEM;
+ 		return NULL;
+ 	}
+-	if ((u->name = strdup(name)) == NULL) {
++	if ((u->name = strdup(fname)) == NULL) {
+ 		free(u);
+ 		errno = ENOMEM;
+ 		return NULL;
+ 	}
+ 	u->crontab = NULL;
+ 
++#ifdef WITH_SELINUX
++	u->scontext = NULL;
++        if (is_selinux_enabled() > 0) {
++            char *sname=uname;
++            if (pw==NULL) {
++                sname="system_u";
++            }
++            if (get_security_context(sname, crontab_fd, 
++                                     &u->scontext, tabname) != 0 ) {
++		u->scontext = NULL;
++                free_user(u);
++                u = NULL;
++                goto done;
++            }
++        }
++#endif
++
++
+ 	/* 
+ 	 * init environment.  this will be copied/augmented for each entry.
+ 	 */
diff --git a/debian/patches/features/set-contenttype-in-mail b/debian/patches/features/set-contenttype-in-mail
new file mode 100644
index 0000000..4cb33b0
--- /dev/null
+++ b/debian/patches/features/set-contenttype-in-mail
@@ -0,0 +1,131 @@
+Subject: Set ContentType: header in emails
+Origin: vendor,Fedora Core
+
+Set the ContentType: header based on the system locale or cron's evironment,
+if available.
+
+Bug-Debian: http://bugs.debian.org/338051
+Bug-Debian: http://bugs.debian.org/309150
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:53.954560978 +0200
++++ patched/cron.c	2010-05-06 18:18:54.665561020 +0200
+@@ -63,6 +63,7 @@
+ 	char	*argv[];
+ {
+ 	cron_db	database;
++	char *cs;
+ 
+ 	ProgramName = argv[0];
+ 
+@@ -95,6 +96,19 @@
+ 	setenv("PATH", _PATH_DEFPATH, 1);
+ #endif
+ 
++       /* Get the default locale character set for the mail
++        * "Content-Type: ...; charset=" header
++        */
++       setlocale(LC_ALL,""); /* set locale to system defaults or to
++                                that specified by any  LC_* env vars */
++       /* Except that "US-ASCII" is preferred to "ANSI_x3.4-1968" in MIME,
++        * even though "ANSI_x3.4-1968" is the official charset name. */
++       if ( ( cs = nl_langinfo( CODESET ) ) != 0L && 
++               strcmp(cs, "ANSI_x3.4-1968") != 0 )
++           strncpy( cron_default_mail_charset, cs, MAX_ENVSTR );
++       else
++           strcpy( cron_default_mail_charset, "US-ASCII" );
++
+ 	/* if there are no debug flags turned on, fork as a daemon should.
+ 	 */
+ # if DEBUGGING
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:51.094436073 +0200
++++ patched/cron.h	2010-05-06 18:18:54.665561020 +0200
+@@ -292,6 +292,8 @@
+ 
+ int     lsbsysinit_mode;
+ 
++char    cron_default_mail_charset[MAX_ENVSTR] = "";
++
+ # if DEBUGGING
+ int	DebugFlags;
+ char	*DebugFlagNames[] = {	/* sync with #defines */
+@@ -310,6 +312,7 @@
+ extern  time_min timeRunning;
+ extern  time_min virtualTime;
+ extern  time_min clockTime;
++extern  char     cron_default_mail_charset[MAX_ENVSTR];
+ # if DEBUGGING
+ extern	int	DebugFlags;
+ extern	char	*DebugFlagNames[];
+Index: patched/externs.h
+===================================================================
+--- patched.orig/externs.h	2010-05-06 18:18:22.672435408 +0200
++++ patched/externs.h	2010-05-06 18:18:54.665561020 +0200
+@@ -26,6 +26,11 @@
+ # define WAIT_IS_INT 1
+ extern char *tzname[2];
+ # define TZONE(tm) tzname[(tm).tm_isdst]
++/* include locale stuff for mailer "Content-Type":
++ */
++#include <locale.h>
++#include <nl_types.h>
++#include <langinfo.h>
+ #endif
+ 
+ #if defined(UNIXPC)
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:51.094436073 +0200
++++ patched/do_command.c	2010-05-06 18:18:54.665561020 +0200
+@@ -486,8 +486,12 @@
+ 
+ 			if (mailto) {
+ 				register char	**env;
++                        	char    **jobenv = build_env(e->envp); 
+ 				auto char	mailcmd[MAX_COMMAND];
+ 				auto char	hostname[MAXHOSTNAMELEN];
++				char    *content_type = env_get("CONTENT_TYPE",jobenv),
++					*content_transfer_encoding = env_get("CONTENT_TRANSFER_ENCODING",jobenv);
++
+ 
+ 				(void) gethostname(hostname, MAXHOSTNAMELEN);
+ 				(void) snprintf(mailcmd, sizeof(mailcmd),
+@@ -505,6 +509,36 @@
+ 				fprintf(mail, "Date: %s\n",
+ 					arpadate(&StartTime));
+ # endif /* MAIL_DATE */
++                               if ( content_type == 0L ) {
++                                       fprintf(mail, "Content-Type: text/plain; charset=%s\n",
++                                               cron_default_mail_charset
++                                              );
++                               } else {   
++				    /* user specified Content-Type header.
++				     * disallow new-lines for security reasons
++				     * (else users could specify arbitrary mail headers!)
++				     */
++				       char *nl=content_type;
++                                       size_t ctlen = strlen(content_type);
++
++                                       while(  (*nl != '\0')
++                                            && ((nl=strchr(nl,'\n')) != 0L)
++                                            && (nl < (content_type+ctlen))
++                                            ) *nl = ' ';
++                                       fprintf(mail,"Content-Type: %s\n", content_type);
++                               }
++                               if ( content_transfer_encoding != 0L ) {
++                                       char *nl=content_transfer_encoding;
++                                       size_t ctlen = strlen(content_transfer_encoding);
++                                       while(  (*nl != '\0')
++                                            && ((nl=strchr(nl,'\n')) != 0L)
++                                            && (nl < (content_transfer_encoding+ctlen))
++                                            ) *nl = ' ';
++
++                                       fprintf(mail,"Content-Transfer-Encoding: %s\n", content_transfer_encoding);
++                               }
++
++
+ 				for (env = e->envp;  *env;  env++)
+ 					fprintf(mail, "X-Cron-Env: <%s>\n",
+ 						*env);
diff --git a/debian/patches/features/support-for-drop.d-directory b/debian/patches/features/support-for-drop.d-directory
new file mode 100644
index 0000000..b7ed9e1
--- /dev/null
+++ b/debian/patches/features/support-for-drop.d-directory
@@ -0,0 +1,334 @@
+Subject: Support for drop-in directory /etc/cron.d
+Last-Update: 2010-04-11
+
+Add support for /etc/cron.d, a drop-in directory for packages. This involves
+numerous features, such as:
+    * Efficiently detecting changes
+    * LSB-conform naming convention
+    * Security concerns
+
+Bug-Debian: http://bugs.debian.org/171587
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:18:48.838561166 +0200
++++ patched/database.c	2010-05-06 18:18:49.631436001 +0200
+@@ -46,18 +46,27 @@
+ static	void		process_crontab __P((char *, char *, char *,
+ 					     struct stat *,
+ 					     cron_db *, cron_db *));
+-
+-
++#ifdef DEBIAN
++static int valid_name (char *filename);
++static user *get_next_system_crontab __P((user *));
++#endif
+ void
+ load_database(old_db)
+ 	cron_db		*old_db;
+ {
+-	DIR		*dir;
++        DIR		*dir;
+ 	struct stat	statbuf;
+ 	struct stat	syscron_stat;
+ 	DIR_T   	*dp;
+ 	cron_db		new_db;
+ 	user		*u, *nu;
++#ifdef DEBIAN
++	struct stat     syscrond_stat;
++	struct stat     syscrond_file_stat;
++	
++        char            syscrond_fname[PATH_MAX+1];
++	int             syscrond_change = 0;
++#endif
+ 
+ 	Debug(DLOAD, ("[%d] load_database()\n", getpid()))
+ 
+@@ -75,6 +84,53 @@
+ 	if (stat(SYSCRONTAB, &syscron_stat) < OK)
+ 		syscron_stat.st_mtime = 0;
+ 
++#ifdef DEBIAN
++	/* Check mod time of SYSCRONDIR. This won't tell us if a file
++         * in it changed, but will capture deletions, which the individual
++         * file check won't
++	 */
++	if (stat(SYSCRONDIR, &syscrond_stat) < OK) {
++		log_it("CRON", getpid(), "STAT FAILED", SYSCRONDIR);
++		(void) exit(ERROR_EXIT);
++	}
++
++	/* If SYSCRONDIR was modified, we know that something is changed and
++	 * there is no need for any further checks. If it wasn't, we should
++	 * pass through the old list of files in SYSCRONDIR and check their
++	 * mod time. Therefore a stopped hard drive won't be spun up, since
++	 * we avoid reading of SYSCRONDIR and don't change its access time.
++	 * This is especially important on laptops with APM.
++	 */
++	if (old_db->sysd_mtime != syscrond_stat.st_mtime) {
++	        syscrond_change = 1;
++	} else {
++	        /* Look through the individual files */
++		user *systab;
++
++		Debug(DLOAD, ("[%d] system dir mtime unch, check files now.\n",
++			      getpid()))
++
++		for (systab = old_db->head;
++		     (systab = get_next_system_crontab (systab)) != NULL;
++		     systab = systab->next) {
++
++			sprintf(syscrond_fname, "%s/%s", SYSCRONDIR,
++							 systab->name + 8);
++
++			Debug(DLOAD, ("\t%s:", syscrond_fname))
++
++			if (stat(syscrond_fname, &syscrond_file_stat) < OK)
++				syscrond_file_stat.st_mtime = 0;
++
++			if (syscrond_file_stat.st_mtime != systab->mtime) {
++			        syscrond_change = 1;
++                        }
++
++			Debug(DLOAD, (" [checked]\n"))
++		}
++	}
++#endif /* DEBIAN */
++
+ 	/* if spooldir's mtime has not changed, we don't need to fiddle with
+ 	 * the database.
+ 	 *
+@@ -82,7 +138,14 @@
+ 	 * so is guaranteed to be different than the stat() mtime the first
+ 	 * time this function is called.
+ 	 */
+-	if (old_db->mtime == TMAX(statbuf.st_mtime, syscron_stat.st_mtime)) {
++#ifdef DEBIAN
++	if ((old_db->user_mtime == statbuf.st_mtime) &&
++	    (old_db->sys_mtime == syscron_stat.st_mtime) &&
++	    (!syscrond_change)) {
++#else
++	if ((old_db->user_mtime == statbuf.st_mtime) &&
++	    (old_db->sys_mtime == syscron_stat.st_mtime)) {
++#endif
+ 		Debug(DLOAD, ("[%d] spool dir mtime unch, no load needed.\n",
+ 			      getpid()))
+ 		return;
+@@ -93,7 +156,11 @@
+ 	 * actually changed.  Whatever is left in the old database when
+ 	 * we're done is chaff -- crontabs that disappeared.
+ 	 */
+-	new_db.mtime = TMAX(statbuf.st_mtime, syscron_stat.st_mtime);
++	new_db.user_mtime = statbuf.st_mtime;
++	new_db.sys_mtime = syscron_stat.st_mtime;
++#ifdef DEBIAN
++	new_db.sysd_mtime = syscrond_stat.st_mtime;
++#endif
+ 	new_db.head = new_db.tail = NULL;
+ 
+ 	if (syscron_stat.st_mtime) {
+@@ -102,6 +169,46 @@
+ 				&new_db, old_db);
+ 	}
+ 
++#ifdef DEBIAN
++	/* Read all the package crontabs. */
++	if (!(dir = opendir(SYSCRONDIR))) {
++		log_it("CRON", getpid(), "OPENDIR FAILED", SYSCRONDIR);
++		(void) exit(ERROR_EXIT);
++	}
++
++	while (NULL != (dp = readdir(dir))) {
++		char	fname[MAXNAMLEN+1],
++		        tabname[PATH_MAX+1];
++
++
++		/* avoid file names beginning with ".".  this is good
++		 * because we would otherwise waste two guaranteed calls
++		 * to stat() for . and .., and also because package names
++		 * starting with a period are just too nasty to consider.
++		 */
++		if (dp->d_name[0] == '.')
++			continue;
++
++		/* skipfile names with letters outside the set
++		 * [A-Za-z0-9_-], like run-parts.
++		 */
++		if (!valid_name(dp->d_name))
++		  continue;
++
++		/* Generate the "fname" */
++		(void) strcpy(fname,"*system*");
++		(void) strcat(fname, dp->d_name);
++		sprintf(tabname,"%s/%s", SYSCRONDIR, dp->d_name);
++
++		/* statbuf is used as working storage by process_crontab() --
++		   current contents are irrelevant */
++		process_crontab(SYSUSERNAME, fname, tabname,
++				&statbuf, &new_db, old_db);
++
++	}
++	closedir(dir);
++#endif
++
+ 	/* we used to keep this dir open all the time, for the sake of
+ 	 * efficiency.  however, we need to close it in every fork, and
+ 	 * we fork a lot more often than the mtime of the dir changes.
+@@ -214,7 +321,13 @@
+ 	int		crontab_fd = OK - 1;
+ 	user		*u;
+ 
++#ifdef DEBIAN
++	/* If the name begins with *system*, don't worry about password -
++	 it's part of the system crontab */
++	if (strncmp(fname, "*system*", 8) && !(pw = getpwnam(uname))) {
++#else
+ 	if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) {
++#endif
+ 		/* file doesn't have a user in passwd file.
+ 		 */
+ 		if (strncmp(fname, "tmp.", 4)) {
+@@ -274,3 +387,56 @@
+ 		close(crontab_fd);
+ 	}
+ }
++
++#ifdef DEBIAN
++
++#include <regex.h>
++
++/* True or false? Is this a valid filename? */
++
++/* Taken from Clint Adams 'run-parts' version to support lsb style
++   names, originally GPL, but relicensed to cron license per e-mail of
++   27 September 2003. I've changed it to do regcomp() only once. */
++
++static int
++valid_name(char *filename)
++{
++  static regex_t hierre, tradre, excsre, classicalre;
++  static int donere = 0;
++
++  if (!donere) {
++      donere = 1;
++      if (regcomp(&hierre, "^_?([a-z0-9_.]+-)+[a-z0-9]+$",
++                  REG_EXTENDED | REG_NOSUB)
++          || regcomp(&excsre, "^[a-z0-9-].*dpkg-(old|dist)$",
++                     REG_EXTENDED | REG_NOSUB)
++          || regcomp(&tradre, "^[a-z0-9][a-z0-9-]*$", REG_NOSUB)
++          || regcomp(&classicalre, "^[a-zA-Z0-9_-]+$",
++                     REG_EXTENDED | REG_NOSUB)) {
++          log_it("CRON", getpid(), "REGEX FAILED", "valid_name");
++          (void) exit(ERROR_EXIT);
++      }
++  }
++  if (lsbsysinit_mode) {
++      if (!regexec(&hierre, filename, 0, NULL, 0)) {
++          return regexec(&excsre, filename, 0, NULL, 0);
++      } else {
++          return !regexec(&tradre, filename, 0, NULL, 0);
++      }
++  }
++  /* Old standard style */
++  return !regexec(&classicalre, filename, 0, NULL, 0);
++}
++
++
++static user *
++get_next_system_crontab (curtab)
++	user	*curtab;
++{
++	for ( ; curtab != NULL; curtab = curtab->next)
++		if (!strncmp(curtab->name, "*system*", 8) && curtab->name [8])
++			break;
++	return curtab;
++}
++
++#endif
+Index: patched/pathnames.h
+===================================================================
+--- patched.orig/pathnames.h	2010-05-06 18:18:46.636435718 +0200
++++ patched/pathnames.h	2010-05-06 18:18:49.631436001 +0200
+@@ -67,7 +67,10 @@
+ 
+ 			/* 4.3BSD-style crontab */
+ #define SYSCRONTAB	"/etc/crontab"
+-
++#ifdef DEBIAN
++                        /* where package specific crontabs live */ 
++#define SYSCRONDIR      "/etc/cron.d"
++#endif
+ 			/* what editor to use if no EDITOR or VISUAL
+ 			 * environment variable specified.
+ 			 */
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:48.838561166 +0200
++++ patched/cron.h	2010-05-06 18:18:49.631436001 +0200
+@@ -188,7 +188,11 @@
+ 
+ typedef	struct _cron_db {
+ 	user		*head, *tail;	/* links */
+-	time_t		mtime;		/* last modtime on spooldir */
++	time_t		user_mtime;     /* last modtime on spooldir */
++	time_t		sys_mtime;      /* last modtime on system crontab */
++#ifdef DEBIAN
++	time_t		sysd_mtime;     /* last modtime on system crondir */
++#endif
+ } cron_db;
+ 
+ 
+@@ -267,6 +271,8 @@
+ int	LineNumber;
+ time_t	TargetTime;
+ 
++int     lsbsysinit_mode;
++
+ # if DEBUGGING
+ int	DebugFlags;
+ char	*DebugFlagNames[] = {	/* sync with #defines */
+@@ -279,6 +285,7 @@
+ 		*MonthNames[],
+ 		*DowNames[],
+ 		*ProgramName;
++extern  int     lsbsysinit_mode;
+ extern	int	LineNumber;
+ extern	time_t	TargetTime;
+ # if DEBUGGING
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:44.880437493 +0200
++++ patched/cron.c	2010-05-06 18:18:49.632435697 +0200
+@@ -131,7 +131,11 @@
+ 	acquire_daemonlock(0);
+ 	database.head = NULL;
+ 	database.tail = NULL;
+-	database.mtime = (time_t) 0;
++	database.sys_mtime = (time_t) 0;
++	database.user_mtime = (time_t) 0;
++#ifdef DEBIAN
++	database.sysd_mtime = (time_t) 0;
++#endif
+ 	load_database(&database);
+ 	run_reboot_jobs(&database);
+ 	cron_sync();
+@@ -317,7 +321,9 @@
+ {
+ 	int	argch;
+ 
+-	while (EOF != (argch = getopt(argc, argv, "x:"))) {
++        lsbsysinit_mode = 0;
++
++	while (EOF != (argch = getopt(argc, argv, "lx:"))) {
+ 		switch (argch) {
+ 		default:
+ 			usage();
+@@ -325,6 +331,9 @@
+ 			if (!set_debug_flags(optarg))
+ 				usage();
+ 			break;
++                case 'l':
++                    lsbsysinit_mode = 1;
++                    break;
+ 		}
+ 	}
+ }
diff --git a/debian/patches/features/swap-both-uid-and-gid b/debian/patches/features/swap-both-uid-and-gid
new file mode 100644
index 0000000..4e5b7a4
--- /dev/null
+++ b/debian/patches/features/swap-both-uid-and-gid
@@ -0,0 +1,36 @@
+Subject: swap_uid, swap_uid_back support group ids
+Author: Solar Designer
+Last-Update: 2010-04-11
+
+Save/swap the group id, too.
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:51.095435790 +0200
++++ patched/misc.c	2010-05-06 18:18:51.875560985 +0200
+@@ -676,11 +676,22 @@
+ 
+ 
+ #ifdef HAVE_SAVED_UIDS
+-static int save_euid;
+-int swap_uids() { save_euid = geteuid(); return seteuid(getuid()); }
+-int swap_uids_back() { return seteuid(save_euid); }
++static uid_t save_euid, save_egid;
++int swap_uids()
++{
++	save_euid = geteuid(); save_egid = getegid();
++	return (setegid(getgid()) || seteuid(getuid())) ? -1 : 0;
++}
++int swap_uids_back()
++{
++	return (setegid(save_egid) || seteuid(save_euid)) ? -1 : 0;
++}
+ #else /*HAVE_SAVED_UIDS*/
+-int swap_uids() { return setreuid(geteuid(), getuid()); }
++int swap_uids()
++{
++	return (setregid(getegid(), getgid()) || setreuid(geteuid(), getuid()))
++		? -1 : 0;
++}
+ int swap_uids_back() { return swap_uids(); }
+ #endif /*HAVE_SAVED_UIDS*/
+ 
diff --git a/debian/patches/fixes/abort-crontabs-with-errors b/debian/patches/fixes/abort-crontabs-with-errors
new file mode 100644
index 0000000..995a6c8
--- /dev/null
+++ b/debian/patches/fixes/abort-crontabs-with-errors
@@ -0,0 +1,39 @@
+Subject: Abort processing of crontabs with errors
+Author: Faidon Liambotis <FIXME>
+Last-Update: 2010-04-11
+
+Abort processing of a crontab when an error is encountered.
+
+Strictly speaking, this fix is mostly relevant only to the /etc/cron.d feature
+patch (in order to prevent a security issue). It is include in fixes/, however,
+because it made general sense. 
+
+Bug-Debian: http://bugs.debian.org/378153
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/user.c
+===================================================================
+--- patched.orig/user.c	2010-05-06 18:18:27.646435759 +0200
++++ patched/user.c	2010-05-06 18:18:32.328436004 +0200
+@@ -97,6 +97,9 @@
+  			 * newline, so we bail out
+ 			 */
+ 			if (envstr[0] != '\0') {
++                                log_it(u->name, getpid(), "ERROR", "Missing "
++                                "newline before EOF, this crontab file will be "
++                                "ignored");
+ 				free_user(u);
+ 				u = NULL;
+ 			}
+@@ -106,6 +109,11 @@
+ 			if (e) {
+ 				e->next = u->crontab;
+ 				u->crontab = e;
++			} else {
++				/* stop processing on syntax error */
++				free_user(u);
++				u = NULL;
++				goto done;
+ 			}
+ 			break;
+ 		case TRUE:
diff --git a/debian/patches/fixes/allow-crontab-by-users b/debian/patches/fixes/allow-crontab-by-users
new file mode 100644
index 0000000..cce01c6
--- /dev/null
+++ b/debian/patches/fixes/allow-crontab-by-users
@@ -0,0 +1,36 @@
+Subject: Allow use of crontab by users
+Last-Update: 2010-04-11
+
+Remove a bug denying non-privileged users crontab(1).
+
+Debian-Bug: http://bugs.debian.org/8702
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:28.844435899 +0200
++++ patched/crontab.c	2010-05-06 18:18:30.213560954 +0200
+@@ -156,18 +156,19 @@
+ 				usage("bad debug option");
+ 			break;
+ 		case 'u':
+-			if (getuid() != ROOT_UID)
+-			{
+-				fprintf(stderr,
+-					"must be privileged to use -u\n");
+-				exit(ERROR_EXIT);
+-			}
+ 			if (!(pw = getpwnam(optarg)))
+ 			{
+ 				fprintf(stderr, "%s:  user `%s' unknown\n",
+ 					ProgramName, optarg);
+ 				exit(ERROR_EXIT);
+ 			}
++			if ((getuid() != ROOT_UID) &&
++			    (getuid() != pw->pw_uid))
++			{
++				fprintf(stderr,
++					"must be privileged to use -u\n");
++				exit(ERROR_EXIT);
++			}
+ 			free(User);
+ 			if ((User=strdup(pw->pw_name)) == NULL) {
+ 			        fprintf(stderr, "Memory allocation error\n");
diff --git a/debian/patches/fixes/allow-editors-with-tmpfiles b/debian/patches/fixes/allow-editors-with-tmpfiles
new file mode 100644
index 0000000..bab2516
--- /dev/null
+++ b/debian/patches/fixes/allow-editors-with-tmpfiles
@@ -0,0 +1,311 @@
+Subject: Allow editors which create temporary files
+Last-Updated: 2010-04-11
+
+Certain editors such as vi use temporary files for editing. This caused
+problems with crontab's operation mode.
+
+Bug-Debian: http://bugs.debian.org/149908
+Bug-Debian: http://bugs.debian.org/413962
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:40.501560966 +0200
++++ patched/crontab.c	2010-05-06 18:18:41.216560876 +0200
+@@ -57,6 +57,7 @@
+ static	PID_T		Pid;
+ static	char		*User, *RealUser;
+ static	char		Filename[MAX_FNAME];
++static	char		Directory[MAX_FNAME];
+ static	FILE		*NewCrontab = NULL;
+ static	int		CheckErrorCount;
+ static	enum opt_t	Option;
+@@ -69,6 +70,10 @@
+ 			parse_args __P((int c, char *v[]));
+ static	int		replace_cmd __P((void));
+ 
++/* Support edit command */
++static  int             create_tmp_crontab __P((void));
++static  int             open_tmp_crontab __P((struct stat *fsbuf));
++static  void            cleanup_tmp_crontab __P((void));
+ 
+ static void
+ usage(msg)
+@@ -320,13 +325,154 @@
+ }
+ 
+ 
++/* The next several function implement 'crontab -e' */
++
++/* Returns -1 on error, or fd to tempfile. */
++static int
++create_tmp_crontab()
++{
++        const char *template = "/crontab.XXXXXX";
++        int nfd;
++        char *tmp;
++
++        /* Create the temp directory. Note that since crontab is
++           setuid(root), TMPDIR only work for root. */
++	if ((tmp=getenv("TMPDIR")) && strlen(tmp) < MAX_FNAME) {
++	  strcpy(Directory, tmp);
++	} else {
++	  strcpy(Directory,"/tmp");
++	}
++
++        if (strlen(Directory) + strlen(template) < MAX_FNAME) {
++                strcat(Directory, template);
++        } else {
++                fprintf(stderr, "TMPDIR value is to long -- exiting\n");
++                Directory[0] = '\0';
++                return -1;
++        }
++
++        if (!mkdtemp(Directory)) {
++                perror(Directory);
++                Directory[0] = '\0';
++                return -1;
++        }
++
++        if (chown(Directory, getuid(), getgid()) < 0) {
++                perror(Directory);
++                Directory[0] = '\0';
++                return -1;
++        }
++
++        /* Now create the actual temporary crontab file */
++        if (snprintf(Filename, MAX_FNAME, "%s/crontab", Directory)
++            >= MAX_FNAME) {
++                fprintf(stderr, "Temporary filename too long - aborting\n");
++                Filename[0] = '\0';
++                return -1;
++        }
++        if ((nfd=open(Filename, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1) {
++                perror(Filename);
++                Filename[0] = '\0';
++                return -1;
++        }
++        return nfd;
++}
++
++/* Re-open the new (temporary) crontab, and check to make sure that
++   no-one is playing games. Return 0 on success, -1 on error. (Why not
++   just fopen() and stat()? Because there's no guarantee that you
++   fopen()ed the file you stat()ed.) */
++static int
++open_tmp_crontab(fsbuf)
++      struct stat *fsbuf;
++{
++        int t;
++        struct stat statbuf;
++
++        if ((t=open(Filename, O_RDONLY)) < 0) {
++                perror("Can't open tempfile after edit");
++                return -1;
++        }
++
++	if (fstat(t, &statbuf) < 0) {
++		perror("fstat");
++		return -1;
++	}
++	if (statbuf.st_uid != getuid() || statbuf.st_gid != getgid()) {
++		fprintf(stderr, "Temporary crontab no longer owned by you.\n");
++		return -1;;
++	}
++
++        if (!S_ISREG(statbuf.st_mode)) {
++                fprintf(stderr, "The temporary crontab must remain a regular file");
++                return -1;
++        }
++
++        if (statbuf.st_mtime == fsbuf->st_mtime) {
++                return 1; /* No change to file */
++        }
++
++        NewCrontab = fdopen(t, "r");
++        if (!NewCrontab) {
++                perror("fdopen(): after edit");
++                return -1;
++        }
++        return 0;
++}
++
++/* We can't just delete Filename, because the editor might have
++   created other temporary files in there. If there's an error, we
++   just bail, and let the user/admin deal with it.*/
++
++static void
++cleanup_tmp_crontab(void) 
++{
++        DIR *dp;
++        struct dirent *ep;
++        char fname[MAX_FNAME];
++
++        if (Directory[0] == '\0') {
++                return;
++        }
++
++        /* Delete contents */
++        dp = opendir (Directory);
++        if (dp == NULL) {
++                perror(Directory);
++                return;
++        }
++
++        while ((ep = readdir (dp))) {
++                if (!strcmp(ep->d_name, ".") ||
++                    !strcmp(ep->d_name, "..")) {
++                        continue;
++                }
++                if (snprintf(fname, MAX_FNAME, "%s/%s",
++                             Directory, ep->d_name) >= MAX_FNAME) {
++                        fprintf(stderr, "filename too long to delete: %s/%s",
++                                Directory, ep->d_name);
++                        return;
++                }
++                if (unlink(fname)) {
++                        perror(ep->d_name);
++                        return;
++                }
++        }
++        (void) closedir (dp);
++
++        if (rmdir(Directory)) {
++                perror(Directory);
++                return;
++        }
++        return;
++}
++
+ static void
+ edit_cmd() {
+ 	char		n[MAX_FNAME], q[MAX_TEMPSTR], *editor;
+ 	FILE		*f;
+ 	int		ch, t, x;
+-	struct stat	statbuf;
+-	time_t		mtime;
++	struct stat     fsbuf;
+ 	WAIT_T		waiter;
+ 	PID_T		pid, xpid;
+ 	mode_t		um;
+@@ -347,23 +493,15 @@
+ 	}
+ 
+ 	um = umask(077);
+-	(void) snprintf(Filename, sizeof(Filename)-1, "/tmp/crontab.%d", Pid);
+-	Filename[sizeof(Filename)-1] = '\0';
+-	if (-1 == (t = open(Filename, O_CREAT|O_EXCL|O_RDWR, 0600))) {
+-		perror(Filename);
+-		goto fatal;
+-	}
+-#ifdef HAS_FCHOWN
+-	if (fchown(t, getuid(), getgid()) < 0) {
+-#else
+-	if (chown(Filename, getuid(), getgid()) < 0) {
+-#endif
+-		perror("fchown");
++
++        if ((t=create_tmp_crontab()) < 0) {
++                fprintf(stderr, "Creation of temporary crontab file failed - aborting\n");
++                (void) umask(um);
+ 		goto fatal;
+ 	}
+ 
+ 	(void) umask(um);
+-	if (!(NewCrontab = fdopen(t, "r+"))) {
++	if (!(NewCrontab = fdopen(t, "w"))) {
+ 		perror("fdopen");
+ 		goto fatal;
+ 	}
+@@ -393,23 +531,16 @@
+ 		while (EOF != (ch = get_char(f)))
+ 			putc(ch, NewCrontab);
+ 	fclose(f);
+-	if (fflush(NewCrontab) < OK) {
+-		perror(Filename);
+-		exit(ERROR_EXIT);
+-	}
+- again:
+-	rewind(NewCrontab);
++
+ 	if (ferror(NewCrontab)) {
+ 		fprintf(stderr, "%s: error while writing new crontab to %s\n",
+ 			ProgramName, Filename);
+- fatal:		unlink(Filename);
+-		exit(ERROR_EXIT);
+ 	}
+-	if (fstat(t, &statbuf) < 0) {
+-		perror("fstat");
++
++	if (fstat(t, &fsbuf) < 0) {
++		perror("unable to stat temp file");
+ 		goto fatal;
+ 	}
+-	mtime = statbuf.st_mtime;
+ 
+ 
+ 
+@@ -421,13 +552,14 @@
+ 		editor = EDITOR;
+ 	}
+ 
+-	/* we still have the file open.  editors will generally rewrite the
+-	 * original file rather than renaming/unlinking it and starting a
+-	 * new one; even backup files are supposed to be made by copying
+-	 * rather than by renaming.  if some editor does not support this,
+-	 * then don't use it.  the security problems are more severe if we
+-	 * close and reopen the file around the edit.
+-	 */
++ again:
++
++        /*  Close before cleanup_tmp_crontab is called or otherwise
++         *  (on NFS mounted /) will get renamed on unlink */
++	if (fclose(NewCrontab) != 0) {
++		perror(Filename);
++                goto fatal;
++	}
+ 
+ 	/* Turn off signals. */
+ 	(void)signal(SIGHUP, SIG_IGN);
+@@ -495,6 +627,21 @@
+ 	(void)signal(SIGQUIT, SIG_DFL);
+ 	(void)signal(SIGTSTP, SIG_DFL);
+ 
++        switch (open_tmp_crontab(&fsbuf)) {
++        case -1:
++                fprintf(stderr, "Error while editing crontab\n");
++                goto fatal;
++        case 1:
++                fprintf(stderr, "No modification made\n");
++                goto remove;
++        case 0:
++                break;
++        default:
++                fprintf(stderr,
++                        "cron at packages.debian.org fscked up. Send him a nasty note\n");
++                break;
++        }
++
+ 	fprintf(stderr, "%s: installing new crontab\n", ProgramName);
+ 	switch (replace_cmd()) {
+ 	case 0:
+@@ -525,10 +672,20 @@
+ 		    ProgramName);
+ 		goto fatal;
+ 	}
++
++       if (fclose(NewCrontab) != 0) {
++               perror(Filename);
++       }
++
+  remove:
+-	unlink(Filename);
++        cleanup_tmp_crontab();
+  done:
+ 	log_it(RealUser, Pid, "END EDIT", User);
++        return;
++ fatal:
++        cleanup_tmp_crontab();
++        unlink(Filename);
++        exit(ERROR_EXIT);
+ }
+ 
+ static char tn[MAX_FNAME];
diff --git a/debian/patches/fixes/check-for-broken-command b/debian/patches/fixes/check-for-broken-command
new file mode 100644
index 0000000..869fdd4
--- /dev/null
+++ b/debian/patches/fixes/check-for-broken-command
@@ -0,0 +1,26 @@
+Subject: Check for broken command in system crontab
+Last-Update: 2010-04-11
+
+This patch apparently adds a test for a superfluous star in a system crontab
+entry, eg:
+
+    * * * * * * some_command
+
+(Notice the 6th star, where only 5 should be). Otherwise, this patch doesn't
+make sense. Not that it makes much sense this way, either...
+
+NOT Acked
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:35.043561126 +0200
++++ patched/entry.c	2010-05-06 18:18:35.745561147 +0200
+@@ -246,6 +246,9 @@
+ 			goto eof;
+ 		}
+ 		Debug(DPARS, ("load_entry()...uid %d, gid %d\n",e->uid,e->gid))
++	} else if (ch == '*') {
++		ecode = e_cmd;
++		goto eof;
+ 	}
+ 
+ 	e->uid = pw->pw_uid;
diff --git a/debian/patches/fixes/check-for-full-disk b/debian/patches/fixes/check-for-full-disk
new file mode 100644
index 0000000..107743e
--- /dev/null
+++ b/debian/patches/fixes/check-for-full-disk
@@ -0,0 +1,53 @@
+Subject: Check for full disk
+Last-Update: 2010-10-11
+
+Raise an error if we couldn't write the crontab to disk.
+ 
+Debian-Bug: http://bugs.debian.org/110612
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:39.796561016 +0200
++++ patched/crontab.c	2010-05-06 18:18:40.501560966 +0200
+@@ -596,19 +596,17 @@
+ 	Set_LineNum(1)
+ 	while (EOF != (ch = get_char(NewCrontab)))
+ 		putc(ch, tmp);
+-	ftruncate(fileno(tmp), ftell(tmp));
+-	fflush(tmp);  rewind(tmp);
+ 
+-	if (ferror(tmp)) {
+-		fprintf(stderr, "%s: error while writing new crontab to %s\n",
+-			ProgramName, tn);
++	if (ferror(tmp) || fflush(tmp) || fsync(fd)) {
++		fprintf(stderr, "%s: %s: %s\n",
++			ProgramName, tn, strerror(errno));
+ 		fclose(tmp);  unlink(tn);
+ 		return (-2);
+ 	}
+ 
+ 	/* check the syntax of the file being installed.
+ 	 */
+-
++	rewind(tmp);
+ 	/* BUG: was reporting errors after the EOF if there were any errors
+ 	 * in the file proper -- kludged it by stopping after first error.
+ 	 *		vix 31mar87
+@@ -658,6 +656,7 @@
+ 		return (-2);
+ 	}
+ 
++
+ 	if (fclose(tmp) == EOF) {
+ 		perror("fclose");
+ 		unlink(tn);
+@@ -671,6 +670,8 @@
+ 		unlink(tn);
+ 		return (-2);
+ 	}
++
++
+ 	log_it(RealUser, Pid, "REPLACE", User);
+ 
+ 	poke_daemon();
diff --git a/debian/patches/fixes/compilation-issues b/debian/patches/fixes/compilation-issues
new file mode 100644
index 0000000..afb0643
--- /dev/null
+++ b/debian/patches/fixes/compilation-issues
@@ -0,0 +1,23 @@
+Subject: Fix compilation issues
+Last-Update: 2010-04-11
+
+Resolve issues related to compilation (Makefile, etc).
+
+
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:41.972560882 +0200
++++ patched/crontab.c	2010-05-06 18:18:43.421561039 +0200
+@@ -137,6 +137,12 @@
+ 	case opt_replace:	if (replace_cmd() < 0)
+ 					exitstatus = ERROR_EXIT;
+ 				break;
++				/* The following was added to shut
++				 -Wall up, but it will never be hit,
++				 because the option parser will catch
++				 it */
++	case opt_unknown: usage("unknown option specified");
++	                  break;
+ 	}
+ 	exit(exitstatus);
+ 	/*NOTREACHED*/
diff --git a/debian/patches/fixes/correct-flag-setting-in-crontab-entry b/debian/patches/fixes/correct-flag-setting-in-crontab-entry
new file mode 100644
index 0000000..b3ef7d1
--- /dev/null
+++ b/debian/patches/fixes/correct-flag-setting-in-crontab-entry
@@ -0,0 +1,48 @@
+Subject: Correct which/how flags are set for entries
+Last-Update: 2010-04-11
+
+In the entry processing code, either set certain internal flags which are missing or
+correct broken settings. 
+
+Bug-Debian: http://bugs.debian.org/43282
+Bug-Debian: http://bugs.debian.org/62141
+Bug-Debian: http://bugs.debian.org/84727
+Bug-Debian: http://bugs.debian.org/150591
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:28.217435826 +0200
++++ patched/entry.c	2010-05-06 18:18:35.043561126 +0200
+@@ -130,18 +130,21 @@
+ 			bit_set(e->dom, 0);
+ 			bit_set(e->month, 0);
+ 			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
++                        e->flags |= DOW_STAR; 
+ 		} else if (!strcmp("monthly", cmd)) {
+ 			bit_set(e->minute, 0);
+ 			bit_set(e->hour, 0);
+ 			bit_set(e->dom, 0);
+ 			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+ 			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
++                        e->flags |= DOW_STAR;
+ 		} else if (!strcmp("weekly", cmd)) {
+ 			bit_set(e->minute, 0);
+ 			bit_set(e->hour, 0);
+ 			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
++			e->flags |= DOM_STAR;
+ 			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+-			bit_set(e->dow, 0);
++			bit_nset(e->dow, 0,0);
+ 		} else if (!strcmp("daily", cmd) || !strcmp("midnight", cmd)) {
+ 			bit_set(e->minute, 0);
+ 			bit_set(e->hour, 0);
+@@ -150,7 +153,7 @@
+ 			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
+ 		} else if (!strcmp("hourly", cmd)) {
+ 			bit_set(e->minute, 0);
+-			bit_set(e->hour, (LAST_HOUR-FIRST_HOUR+1));
++			bit_nset(e->hour, 0, (LAST_HOUR-FIRST_HOUR+1));
+ 			bit_nset(e->dom, 0, (LAST_DOM-FIRST_DOM+1));
+ 			bit_nset(e->month, 0, (LAST_MONTH-FIRST_MONTH+1));
+ 			bit_nset(e->dow, 0, (LAST_DOW-FIRST_DOW+1));
diff --git a/debian/patches/fixes/correct-use-of-error-messages b/debian/patches/fixes/correct-use-of-error-messages
new file mode 100644
index 0000000..f159e8a
--- /dev/null
+++ b/debian/patches/fixes/correct-use-of-error-messages
@@ -0,0 +1,152 @@
+Subject: Correct use of error messages
+Author: Justin Pryzby <justinpryzby at users.sourceforge.net>
+Last Update: 2004-10-11
+
+Fix the use of perror so that the error message is correct when printing the
+reason why an operation failed. Thanks to Justin Pryzby for the patch.
+
+Debian-Bug: http://bugs.debian/org/470587
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:28.216436280 +0200
++++ patched/do_command.c	2010-05-06 18:18:28.844435899 +0200
+@@ -229,8 +229,7 @@
+ 			}
+ # endif /*DEBUGGING*/
+ 			execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
+-			fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
+-			perror("execl");
++			fprintf(stderr, "%s: execle: %s\n", shell, strerror(errno));
+ 			_exit(ERROR_EXIT);
+ 		}
+ 		break;
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:28.217435826 +0200
++++ patched/misc.c	2010-05-06 18:18:28.844435899 +0200
+@@ -200,8 +200,7 @@
+ 			fprintf(stderr, "%s: created\n", CRONDIR);
+ 			stat(CRONDIR, &sb);
+ 		} else {
+-			fprintf(stderr, "%s: ", CRONDIR);
+-			perror("mkdir");
++			fprintf(stderr, "%s: mkdir: %s\n", CRONDIR, strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
+ 	}
+@@ -211,8 +210,7 @@
+ 		exit(ERROR_EXIT);
+ 	}
+ 	if (chdir(CRONDIR) < OK) {
+-		fprintf(stderr, "cannot chdir(%s), bailing out.\n", CRONDIR);
+-		perror(CRONDIR);
++		fprintf(stderr, "%s: chdir: %s\n", CRONDIR, strerror(errno));
+ 		exit(ERROR_EXIT);
+ 	}
+ 
+@@ -224,8 +222,7 @@
+ 			fprintf(stderr, "%s: created\n", SPOOL_DIR);
+ 			stat(SPOOL_DIR, &sb);
+ 		} else {
+-			fprintf(stderr, "%s: ", SPOOL_DIR);
+-			perror("mkdir");
++			fprintf(stderr, "%s: mkdir: %s\n", SPOOL_DIR, strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
+ 	}
+@@ -487,9 +484,8 @@
+ 	if (LogFD < OK) {
+ 		LogFD = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600);
+ 		if (LogFD < OK) {
+-			fprintf(stderr, "%s: can't open log file\n",
+-				ProgramName);
+-			perror(LOG_FILE);
++			fprintf(stderr, "%s: %s: open: %s\n",
++				ProgramName, LOG_FILE, strerror(errno));
+ 		} else {
+ 			(void) fcntl(LogFD, F_SETFD, 1);
+ 		}
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:28.216436280 +0200
++++ patched/crontab.c	2010-05-06 18:18:28.844435899 +0200
+@@ -256,10 +256,11 @@
+ 	log_it(RealUser, Pid, "LIST", User);
+ 	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+ 	if (!(f = fopen(n, "r"))) {
+-		if (errno == ENOENT)
++		if (errno == ENOENT) 
+ 			fprintf(stderr, "no crontab for %s\n", User);
+-		else
+-			perror(n);
++		else {
++                        fprintf(stderr, "%s/: fopen: %s\n", n, strerror(errno));
++                }
+ 		exit(ERROR_EXIT);
+ 	}
+ 
+@@ -281,8 +282,9 @@
+ 	if (unlink(n)) {
+ 		if (errno == ENOENT)
+ 			fprintf(stderr, "no crontab for %s\n", User);
+-		else
+-			perror(n);
++		else {
++                        fprintf(stderr, "%s/: unlink: %s\n", CRONDIR, strerror(errno));
++                }
+ 		exit(ERROR_EXIT);
+ 	}
+ 	poke_daemon();
+@@ -312,7 +314,7 @@
+ 	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+ 	if (!(f = fopen(n, "r"))) {
+ 		if (errno != ENOENT) {
+-			perror(n);
++                        fprintf(stderr, "%s/: fdopen: %s", n, strerror(errno));
+ 			exit(ERROR_EXIT);
+ 		}
+ 		fprintf(stderr, "no crontab for %s - using an empty one\n",
+@@ -535,8 +537,8 @@
+ 	fflush(tmp);  rewind(tmp);
+ 
+ 	if (ferror(tmp)) {
+-		fprintf(stderr, "%s: error while writing new crontab to %s\n",
+-			ProgramName, tn);
++		fprintf(stderr, "%s: %s: %s\n",
++			ProgramName, tn, strerror(errno));
+ 		fclose(tmp);  unlink(tn);
+ 		return (-2);
+ 	}
+@@ -601,9 +603,8 @@
+ 
+ 	(void) snprintf(n, sizeof(n), CRON_TAB(User));
+ 	if (rename(tn, n)) {
+-		fprintf(stderr, "%s: error renaming %s to %s\n",
+-			ProgramName, tn, n);
+-		perror("rename");
++		fprintf(stderr, "%s: %s: rename: %s\n",
++			ProgramName, n, strerror(errno));
+ 		unlink(tn);
+ 		return (-2);
+ 	}
+@@ -624,14 +625,14 @@
+ 	(void) gettimeofday(&tvs[0], &tz);
+ 	tvs[1] = tvs[0];
+ 	if (utimes(SPOOL_DIR, tvs) < OK) {
+-		fprintf(stderr, "crontab: can't update mtime on spooldir\n");
+-		perror(SPOOL_DIR);
++                fprintf(stderr, "%s/: utimes: %s", CRONDIR, strerror(errno));
++		fputs("crontab: can't update mtime on spooldir\n", stderr);
+ 		return;
+ 	}
+ #else
+ 	if (utime(SPOOL_DIR, NULL) < OK) {
+-		fprintf(stderr, "crontab: can't update mtime on spooldir\n");
+-		perror(SPOOL_DIR);
++                fprintf(stderr, "%s: utime: %s\n", CRONDIR, strerror(errno));
++		fputs("crontab: can't update mtime on spooldir\n", stderr);
+ 		return;
+ 	}
+ #endif /*USE_UTIMES*/
diff --git a/debian/patches/fixes/crontab-entry-parsing b/debian/patches/fixes/crontab-entry-parsing
new file mode 100644
index 0000000..bf1b695
--- /dev/null
+++ b/debian/patches/fixes/crontab-entry-parsing
@@ -0,0 +1,38 @@
+Subject: Fixes for crontab entry parsing
+Last-Update: 2010-04-11
+
+Handle bogues values, whitespace, ...
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:25.803561007 +0200
++++ patched/entry.c	2010-05-06 18:18:26.422435960 +0200
+@@ -218,6 +218,9 @@
+ 		bit_set(e->dow, 7);
+ 	}
+ 
++	/* If we used one of the @commands, we may be pointing at
++       blanks, and if we don't skip over them, we'll miss the user/command */	
++    Skip_Blanks(ch, file);
+ 	/* ch is the first character of a command, or a username */
+ 	unget_char(ch, file);
+ 
+@@ -418,7 +421,7 @@
+ 		 * sent as a 0 since there is no offset either.
+ 		 */
+ 		ch = get_number(&num3, 0, PPC_NULL, ch, file);
+-		if (ch == EOF)
++		if (ch == EOF || num3 <= 0)
+ 			return EOF;
+ 	} else {
+ 		/* no step.  default==1.
+@@ -468,6 +471,10 @@
+ 	}
+ 	*pc = '\0';
+ 
++        if (len == 0) {
++            return EOF;
++        }
++
+ 	/* try to find the name in the name list
+ 	 */
+ 	if (names) {
diff --git a/debian/patches/fixes/crontab-file-parsing b/debian/patches/fixes/crontab-file-parsing
new file mode 100644
index 0000000..bbcbcc6
--- /dev/null
+++ b/debian/patches/fixes/crontab-file-parsing
@@ -0,0 +1,59 @@
+Subject: Fix crontab file parsing
+Author: Christian Kastner <debian at kvr.at>
+Last-Update: 2010-04-14
+
+The crontab parsing code contains a test condition that can never be reached.
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/user.c
+===================================================================
+--- patched.orig/user.c	2010-05-06 18:18:15.861436066 +0200
++++ patched/user.c	2010-05-06 18:18:25.803561007 +0200
+@@ -75,11 +75,20 @@
+ 	/*
+ 	 * load the crontab
+ 	 */
+-	while ((status = load_env(envstr, file)) >= OK) {
++	do {
++		status = load_env(envstr, file);
+ 		switch (status) {
+ 		case ERR:
+-			free_user(u);
+-			u = NULL;
++			/* If envstr has no content, we reached a proper EOF
++ 			 * and we can return to continue regular processing.
++			 *
++ 			 * If it does have content, we reached EOF without a
++ 			 * newline, so we bail out
++			 */
++			if (envstr[0] != '\0') {
++				free_user(u);
++				u = NULL;
++			}
+ 			goto done;
+ 		case FALSE:
+ 			e = load_entry(file, NULL, pw, envp);
+@@ -92,7 +101,7 @@
+ 			envp = env_set(envp, envstr);
+ 			break;
+ 		}
+-	}
++	} while (status >= OK);
+ 
+  done:
+ 	env_free(envp);
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:15.855435677 +0200
++++ patched/entry.c	2010-05-06 18:18:25.803561007 +0200
+@@ -277,6 +277,10 @@
+ 	ch = get_string(cmd, MAX_COMMAND, file, "\n");
+ 
+ 	/* a file without a \n before the EOF is rude, so we'll complain...
++
++	   CK 2010-04-14: this code will never be reached. All calls to
++	   load_entry are proceeded by calls to load_env, which aborts on EOF, and
++       where load_env fails, the code bails out.
+ 	 */
+ 	if (ch == EOF) {
+ 		ecode = e_cmd;
diff --git a/debian/patches/fixes/crontab-time-parsing b/debian/patches/fixes/crontab-time-parsing
new file mode 100644
index 0000000..8a053e4
--- /dev/null
+++ b/debian/patches/fixes/crontab-time-parsing
@@ -0,0 +1,22 @@
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:26.422435960 +0200
++++ patched/entry.c	2010-05-06 18:18:27.017560712 +0200
+@@ -429,6 +429,17 @@
+ 		num3 = 1;
+ 	}
+ 
++	/* Explicitly check for sane values. Certain combinations of ranges and
++	 * steps which should return EOF don't get picked up by the code below,
++	 * eg:
++	 *	5-64/30 * * * *	touch /dev/null
++	 *
++	 * Code adapted from set_elements() where this error was probably intended
++	 * to be catched.
++	 */
++	if (num1 < low || num1 > high || num2 < low || num2 > high)
++		return EOF;
++
+ 	/* range. set all elements from num1 to num2, stepping
+ 	 * by num3.  (the step is a downward-compatible extension
+ 	 * proposed conceptually by bob at acornrc, syntactically
diff --git a/debian/patches/fixes/dont-give-root-on-repeated-edits b/debian/patches/fixes/dont-give-root-on-repeated-edits
new file mode 100644
index 0000000..5f1db9f
--- /dev/null
+++ b/debian/patches/fixes/dont-give-root-on-repeated-edits
@@ -0,0 +1,53 @@
+Subject: Don't give root privileges on repeated edits
+Last-Update: 2010-04-11
+
+Because of an oversight, repeated edits wouldn't drop privileges prior to
+editing.
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:41.216560876 +0200
++++ patched/crontab.c	2010-05-06 18:18:41.972560882 +0200
+@@ -709,12 +709,21 @@
+ 	time_t	now = time(NULL);
+ 	char	**envp = env_init();
+ 	mode_t	um;
++	int	saved_uid;
+ 
+ 	if (envp == NULL) {
+ 		fprintf(stderr, "%s: Cannot allocate memory.\n", ProgramName);
+ 		return (-2);
+ 	}
+ 
++	/* Assume privilege.  This way we can only receive signals on our
++	   input - the ones listed below (or from root - root's problem, not
++	   ours). */
++	saved_uid = getuid();
++	if (setuid(geteuid()) < 0) {
++		perror("setuid");
++		return -2;
++	}
+ 
+ 	/* Assumes Linux-style signal handlers (takes int, returns void) */
+ 	/* Signal handlers, to ensure we do not leave temp files in the
+@@ -788,6 +797,9 @@
+ 	if (CheckErrorCount != 0) {
+ 		fprintf(stderr, "errors in crontab file, can't install.\n");
+ 		fclose(tmp);  unlink(tn);
++		/* Give up privilege, in case we loop. */
++		if (setreuid(saved_uid, -1) < 0)
++			return (-2);
+ 		return (-1);
+ 	}
+ 
+@@ -833,6 +845,11 @@
+ 
+ 	poke_daemon();
+ 
++	/* Give up privilege, just in case. */
++	/* Don't need to check for error; nothing happens beyond here but a log entry,
++	   and the failure message is incorrect after the rename above. */
++	setreuid(saved_uid, -1);
++
+ 	return (0);
+ }
+ 
diff --git a/debian/patches/fixes/dont-log-temp-files b/debian/patches/fixes/dont-log-temp-files
new file mode 100644
index 0000000..83c6702
--- /dev/null
+++ b/debian/patches/fixes/dont-log-temp-files
@@ -0,0 +1,17 @@
+Subject: Don't log temporary files
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:18:28.217435826 +0200
++++ patched/database.c	2010-05-06 18:18:36.431560887 +0200
+@@ -217,7 +217,10 @@
+ 	if (strcmp(fname, "*system*") && !(pw = getpwnam(uname))) {
+ 		/* file doesn't have a user in passwd file.
+ 		 */
+-		log_it(fname, getpid(), "ORPHAN", "no passwd entry");
++		if (strncmp(fname, "tmp.", 4)) {
++			/* don't log these temporary files */
++			log_it(fname, getpid(), "ORPHAN", "no passwd entry");
++		}
+ 		goto next_crontab;
+ 	}
+ 
diff --git a/debian/patches/fixes/drop-privileges b/debian/patches/fixes/drop-privileges
new file mode 100644
index 0000000..a86861d
--- /dev/null
+++ b/debian/patches/fixes/drop-privileges
@@ -0,0 +1,119 @@
+Subject: Drop privileges where appropriate
+Last-Update: 2010-04-11
+
+Ensure that we drop privileges when running commands on behalf of a user.
+
+Bug-Debian: http://bugs.debian.org/528434
+Bug-Debian: http://bugs.debian.org/85609
+Bug-Debian: http://bugs.debian.org/86775
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:28.216436280 +0200
++++ patched/cron.h	2010-05-06 18:18:30.896560600 +0200
+@@ -226,7 +226,7 @@
+ entry		*load_entry __P((FILE *, void (*)(),
+ 				 struct passwd *, char **));
+ 
+-FILE		*cron_popen __P((char *, char *));
++FILE		*cron_popen __P((char *, char *, entry *));
+ 
+ 
+ 				/* in the C tradition, we only create
+Index: patched/popen.c
+===================================================================
+--- patched.orig/popen.c	2010-05-06 18:18:25.171561124 +0200
++++ patched/popen.c	2010-05-06 18:18:30.896560600 +0200
+@@ -48,8 +48,9 @@
+ static int fds;
+ 
+ FILE *
+-cron_popen(program, type)
++cron_popen(program, type, e)
+ 	char *program, *type;
++	entry *e;
+ {
+ 	register char *cp;
+ 	FILE *iop;
+@@ -120,6 +121,34 @@
+ 			}
+ 			(void)close(pdes[1]);
+ 		}
++ 		/* set our directory, uid and gid.  Set gid first, since once
++         * we set uid, we've lost root privleges.
++         */
++        if (setgid(e->gid) !=0) {
++          char msg[256];
++          snprintf(msg, 256, "popen:setgid(%lu) failed: %s",
++               (unsigned long) e->gid, strerror(errno));
++          log_it("CRON",getpid(),"error",msg);
++          exit(ERROR_EXIT);
++        }
++# if defined(BSD) || defined(POSIX)
++		if (initgroups(env_get("LOGNAME", e->envp), e->gid) !=0) {
++		  char msg[256];
++		  snprintf(msg, 256, "popen:initgroups(%lu) failed: %s",
++			   (unsigned long) e->gid, strerror(errno));
++		  log_it("CRON",getpid(),"error",msg);
++		  exit(ERROR_EXIT);
++                }
++# endif
++		if (setuid(e->uid) !=0) {
++		  char msg[256];
++		  snprintf(msg, 256, "popen: setuid(%lu) failed: %s",
++			   (unsigned long) e->uid, strerror(errno)); 
++		  log_it("CRON",getpid(),"error",msg);
++		  exit(ERROR_EXIT);
++		}	
++		chdir(env_get("HOME", e->envp));
++
+ #if WANT_GLOBBING
+ 		execvp(gargv[0], gargv);
+ #else
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:29.548561115 +0200
++++ patched/do_command.c	2010-05-06 18:18:30.896560600 +0200
+@@ -210,11 +210,29 @@
+ 		/* set our directory, uid and gid.  Set gid first, since once
+ 		 * we set uid, we've lost root privledges.
+ 		 */
+-		setgid(e->gid);
++		if (setgid(e->gid) !=0) {
++		  char msg[256];
++		  snprintf(msg, 256, "do_command:setgid(%lu) failed: %s",
++			   (unsigned long) e->gid, strerror(errno));
++		  log_it("CRON",getpid(),"error",msg);
++		  exit(ERROR_EXIT);
++		}
+ # if defined(BSD) || defined(POSIX)
+-		initgroups(env_get("LOGNAME", e->envp), e->gid);
++		if (initgroups(env_get("LOGNAME", e->envp), e->gid) !=0) {
++		  char msg[256];
++		  snprintf(msg, 256, "do_command:initgroups(%lu) failed: %s",
++			   (unsigned long) e->gid, strerror(errno));
++		  log_it("CRON",getpid(),"error",msg);
++		  exit(ERROR_EXIT);
++		}
+ # endif
+-		setuid(e->uid);		/* we aren't root after this... */
++		if (setuid(e->uid) !=0) { /* we aren't root after this... */
++		  char msg[256];
++		  snprintf(msg, 256, "do_command:setuid(%lu) failed: %s",
++			   (unsigned long) e->uid, strerror(errno)); 
++		  log_it("CRON",getpid(),"error",msg);
++		  exit(ERROR_EXIT);
++		}	
+ 		chdir(env_get("HOME", e->envp));
+ 
+ 		/* exec the command.
+@@ -371,7 +389,7 @@
+ 				(void) gethostname(hostname, MAXHOSTNAMELEN);
+ 				(void) snprintf(mailcmd, sizeof(mailcmd),
+ 				    MAILARGS, MAILCMD, mailto);
+-				if (!(mail = cron_popen(mailcmd, "w"))) {
++				if (!(mail = cron_popen(mailcmd, "w", e))) {
+ 					perror(MAILCMD);
+ 					(void) _exit(ERROR_EXIT);
+ 				}
diff --git a/debian/patches/fixes/general-coding-errors b/debian/patches/fixes/general-coding-errors
new file mode 100644
index 0000000..b9e00a4
--- /dev/null
+++ b/debian/patches/fixes/general-coding-errors
@@ -0,0 +1,161 @@
+Subject: General coding errors
+Last-Update: 2010-04-11
+
+These are mostly one-line fixes of obvious errors such as missing arguments,
+typos etc. Creating separate patches for them would be overkill.
+
+Bug-Debian: http://bugs.debian.org/53735
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/compat.c
+===================================================================
+--- patched.orig/compat.c	2010-05-06 18:18:16.073435740 +0200
++++ patched/compat.c	2010-05-06 18:18:24.437560974 +0200
+@@ -227,7 +227,7 @@
+ 		return -1;
+ 	}
+ 
+-	sprintf("%s=%s", name, value);
++	sprintf(tmp, "%s=%s", name, value);
+ 	return putenv(tmp);	/* intentionally orphan 'tmp' storage */
+ }
+ #endif
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:16.078436032 +0200
++++ patched/crontab.c	2010-05-06 18:18:24.437560974 +0200
+@@ -57,7 +57,7 @@
+ static	PID_T		Pid;
+ static	char		User[MAX_UNAME], RealUser[MAX_UNAME];
+ static	char		Filename[MAX_FNAME];
+-static	FILE		*NewCrontab;
++static	FILE		*NewCrontab = NULL;
+ static	int		CheckErrorCount;
+ static	enum opt_t	Option;
+ static	struct passwd	*pw;
+@@ -125,7 +125,7 @@
+ 					exitstatus = ERROR_EXIT;
+ 				break;
+ 	}
+-	exit(0);
++	exit(exitstatus);
+ 	/*NOTREACHED*/
+ }
+ 	
+@@ -227,7 +227,7 @@
+ 				perror(Filename);
+ 				exit(ERROR_EXIT);
+ 			}
+-			if (swap_uids() < OK) {
++			if (swap_uids_back() < OK) {
+ 				perror("swapping uids back");
+ 				exit(ERROR_EXIT);
+ 			}
+@@ -453,7 +453,7 @@
+ 		break;
+ 	case -1:
+ 		for (;;) {
+-			printf("Do you want to retry the same edit? ");
++			printf("Do you want to retry the same edit? (y/n) ");
+ 			fflush(stdout);
+ 			q[0] = '\0';
+ 			(void) fgets(q, sizeof q, stdin);
+@@ -473,7 +473,8 @@
+ 			ProgramName, Filename);
+ 		goto done;
+ 	default:
+-		fprintf(stderr, "%s: panic: bad switch() in replace_cmd()\n");
++		fprintf(stderr, "%s: panic: bad switch() in replace_cmd()\n",
++		    ProgramName);
+ 		goto fatal;
+ 	}
+  remove:
+@@ -574,7 +575,7 @@
+ 	if (chmod(tn, 0600) < OK)
+ #endif
+ 	{
+-		perror("chown");
++		perror("chmod");
+ 		fclose(tmp);  unlink(tn);
+ 		return (-2);
+ 	}
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:16.094435737 +0200
++++ patched/misc.c	2010-05-06 18:18:24.458435579 +0200
+@@ -308,7 +308,7 @@
+ 
+ 	ch = getc(file);
+ 	if (ch == '\n')
+-		Set_LineNum(LineNumber + 1)
++		Set_LineNum(LineNumber + 1);
+ 	return ch;
+ }
+ 
+@@ -322,7 +322,7 @@
+ {
+ 	ungetc(ch, file);
+ 	if (ch == '\n')
+-		Set_LineNum(LineNumber - 1)
++	       Set_LineNum(LineNumber - 1);
+ }
+ 
+ 
+@@ -533,7 +533,7 @@
+ #if DEBUGGING
+ 	if (DebugFlags) {
+ 		fprintf(stderr, "log_it: (%s %d) %s (%s)\n",
+-			username, pid, event, detail);
++			username, xpid, event, detail);
+ 	}
+ #endif
+ }
+Index: patched/env.c
+===================================================================
+--- patched.orig/env.c	2010-05-06 18:18:16.088435734 +0200
++++ patched/env.c	2010-05-06 18:18:24.458435579 +0200
+@@ -39,6 +39,9 @@
+ {
+ 	char	**p;
+ 
++	if(!envp)
++		return;
++
+ 	for (p = envp;  *p;  p++)
+ 		free(*p);
+ 	free(envp);
+@@ -168,7 +171,7 @@
+ 	register int	len = strlen(name);
+ 	register char	*p, *q;
+ 
+-	while (p = *envp++) {
++	while ((p = *envp++)) {
+ 		if (!(q = strchr(p, '=')))
+ 			continue;
+ 		if ((q - p) == len && !strncmp(p, name, len))
+Index: patched/popen.c
+===================================================================
+--- patched.orig/popen.c	2010-05-06 18:18:22.672435408 +0200
++++ patched/popen.c	2010-05-06 18:18:24.458435579 +0200
+@@ -62,7 +62,7 @@
+ 	extern char **glob(), **copyblk();
+ #endif
+ 
+-	if (*type != 'r' && *type != 'w' || type[1])
++	if ((*type != 'r' && *type != 'w') || type[1])
+ 		return(NULL);
+ 
+ 	if (!pids) {
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:22.672435408 +0200
++++ patched/do_command.c	2010-05-06 18:18:24.458435579 +0200
+@@ -331,7 +331,7 @@
+ 		register int	ch = getc(in);
+ 
+ 		if (ch != EOF) {
+-			register FILE	*mail;
++			register FILE	*mail = NULL;
+ 			register int	bytes = 1;
+ 			int		status = 0;
+ 
diff --git a/debian/patches/fixes/general-platform-issues b/debian/patches/fixes/general-platform-issues
new file mode 100644
index 0000000..51a469e
--- /dev/null
+++ b/debian/patches/fixes/general-platform-issues
@@ -0,0 +1,194 @@
+Subject: General platform-related issues
+Author: Steve Greenland <stevegr at debian.org>
+Last-Update: 2010-04-11
+
+Various platform-related fixes, additions or updates. These are quite numerous
+because the upstream code is from 1993.
+
+Bug-Debian: http://bugs.debian.org/64382
+Bug-Debian: http://bugs.debian.org/50240
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/externs.h
+===================================================================
+--- patched.orig/externs.h	2010-05-06 18:18:16.268435775 +0200
++++ patched/externs.h	2010-05-06 18:18:22.672435408 +0200
+@@ -20,6 +20,7 @@
+ # include <unistd.h>
+ # include <string.h>
+ # include <dirent.h>
++# include <errno.h>
+ # define DIR_T	struct dirent
+ # define WAIT_T	int
+ # define WAIT_IS_INT 1
+@@ -55,6 +56,7 @@
+ extern	void		perror(), exit(), free();
+ extern	char		*getenv(), *strcpy(), *strchr(), *strtok();
+ extern	void		*malloc(), *realloc();
++
+ # define SIG_T	void
+ # define TIME_T	long
+ # define PID_T int
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:16.252435886 +0200
++++ patched/cron.c	2010-05-06 18:18:22.672435408 +0200
+@@ -24,7 +24,7 @@
+ 
+ 
+ #include "cron.h"
+-#include <sys/signal.h>
++#include <signal.h>
+ #if SYS_TIME_H
+ # include <sys/time.h>
+ #else
+Index: patched/popen.c
+===================================================================
+--- patched.orig/popen.c	2010-05-06 18:18:16.279435871 +0200
++++ patched/popen.c	2010-05-06 18:18:22.672435408 +0200
+@@ -29,7 +29,11 @@
+ #endif /* not lint */
+ 
+ #include "cron.h"
+-#include <sys/signal.h>
++#include <signal.h>
++
++#if defined(BSD) || defined(POSIX)
++#  include <grp.h>
++#endif
+ 
+ 
+ #define WANT_GLOBBING 0
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:16.263436081 +0200
++++ patched/do_command.c	2010-05-06 18:18:22.672435408 +0200
+@@ -21,7 +21,8 @@
+ 
+ 
+ #include "cron.h"
+-#include <sys/signal.h>
++#include <signal.h>
++#include <grp.h>
+ #if defined(sequent)
+ # include <sys/universe.h>
+ #endif
+@@ -207,7 +208,7 @@
+ 		 * we set uid, we've lost root privledges.
+ 		 */
+ 		setgid(e->gid);
+-# if defined(BSD)
++# if defined(BSD) || defined(POSIX)
+ 		initgroups(env_get("LOGNAME", e->envp), e->gid);
+ # endif
+ 		setuid(e->uid);		/* we aren't root after this... */
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:18:16.257436063 +0200
++++ patched/database.c	2010-05-06 18:18:22.672435408 +0200
+@@ -28,9 +28,20 @@
+ #include <sys/stat.h>
+ #include <sys/file.h>
+ 
+-
+ #define TMAX(a,b) ((a)>(b)?(a):(b))
+ 
++/* Try to get maximum path name -- this isn't really correct, but we're
++going to be lazy */
++
++#ifndef PATH_MAX
++
++#ifdef MAXPATHLEN
++#define PATH_MAX MAXPATHLEN 
++#else
++#define PATH_MAX 2048
++#endif
++
++#endif /* ifndef PATH_MAX */
+ 
+ static	void		process_crontab __P((char *, char *, char *,
+ 					     struct stat *,
+@@ -102,7 +113,7 @@
+ 
+ 	while (NULL != (dp = readdir(dir))) {
+ 		char	fname[MAXNAMLEN+1],
+-			tabname[MAXNAMLEN+1];
++			tabname[PATH_MAX+1];
+ 
+ 		/* avoid file names beginning with ".".  this is good
+ 		 * because we would otherwise waste two guaranteed calls
+Index: patched/compat.h
+===================================================================
+--- patched.orig/compat.h	2010-05-06 18:18:16.247436070 +0200
++++ patched/compat.h	2010-05-06 18:18:22.672435408 +0200
+@@ -62,8 +62,8 @@
+ #endif
+ 
+ #ifndef POSIX
+-# if (BSD >= 199103) || defined(__linux) || defined(ultrix) || defined(AIX) ||\
+-	defined(HPUX) || defined(CONVEX) || defined(IRIX)
++# if (BSD >= 199103) || defined(__linux__) || defined(__GNU__) || defined(ultrix) ||\
++        defined(AIX) ||\ defined(HPUX) || defined(CONVEX) || defined(IRIX) || defined(__GLIBC__)
+ #  define POSIX
+ # endif
+ #endif
+@@ -76,17 +76,17 @@
+ 
+ /*****************************************************************/
+ 
+-#if !defined(BSD) && !defined(HPUX) && !defined(CONVEX) && !defined(__linux)
++#if !defined(BSD) && !defined(HPUX) && !defined(CONVEX) && !defined(__linux__) && !defined(__GNU__)
+ # define NEED_VFORK
+ #endif
+ 
+-#if (!defined(BSD) || (BSD < 198902)) && !defined(__linux) && \
+-	!defined(IRIX) && !defined(NeXT) && !defined(HPUX)
++#if (!defined(BSD) || (BSD < 198902)) && !defined(__linux__) && \
++	!defined(IRIX) && !defined(NeXT) && !defined(HPUX) && !defined(__GNU__) && !defined(__GLIBC__)
+ # define NEED_STRCASECMP
+ #endif
+ 
+-#if (!defined(BSD) || (BSD < 198911)) && !defined(__linux) &&\
+-	!defined(IRIX) && !defined(UNICOS) && !defined(HPUX)
++#if (!defined(BSD) || (BSD < 198911)) && !defined(__linux__) &&\
++	!defined(IRIX) && !defined(UNICOS) && !defined(HPUX) && !defined(__GNU__) && !defined(__GLIBC__)
+ # define NEED_STRDUP
+ #endif
+ 
+@@ -102,19 +102,19 @@
+ # define NEED_SETSID
+ #endif
+ 
+-#if (defined(POSIX) && !defined(BSD)) && !defined(__linux)
++#if (defined(POSIX) && !defined(BSD)) && !defined(__linux__) && !defined(__GNU__) && !defined(__GLIBC__)
+ # define NEED_GETDTABLESIZE
+ #endif
+ 
+-#if (BSD >= 199103)
++#if (BSD >= 199103) || defined(__linux)
+ # define HAVE_SAVED_UIDS
+ #endif
+ 
+-#if !defined(ATT) && !defined(__linux) && !defined(IRIX) && !defined(UNICOS)
++#if !defined(ATT) && !defined(__linux__) && !defined(__GNU__) && !defined(IRIX) && !defined(UNICOS) && !defined(__GLIBC__)
+ # define USE_SIGCHLD
+ #endif
+ 
+-#if !defined(AIX) && !defined(UNICOS)
++#if !defined(AIX) && !defined(UNICOS) && !defined(DEBIAN)
+ # define SYS_TIME_H 1
+ #else
+ # define SYS_TIME_H 0
+Index: patched/pathnames.h
+===================================================================
+--- patched.orig/pathnames.h	2010-05-06 18:18:16.273435823 +0200
++++ patched/pathnames.h	2010-05-06 18:18:22.673435429 +0200
+@@ -19,7 +19,7 @@
+  * $Id: pathnames.h,v 1.3 1994/01/15 20:43:43 vixie Exp $
+  */
+ 
+-#if (defined(BSD)) && (BSD >= 199103) || defined(__linux) || defined(AIX)
++#if (defined(BSD)) && (BSD >= 199103) || defined(__linux__) || defined(AIX) || defined(__GNU__) || defined(__GLIBC__)
+ # include <paths.h>
+ #endif /*BSD*/
+ 
diff --git a/debian/patches/fixes/handle-escapes-in-commands b/debian/patches/fixes/handle-escapes-in-commands
new file mode 100644
index 0000000..3cfd044
--- /dev/null
+++ b/debian/patches/fixes/handle-escapes-in-commands
@@ -0,0 +1,48 @@
+Subject: Properly process escapes in commands
+Last-Update: 2010-04-11
+
+Certain escape sequence are not handled correctly.
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:31.634435779 +0200
++++ patched/do_command.c	2010-05-06 18:18:33.012435990 +0200
+@@ -138,13 +138,21 @@
+ 	 * command, and subsequent characters are the additional input to
+ 	 * the command.  Subsequent %'s will be transformed into newlines,
+ 	 * but that happens later.
++	 *
++	 * If there are escaped %'s, remove the escape character.
+ 	 */
+ 	/*local*/{
+ 		register int escaped = FALSE;
+ 		register int ch;
++		register char *p;
+ 
+-		for (input_data = e->cmd;  ch = *input_data;  input_data++) {
++		for (input_data = p = e->cmd; (ch = *input_data);
++		    input_data++, p++) {
++			if (p != input_data)
++				*p = ch;
+ 			if (escaped) {
++				if (ch == '%' || ch == '\\')
++					*--p = ch;
+ 				escaped = FALSE;
+ 				continue;
+ 			}
+@@ -157,6 +165,7 @@
+ 				break;
+ 			}
+ 		}
++		*p = '\0';
+ 	}
+ 
+ 	/* fork again, this time so we can exec the user's command.
+@@ -317,7 +326,7 @@
+ 		 *	%  -> \n
+ 		 *	\x -> \x	for all x != %
+ 		 */
+-		while (ch = *input_data++) {
++		while ((ch = *input_data++) != '\0') {
+ 			if (escaped) {
+ 				if (ch != '%')
+ 					putc('\\', out);
diff --git a/debian/patches/fixes/limit-args-for-commands b/debian/patches/fixes/limit-args-for-commands
new file mode 100644
index 0000000..e939648
--- /dev/null
+++ b/debian/patches/fixes/limit-args-for-commands
@@ -0,0 +1,35 @@
+Subject: Limit the maximum number of arguments to commands
+Last-Update: 2010-04-11
+Index: patched/popen.c
+===================================================================
+--- patched.orig/popen.c	2010-05-06 18:18:24.458435579 +0200
++++ patched/popen.c	2010-05-06 18:18:25.171561124 +0200
+@@ -36,6 +36,7 @@
+ #endif
+ 
+ 
++#define MAX_ARGS 100
+ #define WANT_GLOBBING 0
+ 
+ /*
+@@ -54,7 +55,7 @@
+ 	FILE *iop;
+ 	int argc, pdes[2];
+ 	PID_T pid;
+-	char *argv[100];
++	char *argv[MAX_ARGS + 1];
+ #if WANT_GLOBBING
+ 	char **pop, *vv[2];
+ 	int gargc;
+@@ -76,9 +77,10 @@
+ 		return(NULL);
+ 
+ 	/* break up string into pieces */
+-	for (argc = 0, cp = program;; cp = NULL)
++	for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL)
+ 		if (!(argv[argc++] = strtok(cp, " \t\n")))
+ 			break;
++    argv[MAX_ARGS] = NULL;
+ 
+ #if WANT_GLOBBING
+ 	/* glob each piece */
diff --git a/debian/patches/fixes/make-it-buildable b/debian/patches/fixes/make-it-buildable
new file mode 100644
index 0000000..8490c00
--- /dev/null
+++ b/debian/patches/fixes/make-it-buildable
@@ -0,0 +1,66 @@
+Subject: Make source buildable on Debian
+
+The fixes/* directory shouldn't contain any Debian-specific fixes, only common
+ones. Unfortunately, this approach fails without patching the Makefile, simply
+because the original source (cron 3.0) was release in 1993, and certain things
+such as POSIX are considered a "feature".
+Index: patched/Makefile
+===================================================================
+--- patched.orig/Makefile	2010-05-06 18:18:16.350561149 +0200
++++ patched/Makefile	2010-05-06 18:18:21.821436206 +0200
+@@ -57,28 +57,32 @@
+ #<<need getopt()>>
+ LIBS		=
+ #<<optimize or debug?>>
+-#OPTIM		=	-O
+-OPTIM		=	-g
++OPTIM		=	-O2
++#OPTIM		=	-g
+ #<<ATT or BSD or POSIX?>>
+ # (ATT untested)
+ #COMPAT		=	-DATT
+ #(BSD is only needed if <sys/params.h> does not define it, as on ULTRIX)
+ #COMPAT		=	-DBSD
+ # (POSIX)
+-#COMPAT		=	-DPOSIX
++COMPAT		=	-DPOSIX
+ #<<lint flags of choice?>>
+ LINTFLAGS	=	-hbxa $(INCLUDE) $(COMPAT) $(DEBUGGING)
+ #<<want to use a nonstandard CC?>>
+ #CC		=	vcc
+ #<<manifest defines>>
+ DEFS		=
++# The -DUSE_SIGCHLD is needed for the Alpha port
++DEFS = -DDEBIAN -DUSE_SIGCHLD
+ #(SGI IRIX systems need this)
+ #DEFS		=	-D_BSD_SIGNALS -Dconst=
+ #<<the name of the BSD-like install program>>
+ #INSTALL = installbsd
+-INSTALL = install
++INSTALL = install -s
+ #<<any special load flags>>
+-LDFLAGS		=
++# LDFLAGS		=	-s
++# Let install do the strip
++
+ #################################### end configurable stuff
+ 
+ SHELL		=	/bin/sh
+@@ -113,13 +117,14 @@
+ 			$(CC) $(LDFLAGS) -o crontab $(CRONTAB_OBJ) $(LIBS)
+ 
+ install		:	all
+-			$(INSTALL) -c -m  111 -o root -s cron    $(DESTSBIN)/
+-			$(INSTALL) -c -m 4111 -o root -s crontab $(DESTBIN)/
++			$(INSTALL) -c -m  755 -o root cron    $(DESTSBIN)/
++			$(INSTALL) -c -m 4755 -o root crontab $(DESTBIN)/
+ 			sh putman.sh crontab.1 $(DESTMAN)
+ 			sh putman.sh cron.8    $(DESTMAN)
+ 			sh putman.sh crontab.5 $(DESTMAN)
+ 
+-clean		:;	rm -f *.o cron crontab a.out core tags *~ #*
++clean		:
++			rm -f *.o cron crontab a.out core tags *~ #*
+ 
+ kit		:	$(SHAR_SOURCE)
+ 			makekit -m -s99k $(SHAR_SOURCE)
diff --git a/debian/patches/fixes/memory-management-issues b/debian/patches/fixes/memory-management-issues
new file mode 100644
index 0000000..45bc9b7
--- /dev/null
+++ b/debian/patches/fixes/memory-management-issues
@@ -0,0 +1,300 @@
+Subject: Correct memory management issues
+Last-Update: 2010-04-11
+
+Three kinds of fixes:
+  1) Do not just assume that malloc() et al. return successfully
+  2) Don't forget to free memory 
+  3) Function implicitly relying on allocation have to test for successful
+     return, too. These are usually env_init(), etc. They are included here
+     because of the close way they are all tied together.
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/compat.c
+===================================================================
+--- patched.orig/compat.c	2010-05-06 18:18:24.437560974 +0200
++++ patched/compat.c	2010-05-06 18:18:27.645727100 +0200
+@@ -53,7 +53,10 @@
+ {
+ 	char	*temp;
+ 
+-	temp = malloc(strlen(str) + 1);
++	if ((temp = malloc(strlen(str) + 1)) == NULL) {
++		errno = ENOMEM;
++		return NULL;
++	}
+ 	(void) strcpy(temp, str);
+ 	return temp;
+ }
+Index: patched/env.c
+===================================================================
+--- patched.orig/env.c	2010-05-06 18:18:24.458435579 +0200
++++ patched/env.c	2010-05-06 18:18:27.645727100 +0200
+@@ -28,7 +28,8 @@
+ {
+ 	register char	**p = (char **) malloc(sizeof(char **));
+ 
+-	p[0] = NULL;
++	if (p)
++		p[0] = NULL;
+ 	return (p);
+ }
+ 
+@@ -58,8 +59,18 @@
+ 	for (count = 0;  envp[count] != NULL;  count++)
+ 		;
+ 	p = (char **) malloc((count+1) * sizeof(char *));  /* 1 for the NULL */
++	if (p == NULL) {
++		errno = ENOMEM;
++		return NULL;
++	}
+ 	for (i = 0;  i < count;  i++)
+-		p[i] = strdup(envp[i]);
++		if ((p[i] = strdup(envp[i])) == NULL) {
++			while (--i >= 0)
++				(void) free(p[i]);
++			free(p);
++			errno = ENOMEM;
++			return NULL;
++		}
+ 	p[count] = NULL;
+ 	return (p);
+ }
+@@ -90,7 +101,11 @@
+ 		 * save our new one there, and return the existing array.
+ 		 */
+ 		free(envp[found]);
+-		envp[found] = strdup(envstr);
++		if ((envp[found] = strdup(envstr)) == NULL) {
++			envp[found] = "";
++			errno = ENOMEM;
++			return NULL;
++		}
+ 		return (envp);
+ 	}
+ 
+@@ -101,8 +116,15 @@
+ 	 */
+ 	p = (char **) realloc((void *) envp,
+ 			      (unsigned) ((count+1) * sizeof(char **)));
++	if (p == NULL) 	{
++		errno = ENOMEM;
++		return NULL;
++	}
+ 	p[count] = p[count-1];
+-	p[count-1] = strdup(envstr);
++	if ((p[count-1] = strdup(envstr)) == NULL) {
++		errno = ENOMEM;
++		return NULL;
++	}
+ 	return (p);
+ }
+ 
+Index: patched/job.c
+===================================================================
+--- patched.orig/job.c	2010-05-06 18:18:15.622435978 +0200
++++ patched/job.c	2010-05-06 18:18:27.645727100 +0200
+@@ -45,7 +45,8 @@
+ 		if (j->e == e && j->u == u) { return; }
+ 
+ 	/* build a job queue element */
+-	j = (job*)malloc(sizeof(job));
++	if ((j = (job*)malloc(sizeof(job))) == NULL)
++		return;
+ 	j->next = (job*) NULL;
+ 	j->e = e;
+ 	j->u = u;
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:24.458435579 +0200
++++ patched/misc.c	2010-05-06 18:18:27.646435759 +0200
+@@ -479,7 +479,12 @@
+ 		     + strlen(event)
+ 		     + strlen(detail)
+ 		     + MAX_TEMPSTR);
+-
++	if (msg == NULL) {
++	    /* damn, out of mem and we did not test that before... */
++	    fprintf(stderr, "%s: Run OUT OF MEMORY while %s\n",
++		    ProgramName, __FUNCTION__);
++	    return;
++	}
+ 	if (LogFD < OK) {
+ 		LogFD = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600);
+ 		if (LogFD < OK) {
+@@ -622,7 +627,8 @@
+ {
+ 	register char *dst = malloc(len*4 + 1);
+ 
+-	mkprint(dst, src, len);
++	if (dst)
++		mkprint(dst, src, len);
+ 
+ 	return dst;
+ }
+Index: patched/user.c
+===================================================================
+--- patched.orig/user.c	2010-05-06 18:18:25.803561007 +0200
++++ patched/user.c	2010-05-06 18:18:27.646435759 +0200
+@@ -52,7 +52,7 @@
+ 	user	*u;
+ 	entry	*e;
+ 	int	status;
+-	char	**envp;
++	char	**envp = NULL, **tenvp;
+ 
+ 	if (!(file = fdopen(crontab_fd, "r"))) {
+ 		perror("fdopen on crontab_fd in load_user");
+@@ -63,14 +63,25 @@
+ 
+ 	/* file is open.  build user entry, then read the crontab file.
+ 	 */
+-	u = (user *) malloc(sizeof(user));
+-	u->name = strdup(name);
++	if ((u = (user *) malloc(sizeof(user))) == NULL) {
++		errno = ENOMEM;
++		return NULL;
++	}
++	if ((u->name = strdup(name)) == NULL) {
++		free(u);
++		errno = ENOMEM;
++		return NULL;
++	}
+ 	u->crontab = NULL;
+ 
+ 	/* 
+ 	 * init environment.  this will be copied/augmented for each entry.
+ 	 */
+-	envp = env_init();
++	if ((envp = env_init()) == NULL) {
++		free(u->name);
++		free(u);
++		return NULL;
++	}
+ 
+ 	/*
+ 	 * load the crontab
+@@ -98,7 +109,13 @@
+ 			}
+ 			break;
+ 		case TRUE:
+-			envp = env_set(envp, envstr);
++			if ((tenvp = env_set(envp, envstr))) {
++				envp = tenvp;
++			} else {
++				free_user(u);
++				u = NULL;
++				goto done;
++			}
+ 			break;
+ 		}
+ 	} while (status >= OK);
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:27.017560712 +0200
++++ patched/entry.c	2010-05-06 18:18:27.646435759 +0200
+@@ -91,6 +91,7 @@
+ 	int	ch;
+ 	char	cmd[MAX_COMMAND];
+ 	char	envstr[MAX_ENVSTR];
++	char	**tenvp;
+ 
+ 	Debug(DPARS, ("load_entry()...about to eat comments\n"))
+ 
+@@ -250,24 +251,52 @@
+ 	/* copy and fix up environment.  some variables are just defaults and
+ 	 * others are overrides.
+ 	 */
+-	e->envp = env_copy(envp);
++	if ((e->envp = env_copy(envp)) == NULL) {
++		ecode = e_none;
++		goto eof;
++	}
+ 	if (!env_get("SHELL", e->envp)) {
+ 		sprintf(envstr, "SHELL=%s", _PATH_BSHELL);
+-		e->envp = env_set(e->envp, envstr);
++		if ((tenvp = env_set(e->envp, envstr))) {
++			e->envp = tenvp;
++		} else {
++			ecode = e_none;
++			goto eof;
++		}
+ 	}
+ 	if (!env_get("HOME", e->envp)) {
+ 		sprintf(envstr, "HOME=%s", pw->pw_dir);
+-		e->envp = env_set(e->envp, envstr);
++		if ((tenvp = env_set(e->envp, envstr))) {
++			e->envp = tenvp;
++		} else {
++			ecode = e_none;
++			goto eof;
++		}
+ 	}
+ 	if (!env_get("PATH", e->envp)) {
+ 		sprintf(envstr, "PATH=%s", _PATH_DEFPATH);
+-		e->envp = env_set(e->envp, envstr);
++		if ((tenvp = env_set(e->envp, envstr))) {
++			e->envp = tenvp;
++		} else {
++			ecode = e_none;
++			goto eof;
++		}
++	}
++	snprintf(envstr, MAX_ENVSTR, "%s=%s", "LOGNAME", pw->pw_name);
++	if ((tenvp = env_set(e->envp, envstr))) {
++		e->envp = tenvp;
++	} else {
++		ecode = e_none;
++		goto eof;
+ 	}
+-	sprintf(envstr, "%s=%s", "LOGNAME", pw->pw_name);
+-	e->envp = env_set(e->envp, envstr);
+ #if defined(BSD)
+ 	sprintf(envstr, "%s=%s", "USER", pw->pw_name);
+-	e->envp = env_set(e->envp, envstr);
++	if ((tenvp = env_set(e->envp, envstr))) {
++		e->envp = tenvp;
++	} else {
++		ecode = e_none;
++		goto eof;
++	}
+ #endif
+ 
+ 	Debug(DPARS, ("load_entry()...about to parse command\n"))
+@@ -292,7 +321,10 @@
+ 
+ 	/* got the command in the 'cmd' string; save it in *e.
+ 	 */
+-	e->cmd = strdup(cmd);
++	if ((e->cmd = strdup(cmd)) == NULL) {
++		ecode = e_none;
++		goto eof;
++	}
+ 
+ 	Debug(DPARS, ("load_entry()...returning successfully\n"))
+ 
+@@ -301,6 +333,10 @@
+ 	return e;
+ 
+  eof:
++	if (e->envp)
++		env_free(e->envp);
++	if (e->cmd)
++		free(e->cmd);
+ 	free(e);
+ 	if (ecode != e_none && error_func)
+ 		(*error_func)(ecodes[(int)ecode]);
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:24.437560974 +0200
++++ patched/crontab.c	2010-05-06 18:18:27.646435759 +0200
+@@ -497,6 +497,10 @@
+ 	time_t	now = time(NULL);
+ 	char	**envp = env_init();
+ 
++	if (envp == NULL) {
++		fprintf(stderr, "%s: Cannot allocate memory.\n", ProgramName);
++		return (-2);
++	}
+ 	(void) sprintf(n, "tmp.%d", Pid);
+ 	(void) sprintf(tn, CRON_TAB(n));
+ 	if (!(tmp = fopen(tn, "w+"))) {
diff --git a/debian/patches/fixes/missing-or-broken-defs-and-decls b/debian/patches/fixes/missing-or-broken-defs-and-decls
new file mode 100644
index 0000000..13e6a6d
--- /dev/null
+++ b/debian/patches/fixes/missing-or-broken-defs-and-decls
@@ -0,0 +1,27 @@
+Subject: Add or fix definitions and declarations
+Last-Update: 2010-04-11
+
+Add or fix definitions and declarations in headers which are NOT associated
+with a particular feature but considered either an omission, a bug or simply
+outdated.
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:16.151435957 +0200
++++ patched/cron.h	2010-05-06 18:18:23.394435942 +0200
+@@ -105,7 +105,7 @@
+ 
+ #if DEBUGGING
+ # define Debug(mask, message) \
+-			if ( (DebugFlags & (mask) ) == (mask) ) \
++			if ( (DebugFlags & (mask) )  ) \
+ 				printf message;
+ #else /* !DEBUGGING */
+ # define Debug(mask, message) \
+@@ -205,6 +205,7 @@
+ 		get_char __P((FILE *)),
+ 		get_string __P((char *, int, FILE *, char *)),
+ 		swap_uids __P((void)),
++		swap_uids_back __P((void)),
+ 		load_env __P((char *, FILE *)),
+ 		cron_pclose __P((FILE *)),
+ 		strcmp_until __P((char *, char *, int)),
diff --git a/debian/patches/fixes/parse-envvars-correctly b/debian/patches/fixes/parse-envvars-correctly
new file mode 100644
index 0000000..6600cc9
--- /dev/null
+++ b/debian/patches/fixes/parse-envvars-correctly
@@ -0,0 +1,156 @@
+Subject: Correctly pars environment variables in crontab
+Origin: ftp://ftp.isc.org/isc/cron/cron_4.1.shar
+Last-Update: 2010-04-22
+
+The parsing code for environment variables in crontabs is broken. This patch
+backports the parsing code from cron-4.1.
+Index: patched/env.c
+===================================================================
+--- patched.orig/env.c	2010-04-22 20:15:54.192691828 +0200
++++ patched/env.c	2010-04-22 20:23:25.871565946 +0200
+@@ -128,6 +128,17 @@
+ 	return (p);
+ }
+ 
++/* The following states are used by load_env(), traversed in order: */
++enum env_state {
++	NAMEI,		/* First char of NAME, may be quote */
++	NAME,		/* Subsequent chars of NAME */
++	EQ1,		/* After end of name, looking for '=' sign */
++	EQ2,		/* After '=', skipping whitespace */
++	VALUEI,		/* First char of VALUE, may be quote */
++	VALUE,		/* Subsequent chars of VALUE */
++	FINI,		/* All done, skipping trailing whitespace */
++	ERROR,		/* Error */
++};
+ 
+ /* return	ERR = end of file
+  *		FALSE = not an env setting (file was repositioned)
+@@ -140,8 +151,9 @@
+ {
+ 	long	filepos;
+ 	int	fileline;
+-	char	name[MAX_ENVSTR], val[MAX_ENVSTR];
+-	int	fields;
++	enum env_state state;
++	char name[MAX_ENVSTR], val[MAX_ENVSTR];
++	char quotechar, *c, *str;
+ 
+ 	filepos = ftell(f);
+ 	fileline = LineNumber;
+@@ -153,37 +165,93 @@
+ 
+ 	Debug(DPARS, ("load_env, read <%s>\n", envstr))
+ 
+-	name[0] = val[0] = '\0';
+-	fields = sscanf(envstr, "%[^ =] = %[^\n#]", name, val);
+-	if (fields != 2) {
+-		Debug(DPARS, ("load_env, not 2 fields (%d)\n", fields))
++	bzero(name, sizeof name);
++	bzero(val, sizeof val);
++	str = name;
++	state = NAMEI;
++	quotechar = '\0';
++	c = envstr;
++	while (state != ERROR && *c) {
++		switch (state) {
++		case NAMEI:
++		case VALUEI:
++			if (*c == '\'' || *c == '"')
++				quotechar = *c++;
++			state++;
++			/* FALLTHROUGH */
++		case NAME:
++		case VALUE:
++			if (quotechar) {
++				if (*c == quotechar) {
++					state++;
++					c++;
++					break;
++				}
++				if (state == NAME && *c == '=') {
++					state = ERROR;
++					break;
++				}
++			} else {
++				if (state == NAME) {
++					if (isspace((unsigned char)*c)) {
++						c++;
++						state++;
++						break;
++					}
++					if (*c == '=') {
++						state++;
++						break;
++					}
++				}
++			}
++			*str++ = *c++;
++			break;
++
++		case EQ1:
++			if (*c == '=') {
++				state++;
++				str = val;
++				quotechar = '\0';
++			} else {
++				if (!isspace((unsigned char)*c))
++					state = ERROR;
++			}
++			c++;
++			break;
++
++		case EQ2:
++		case FINI:
++			if (isspace((unsigned char)*c))
++				c++;
++			else
++				state++;
++			break;
++
++		default:
++			abort();
++		}
++	}
++	if (state != FINI && !(state == VALUE && !quotechar)) {
++		Debug(DPARS, ("load_env, not an env var, state = %d\n", state))
+ 		fseek(f, filepos, 0);
+ 		Set_LineNum(fileline);
+ 		return (FALSE);
+ 	}
++	if (state == VALUE) {
++		/* End of unquoted value: trim trailing whitespace */
++		c = val + strlen(val);
++		while (c > val && isspace((unsigned char)c[-1]))
++			*(--c) = '\0';
++	}
+ 
+-	/* 2 fields from scanf; looks like an env setting
+-	 */
++	/* 2 fields from parser; looks like an env setting */
+ 
+ 	/*
+-	 * process value string
++	 * This can't overflow because get_string() limited the size of the
++	 * name and val fields.  Still, it doesn't hurt to be careful...
+ 	 */
+-	/*local*/{
+-		int	len = strdtb(val);
+-
+-		if (len >= 2) {
+-			if (val[0] == '\'' || val[0] == '"') {
+-				if (val[len-1] == val[0]) {
+-					val[len-1] = '\0';
+-					(void) strcpy(val, val+1);
+-				}
+-			}
+-		}
+-	}
+-
+-	if (strlen(name) + 1 + strlen(val) >= MAX_ENVSTR-1)
++	if (!glue_strings(envstr, MAX_ENVSTR, name, val, '='))
+ 		return (FALSE);
+-	(void) sprintf(envstr, "%s=%s", name, val);
+ 	Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
+ 	return (TRUE);
+ }
diff --git a/debian/patches/fixes/prevent-tmpfiles-attack b/debian/patches/fixes/prevent-tmpfiles-attack
new file mode 100644
index 0000000..12c9547
--- /dev/null
+++ b/debian/patches/fixes/prevent-tmpfiles-attack
@@ -0,0 +1,113 @@
+Subject: Prevent symlink attack
+Last-Update: 2010-10-11
+Author: Daniel Jacobowitz, Steeve Greenland <stevegr at debian.org>
+
+Prevent symlink attack by ensuring we open a regular file. Also, add some
+additional security measures.
+
+IMPORTANT NOTE for Debian: most of this patch will get replaced by a
+Debian-specific solution (see features/*).
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:39.119435834 +0200
++++ patched/crontab.c	2010-05-06 18:18:39.796561016 +0200
+@@ -144,6 +144,7 @@
+ 	char	*argv[];
+ {
+ 	int		argch;
++	struct stat	statbuf;
+ 
+ 	if (!(pw = getpwuid(getuid()))) {
+ 		fprintf(stderr, "%s: your UID isn't in the passwd file.\n",
+@@ -245,6 +246,15 @@
+ 				perror(Filename);
+ 				exit(ERROR_EXIT);
+ 			}
++			/* Make sure we opened a normal file. */
++			if (fstat(fileno(NewCrontab), &statbuf) < 0) {
++				perror("fstat");
++				exit(ERROR_EXIT);
++			}
++			if (!S_ISREG(statbuf.st_mode)) {
++				fprintf(stderr, "%s: Not a regular file.\n", Filename);
++				exit(ERROR_EXIT);
++			}
+ 			if (swap_uids_back() < OK) {
+ 				perror("swapping uids back");
+ 				exit(ERROR_EXIT);
+@@ -520,7 +530,14 @@
+  done:
+ 	log_it(RealUser, Pid, "END EDIT", User);
+ }
+-	
++
++static char tn[MAX_FNAME];
++
++static void sig_handler(int x)
++{
++	unlink(tn);
++	exit(1);
++}	
+ 
+ /* returns	0	on success
+  *		-1	on syntax error
+@@ -528,23 +545,42 @@
+  */
+ static int
+ replace_cmd() {
+-	char	n[MAX_FNAME], envstr[MAX_ENVSTR], tn[MAX_FNAME];
++	char	n[MAX_FNAME], envstr[MAX_ENVSTR];
+ 	FILE	*tmp;
+-	int	ch, eof;
++	int	ch, eof, fd;
+ 	entry	*e;
+ 	time_t	now = time(NULL);
+ 	char	**envp = env_init();
++	mode_t	um;
+ 
+ 	if (envp == NULL) {
+ 		fprintf(stderr, "%s: Cannot allocate memory.\n", ProgramName);
+ 		return (-2);
+ 	}
+-	(void) snprintf(n, MAX_FNAME, "tmp.%d", Pid);
+-	(void) snprintf(tn, MAX_FNAME, CRON_TAB(n));
+-	if (!(tmp = fopen(tn, "w+"))) {
+-		perror(tn);
++
++
++	/* Assumes Linux-style signal handlers (takes int, returns void) */
++	/* Signal handlers, to ensure we do not leave temp files in the
++	   spool dir.  We don't remove these on exiting this function;
++	   but that's OK, we exit immediately afterwards anyway. */
++	signal(SIGHUP, sig_handler);
++	signal(SIGINT, sig_handler);
++	signal(SIGQUIT, sig_handler);
++	signal(SIGTSTP, SIG_IGN);
++
++	(void) snprintf(tn, MAX_FNAME, CRON_TAB("tmp.XXXXXX"));
++	um = umask(077);
++	fd = mkstemp(tn);
++	if (fd < 0) {
++                fprintf(stderr, "%s/: mkstemp: %s\n", CRONDIR, strerror(errno));
++		return(-2);
++	}
++	tmp = fdopen(fd, "w+");
++	if (!tmp) {
++                fprintf(stderr, "%s/: fdopen: %s\n", CRONDIR, strerror(errno));
+ 		return (-2);
+ 	}
++	(void) umask(um);
+ 
+ 	/* write a signature at the top of the file.
+ 	 *
+@@ -564,8 +600,8 @@
+ 	fflush(tmp);  rewind(tmp);
+ 
+ 	if (ferror(tmp)) {
+-		fprintf(stderr, "%s: %s: %s\n",
+-			ProgramName, tn, strerror(errno));
++		fprintf(stderr, "%s: error while writing new crontab to %s\n",
++			ProgramName, tn);
+ 		fclose(tmp);  unlink(tn);
+ 		return (-2);
+ 	}
diff --git a/debian/patches/fixes/proper-handling-of-stdstreams b/debian/patches/fixes/proper-handling-of-stdstreams
new file mode 100644
index 0000000..e6cb7f1
--- /dev/null
+++ b/debian/patches/fixes/proper-handling-of-stdstreams
@@ -0,0 +1,68 @@
+Subject: Proper handling of standard streams
+Last-Update: 2010-04-11
+
+Fixes related to stdin, stdout, stderr WRT to daemonizing, etc.
+
+Debian-Bug: http://bugs.debian.org/295589
+Debian-Bug: http://bugs.debian.org/37189
+Debian-Bug: http://bugs.debian.org/23231
+Debian-Bug: http://bugs.debian.org/30653
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:22.672435408 +0200
++++ patched/cron.c	2010-05-06 18:18:29.548561115 +0200
+@@ -31,6 +31,8 @@
+ # include <time.h>
+ #endif
+ 
++#include <sys/types.h>
++#include <fcntl.h>
+ 
+ static	void	usage __P((void)),
+ 		run_reboot_jobs __P((cron_db *)),
+@@ -74,6 +76,13 @@
+ #endif
+ 	(void) signal(SIGHUP, sighup_handler);
+ 
++        /* Reopen stdin in case some idiot closed it before starting
++           us - it will only be closed, but not having it open here
++           screws up other things that will be opened */
++        if (fdopen(0,"r") == NULL) {
++            (void) open("dev/null", 0);
++        }
++
+ 	acquire_daemonlock(0);
+ 	set_cron_uid();
+ 	set_cron_cwd();
+@@ -100,6 +109,9 @@
+ 			/* child process */
+ 			log_it("CRON",getpid(),"STARTUP","fork ok");
+ 			(void) setsid();
++			freopen("/dev/null", "r", stdin);
++			freopen("/dev/null", "w", stdout);
++			freopen("/dev/null", "w", stderr);
+ 			break;
+ 		default:
+ 			/* parent process should just die */
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:28.844435899 +0200
++++ patched/do_command.c	2010-05-06 18:18:29.548561115 +0200
+@@ -189,9 +189,12 @@
+ 		/* grandchild process.  make std{in,out} be the ends of
+ 		 * pipes opened by our daddy; make stderr go to stdout.
+ 		 */
+-		close(STDIN);	dup2(stdin_pipe[READ_PIPE], STDIN);
+-		close(STDOUT);	dup2(stdout_pipe[WRITE_PIPE], STDOUT);
+-		close(STDERR);	dup2(STDOUT, STDERR);
++		/* Closes are unnecessary -- let dup2() do it */
++
++		  /* close(STDIN) */; dup2(stdin_pipe[READ_PIPE], STDIN);
++		  /* close(STDOUT) */;  dup2(stdout_pipe[WRITE_PIPE], STDOUT);
++		  /* close(STDERR)*/; dup2(STDOUT, STDERR);
++
+ 
+ 		/* close the pipes we just dup'ed.  The resources will remain.
+ 		 */
diff --git a/debian/patches/fixes/properly-wait-for-spawned-editor b/debian/patches/fixes/properly-wait-for-spawned-editor
new file mode 100644
index 0000000..5e4d937
--- /dev/null
+++ b/debian/patches/fixes/properly-wait-for-spawned-editor
@@ -0,0 +1,93 @@
+Subject: Properly wait for spawned editor to return
+Last-Update: 2010-10-11
+
+Clean up the process of waiting for the spawned editor to return.
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:37.766435855 +0200
++++ patched/crontab.c	2010-05-06 18:18:39.119435834 +0200
+@@ -31,6 +31,7 @@
+ #include "cron.h"
+ #include <errno.h>
+ #include <fcntl.h>
++#include <signal.h>
+ #include <sys/file.h>
+ #include <sys/stat.h>
+ #ifdef USE_UTIMES
+@@ -418,6 +419,13 @@
+ 	 * close and reopen the file around the edit.
+ 	 */
+ 
++	/* Turn off signals. */
++	(void)signal(SIGHUP, SIG_IGN);
++	(void)signal(SIGINT, SIG_IGN);
++	(void)signal(SIGQUIT, SIG_IGN);
++
++
++
+ 	switch (pid = fork()) {
+ 	case -1:
+ 		perror("fork");
+@@ -448,33 +456,35 @@
+ 	}
+ 
+ 	/* parent */
+-	xpid = wait(&waiter);
+-	if (xpid != pid) {
+-		fprintf(stderr, "%s: wrong PID (%d != %d) from \"%s\"\n",
+-			ProgramName, xpid, pid, editor);
+-		goto fatal;
+-	}
+-	if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
+-		fprintf(stderr, "%s: \"%s\" exited with status %d\n",
+-			ProgramName, editor, WEXITSTATUS(waiter));
+-		goto fatal;
+-	}
+-	if (WIFSIGNALED(waiter)) {
+-		fprintf(stderr,
+-			"%s: \"%s\" killed; signal %d (%score dumped)\n",
+-			ProgramName, editor, WTERMSIG(waiter),
+-			WCOREDUMP(waiter) ?"" :"no ");
+-		goto fatal;
+-	}
+-	if (fstat(t, &statbuf) < 0) {
+-		perror("fstat");
+-		goto fatal;
+-	}
+-	if (mtime == statbuf.st_mtime) {
+-		fprintf(stderr, "%s: no changes made to crontab\n",
+-			ProgramName);
+-		goto remove;
+-	}
++	while (1) {
++		xpid = waitpid(pid, &waiter, WUNTRACED);
++		if (xpid == -1) {
++			fprintf(stderr, "%s: waitpid() failed waiting for PID %d from \"%s\": %s\n",
++				ProgramName, pid, editor, strerror(errno));
++		} else if (xpid != pid) {
++			fprintf(stderr, "%s: wrong PID (%d != %d) from \"%s\"\n",
++				ProgramName, xpid, pid, editor);
++			goto fatal;
++		} else if (WIFSTOPPED(waiter)) {
++		        /* raise(WSTOPSIG(waiter)); Not needed and breaks in job control shell*/
++		} else if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
++			fprintf(stderr, "%s: \"%s\" exited with status %d\n",
++				ProgramName, editor, WEXITSTATUS(waiter));
++			goto fatal;
++		} else if (WIFSIGNALED(waiter)) {
++			fprintf(stderr,
++				"%s: \"%s\" killed; signal %d (%score dumped)\n",
++				ProgramName, editor, WTERMSIG(waiter),
++				WCOREDUMP(waiter) ?"" :"no ");
++			goto fatal;
++		} else
++			break;
++	}
++	(void)signal(SIGHUP, SIG_DFL);
++	(void)signal(SIGINT, SIG_DFL);
++	(void)signal(SIGQUIT, SIG_DFL);
++	(void)signal(SIGTSTP, SIG_DFL);
++
+ 	fprintf(stderr, "%s: installing new crontab\n", ProgramName);
+ 	switch (replace_cmd()) {
+ 	case 0:
diff --git a/debian/patches/fixes/protect-against-buffer-overflows b/debian/patches/fixes/protect-against-buffer-overflows
new file mode 100644
index 0000000..b0d208f
--- /dev/null
+++ b/debian/patches/fixes/protect-against-buffer-overflows
@@ -0,0 +1,387 @@
+Subject: Protect against buffer overflows
+Origin: vendor, Redhat vixie-cron-3.0.1-24.src.rpm
+Last-Update: 2010-04-11
+
+Use safe string functions instead of unsafe ones; protect buffer boundaries,
+etc.
+
+Bug-Debian: http://bugs.debian.org/89040
+Bug-Debian: http://bugs.debian.org/62268
+Bug-Debian: http://bugs.debian.org/26705
+Bug-Debian: http://bugs.debian.org/26749
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/compat.c
+===================================================================
+--- patched.orig/compat.c	2010-05-06 18:18:27.645727100 +0200
++++ patched/compat.c	2010-05-06 18:18:28.215435834 +0200
+@@ -76,7 +76,7 @@
+ 		return sys_errlist[error];
+ 	}
+ 
+-	sprintf(buf, "Unknown error: %d", error);
++	snprintf(buf, 32, "Unknown error: %d", error);
+ 	return buf;
+ }
+ #endif
+@@ -221,16 +221,18 @@
+ 	int overwrite;
+ {
+ 	char *tmp;
++ 	int tmp_size;
+ 
+ 	if (overwrite && getenv(name))
+ 		return -1;
+ 
+-	if (!(tmp = malloc(strlen(name) + strlen(value) + 2))) {
++	tmp_size = strlen(name) + strlen(value) + 2;
++ 	if (!(tmp = malloc(tmp_size))) {
+ 		errno = ENOMEM;
+ 		return -1;
+ 	}
+ 
+-	sprintf(tmp, "%s=%s", name, value);
++ 	snprintf(tmp, tmp_size, "%s=%s", name, value);
+ 	return putenv(tmp);	/* intentionally orphan 'tmp' storage */
+ }
+ #endif
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:27.646435759 +0200
++++ patched/crontab.c	2010-05-06 18:18:28.216436280 +0200
+@@ -46,7 +46,6 @@
+ 
+ #define NHEADER_LINES 3
+ 
+-
+ enum opt_t	{ opt_unknown, opt_list, opt_delete, opt_edit, opt_replace };
+ 
+ #if DEBUGGING
+@@ -55,7 +54,7 @@
+ 
+ 
+ static	PID_T		Pid;
+-static	char		User[MAX_UNAME], RealUser[MAX_UNAME];
++static	char		*User, *RealUser;
+ static	char		Filename[MAX_FNAME];
+ static	FILE		*NewCrontab = NULL;
+ static	int		CheckErrorCount;
+@@ -143,8 +142,11 @@
+ 		fprintf(stderr, "bailing out.\n");
+ 		exit(ERROR_EXIT);
+ 	}
+-	strcpy(User, pw->pw_name);
+-	strcpy(RealUser, User);
++	if (((User=strdup(pw->pw_name)) == NULL) ||
++	    ((RealUser=strdup(pw->pw_name)) == NULL)) {
++	        fprintf(stderr, "Memory allocation error\n");
++		exit(ERROR_EXIT);
++	}
+ 	Filename[0] = '\0';
+ 	Option = opt_unknown;
+ 	while (EOF != (argch = getopt(argc, argv, "u:lerx:"))) {
+@@ -166,7 +168,11 @@
+ 					ProgramName, optarg);
+ 				exit(ERROR_EXIT);
+ 			}
+-			(void) strcpy(User, optarg);
++			free(User);
++			if ((User=strdup(pw->pw_name)) == NULL) {
++			        fprintf(stderr, "Memory allocation error\n");
++				exit(ERROR_EXIT);
++			}
+ 			break;
+ 		case 'l':
+ 			if (Option != opt_unknown)
+@@ -197,7 +203,9 @@
+ 	} else {
+ 		if (argv[optind] != NULL) {
+ 			Option = opt_replace;
+-			(void) strcpy (Filename, argv[optind]);
++			(void) strncpy (Filename, argv[optind], (sizeof Filename)-1);
++			Filename[(sizeof Filename)-1] = '\0';
++
+ 		} else {
+ 			usage("file name must be specified for replace");
+ 		}
+@@ -246,7 +254,7 @@
+ 	int	ch;
+ 
+ 	log_it(RealUser, Pid, "LIST", User);
+-	(void) sprintf(n, CRON_TAB(User));
++	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+ 	if (!(f = fopen(n, "r"))) {
+ 		if (errno == ENOENT)
+ 			fprintf(stderr, "no crontab for %s\n", User);
+@@ -269,7 +277,7 @@
+ 	char	n[MAX_FNAME];
+ 
+ 	log_it(RealUser, Pid, "DELETE", User);
+-	(void) sprintf(n, CRON_TAB(User));
++	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+ 	if (unlink(n)) {
+ 		if (errno == ENOENT)
+ 			fprintf(stderr, "no crontab for %s\n", User);
+@@ -301,7 +309,7 @@
+ 	PID_T		pid, xpid;
+ 
+ 	log_it(RealUser, Pid, "BEGIN EDIT", User);
+-	(void) sprintf(n, CRON_TAB(User));
++	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+ 	if (!(f = fopen(n, "r"))) {
+ 		if (errno != ENOENT) {
+ 			perror(n);
+@@ -315,7 +323,8 @@
+ 		}
+ 	}
+ 
+-	(void) sprintf(Filename, "/tmp/crontab.%d", Pid);
++	(void) snprintf(Filename, sizeof(Filename)-1, "/tmp/crontab.%d", Pid);
++	Filename[sizeof(Filename)-1] = '\0';
+ 	if (-1 == (t = open(Filename, O_CREAT|O_EXCL|O_RDWR, 0600))) {
+ 		perror(Filename);
+ 		goto fatal;
+@@ -409,7 +418,7 @@
+ 				ProgramName);
+ 			exit(ERROR_EXIT);
+ 		}
+-		sprintf(q, "%s %s", editor, Filename);
++		snprintf(q, MAX_TEMPSTR, "%s %s", editor, Filename);
+ 		execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", q, NULL);
+ 		perror(editor);
+ 		exit(ERROR_EXIT);
+@@ -501,8 +510,8 @@
+ 		fprintf(stderr, "%s: Cannot allocate memory.\n", ProgramName);
+ 		return (-2);
+ 	}
+-	(void) sprintf(n, "tmp.%d", Pid);
+-	(void) sprintf(tn, CRON_TAB(n));
++	(void) snprintf(n, MAX_FNAME, "tmp.%d", Pid);
++	(void) snprintf(tn, MAX_FNAME, CRON_TAB(n));
+ 	if (!(tmp = fopen(tn, "w+"))) {
+ 		perror(tn);
+ 		return (-2);
+@@ -590,7 +599,7 @@
+ 		return (-2);
+ 	}
+ 
+-	(void) sprintf(n, CRON_TAB(User));
++	(void) snprintf(n, sizeof(n), CRON_TAB(User));
+ 	if (rename(tn, n)) {
+ 		fprintf(stderr, "%s: error renaming %s to %s\n",
+ 			ProgramName, tn, n);
+Index: patched/cron.h
+===================================================================
+--- patched.orig/cron.h	2010-05-06 18:18:23.394435942 +0200
++++ patched/cron.h	2010-05-06 18:18:28.216436280 +0200
+@@ -66,8 +66,8 @@
+ #define	OK_EXIT		0	/* exit() with this is considered 'normal' */
+ #define	MAX_FNAME	100	/* max length of internally generated fn */
+ #define	MAX_COMMAND	1000	/* max length of internally generated cmd */
+-#define	MAX_ENVSTR	1000	/* max length of envvar=value\0 strings */
+-#define	MAX_TEMPSTR	100	/* obvious */
++#define	MAX_TEMPSTR	1000	/* max length of envvar=value\0 strings */
++#define	MAX_ENVSTR	MAX_TEMPSTR	/* DO NOT change - buffer overruns otherwise */
+ #define	MAX_UNAME	20	/* max length of username, should be overkill */
+ #define	ROOT_UID	0	/* don't change this, it really must be root */
+ #define	ROOT_USER	"root"	/* ditto */
+Index: patched/env.c
+===================================================================
+--- patched.orig/env.c	2010-05-06 18:18:27.645727100 +0200
++++ patched/env.c	2010-05-06 18:18:28.216436280 +0200
+@@ -140,15 +140,17 @@
+ {
+ 	long	filepos;
+ 	int	fileline;
+-	char	name[MAX_TEMPSTR], val[MAX_ENVSTR];
++	char	name[MAX_ENVSTR], val[MAX_ENVSTR];
+ 	int	fields;
+ 
+ 	filepos = ftell(f);
+ 	fileline = LineNumber;
+ 	skip_comments(f);
+-	if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
++	if (EOF == get_string(envstr, MAX_ENVSTR - 1, f, "\n"))
+ 		return (ERR);
+ 
++    envstr[MAX_ENVSTR - 1] = '\0';
++
+ 	Debug(DPARS, ("load_env, read <%s>\n", envstr))
+ 
+ 	name[0] = val[0] = '\0';
+@@ -179,6 +181,8 @@
+ 		}
+ 	}
+ 
++	if (strlen(name) + 1 + strlen(val) >= MAX_ENVSTR-1)
++		return (FALSE);
+ 	(void) sprintf(envstr, "%s=%s", name, val);
+ 	Debug(DPARS, ("load_env, <%s> <%s> -> <%s>\n", name, val, envstr))
+ 	return (TRUE);
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:24.458435579 +0200
++++ patched/do_command.c	2010-05-06 18:18:28.216436280 +0200
+@@ -367,8 +367,8 @@
+ 				auto char	hostname[MAXHOSTNAMELEN];
+ 
+ 				(void) gethostname(hostname, MAXHOSTNAMELEN);
+-				(void) sprintf(mailcmd, MAILARGS,
+-					       MAILCMD, mailto);
++				(void) snprintf(mailcmd, sizeof(mailcmd),
++				    MAILARGS, MAILCMD, mailto);
+ 				if (!(mail = cron_popen(mailcmd, "w"))) {
+ 					perror(MAILCMD);
+ 					(void) _exit(ERROR_EXIT);
+@@ -426,7 +426,7 @@
+ 			if (mailto && status) {
+ 				char buf[MAX_TEMPSTR];
+ 
+-				sprintf(buf,
++				snprintf(buf, MAX_TEMPSTR,
+ 			"mailed %d byte%s of output but got status 0x%04x\n",
+ 					bytes, (bytes==1)?"":"s",
+ 					status);
+Index: patched/entry.c
+===================================================================
+--- patched.orig/entry.c	2010-05-06 18:18:27.646435759 +0200
++++ patched/entry.c	2010-05-06 18:18:28.217435826 +0200
+@@ -256,7 +256,7 @@
+ 		goto eof;
+ 	}
+ 	if (!env_get("SHELL", e->envp)) {
+-		sprintf(envstr, "SHELL=%s", _PATH_BSHELL);
++		snprintf(envstr, MAX_ENVSTR, "SHELL=%s", _PATH_BSHELL);
+ 		if ((tenvp = env_set(e->envp, envstr))) {
+ 			e->envp = tenvp;
+ 		} else {
+@@ -265,7 +265,7 @@
+ 		}
+ 	}
+ 	if (!env_get("HOME", e->envp)) {
+-		sprintf(envstr, "HOME=%s", pw->pw_dir);
++		snprintf(envstr, MAX_ENVSTR, "HOME=%s", pw->pw_dir);
+ 		if ((tenvp = env_set(e->envp, envstr))) {
+ 			e->envp = tenvp;
+ 		} else {
+@@ -274,7 +274,7 @@
+ 		}
+ 	}
+ 	if (!env_get("PATH", e->envp)) {
+-		sprintf(envstr, "PATH=%s", _PATH_DEFPATH);
++		snprintf(envstr, MAX_ENVSTR, "PATH=%s", _PATH_DEFPATH);
+ 		if ((tenvp = env_set(e->envp, envstr))) {
+ 			e->envp = tenvp;
+ 		} else {
+@@ -290,7 +290,7 @@
+ 		goto eof;
+ 	}
+ #if defined(BSD)
+-	sprintf(envstr, "%s=%s", "USER", pw->pw_name);
++	snprintf(envstr, MAX_ENVSTR, "%s=%s", "USER", pw->pw_name);
+ 	if ((tenvp = env_set(e->envp, envstr))) {
+ 		e->envp = tenvp;
+ 	} else {
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:27.646435759 +0200
++++ patched/misc.c	2010-05-06 18:18:28.217435826 +0200
+@@ -263,11 +263,11 @@
+ 		char	buf[MAX_TEMPSTR];
+ 		int	fd, otherpid;
+ 
+-		(void) sprintf(pidfile, PIDFILE, PIDDIR);
++		(void) snprintf(pidfile, MAX_FNAME, PIDFILE, PIDDIR);
+ 		if ((-1 == (fd = open(pidfile, O_RDWR|O_CREAT, 0644)))
+ 		    || (NULL == (fp = fdopen(fd, "r+")))
+ 		    ) {
+-			sprintf(buf, "can't open or create %s: %s",
++			snprintf(buf, MAX_TEMPSTR, "can't open or create %s: %s",
+ 				pidfile, strerror(errno));
+ 			fprintf(stderr, "%s: %s\n", ProgramName, buf);
+ 			log_it("CRON", getpid(), "DEATH", buf);
+@@ -278,7 +278,7 @@
+ 			int save_errno = errno;
+ 
+ 			fscanf(fp, "%d", &otherpid);
+-			sprintf(buf, "can't lock %s, otherpid may be %d: %s",
++			snprintf(buf, MAX_TEMPSTR, "can't lock %s, otherpid may be %d: %s",
+ 				pidfile, otherpid, strerror(save_errno));
+ 			fprintf(stderr, "%s: %s\n", ProgramName, buf);
+ 			log_it("CRON", getpid(), "DEATH", buf);
+@@ -466,6 +466,7 @@
+ 	char			*msg;
+ 	TIME_T			now = time((TIME_T) 0);
+ 	register struct tm	*t = localtime(&now);
++	int 			msg_size;
+ #endif /*LOG_FILE*/
+ 
+ #if defined(SYSLOG)
+@@ -475,10 +476,8 @@
+ #if defined(LOG_FILE)
+ 	/* we assume that MAX_TEMPSTR will hold the date, time, &punctuation.
+ 	 */
+-	msg = malloc(strlen(username)
+-		     + strlen(event)
+-		     + strlen(detail)
+-		     + MAX_TEMPSTR);
++	msg_size = strlen(username) + strlen(event) + strlen(detail) + MAX_TEMPSTR;
++	msg = malloc(msg_size);
+ 	if (msg == NULL) {
+ 	    /* damn, out of mem and we did not test that before... */
+ 	    fprintf(stderr, "%s: Run OUT OF MEMORY while %s\n",
+@@ -496,16 +495,16 @@
+ 		}
+ 	}
+ 
+-	/* we have to sprintf() it because fprintf() doesn't always write
++	/* we have to snprintf() it because fprintf() doesn't always write
+ 	 * everything out in one chunk and this has to be atomically appended
+ 	 * to the log file.
+ 	 */
+-	sprintf(msg, "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n",
++	snprintf(msg, msg_size, "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n",
+ 		username,
+ 		t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, pid,
+ 		event, detail);
+ 
+-	/* we have to run strlen() because sprintf() returns (char*) on old BSD
++	/* we have to run strlen() because snprintf() returns (char*) on old BSD
+ 	 */
+ 	if (LogFD < OK || write(LogFD, msg, strlen(msg)) < OK) {
+ 		if (LogFD >= OK)
+@@ -609,8 +608,10 @@
+ 			*dst++ = '^';
+ 			*dst++ = '?';
+ 		} else {			/* parity character */
+-			sprintf(dst, "\\%03o", ch);
+-			dst += 4;
++		    /* well, the following snprintf is paranoid, but that will
++		     * keep grep happy */
++		    snprintf(dst, 5, "\\%03o", ch);
++		    dst += 4;
+ 		}
+ 	}
+ 	*dst = '\0';
+@@ -646,7 +647,7 @@
+ 	struct tm *tm = localtime(&t);
+ 	static char ret[30];	/* zone name might be >3 chars */
+ 	
+-	(void) sprintf(ret, "%s, %2d %s %2d %02d:%02d:%02d %s",
++	(void) snprintf(ret, 30, "%s, %2d %s %2d %02d:%02d:%02d %s",
+ 		       DowNames[tm->tm_wday],
+ 		       tm->tm_mday,
+ 		       MonthNames[tm->tm_mon],
+Index: patched/database.c
+===================================================================
+--- patched.orig/database.c	2010-05-06 18:18:22.672435408 +0200
++++ patched/database.c	2010-05-06 18:18:28.217435826 +0200
+@@ -124,7 +124,7 @@
+ 			continue;
+ 
+ 		(void) strcpy(fname, dp->d_name);
+-		sprintf(tabname, CRON_TAB(fname));
++		snprintf(tabname, PATH_MAX+1, CRON_TAB(fname));
+ 
+ 		process_crontab(fname, fname, tabname,
+ 				&statbuf, &new_db, old_db);
diff --git a/debian/patches/fixes/root-does-not-override-allowdeny b/debian/patches/fixes/root-does-not-override-allowdeny
new file mode 100644
index 0000000..f8f6780
--- /dev/null
+++ b/debian/patches/fixes/root-does-not-override-allowdeny
@@ -0,0 +1,40 @@
+Subject: Do not allow override of cron.{allow,deny} by root
+Author: Javier Fernández-Sanguino Peña <jfs at debian.org>
+Last-Update: 2010-04-11
+
+Prevent root from using "crontab -u" with a user not allowed to use cron via
+cron.{allow,deny}. (Actually, root may not do that anyway. This just prints a
+different error message).
+
+Bug-Debian: http://bugs.debian.org/505288
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:33.711435964 +0200
++++ patched/crontab.c	2010-05-06 18:18:34.351435790 +0200
+@@ -105,11 +105,19 @@
+ 	set_cron_uid();
+ 	set_cron_cwd();
+ 	if (!allowed(User)) {
+-		fprintf(stderr,
+-			"You (%s) are not allowed to use this program (%s)\n",
+-			User, ProgramName);
+-		fprintf(stderr, "See crontab(1) for more information\n");
+-		log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
++                if ( getuid() != 0 ) {
++                    fprintf(stderr,
++                            "You (%s) are not allowed to use this program (%s)\n",
++                            User, ProgramName);
++                    fprintf(stderr, "See crontab(1) for more information\n");
++                    log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
++                } else {
++                /* If the user is not allowed but root is running the
++                 * program warn but do not log */
++                    fprintf(stderr,
++                            "The user %s cannot use this program (%s)\n",
++                            User, ProgramName);
++                }
+ 		exit(ERROR_EXIT);
+ 	}
+ 	exitstatus = OK_EXIT;
diff --git a/debian/patches/fixes/set-umask-while-editing-crontab b/debian/patches/fixes/set-umask-while-editing-crontab
new file mode 100644
index 0000000..11f860f
--- /dev/null
+++ b/debian/patches/fixes/set-umask-while-editing-crontab
@@ -0,0 +1,33 @@
+Subject: Set a tight umask when ediing a crontab
+Last-Update: 2010-04-11
+
+When editing a crontab, set the umask to 077.
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:34.351435790 +0200
++++ patched/crontab.c	2010-05-06 18:18:37.766435855 +0200
+@@ -318,6 +318,7 @@
+ 	time_t		mtime;
+ 	WAIT_T		waiter;
+ 	PID_T		pid, xpid;
++	mode_t		um;
+ 
+ 	log_it(RealUser, Pid, "BEGIN EDIT", User);
+ 	(void) snprintf(n, MAX_FNAME, CRON_TAB(User));
+@@ -334,6 +335,7 @@
+ 		}
+ 	}
+ 
++	um = umask(077);
+ 	(void) snprintf(Filename, sizeof(Filename)-1, "/tmp/crontab.%d", Pid);
+ 	Filename[sizeof(Filename)-1] = '\0';
+ 	if (-1 == (t = open(Filename, O_CREAT|O_EXCL|O_RDWR, 0600))) {
+@@ -348,6 +350,8 @@
+ 		perror("fchown");
+ 		goto fatal;
+ 	}
++
++	(void) umask(um);
+ 	if (!(NewCrontab = fdopen(t, "r+"))) {
+ 		perror("fdopen");
+ 		goto fatal;
diff --git a/debian/patches/fixes/signal-handling-issues b/debian/patches/fixes/signal-handling-issues
new file mode 100644
index 0000000..3e60691
--- /dev/null
+++ b/debian/patches/fixes/signal-handling-issues
@@ -0,0 +1,89 @@
+Subject: Fixes to signal handling issues
+Last-Update: 2010-04-11
+
+Fixes to signal handling issues. Includes a patch from Justin Pryzby
+<justinpryzby at users.sourceforge.net> from Debian Bug #155109; this moves away
+from the depreceated signal handling API.
+
+The possible race condition warned about
+should be fixed, so:
+
+NOT Acked
+Index: patched/cron.c
+===================================================================
+--- patched.orig/cron.c	2010-05-06 18:18:29.548561115 +0200
++++ patched/cron.c	2010-05-06 18:18:38.503560917 +0200
+@@ -259,6 +259,7 @@
+ #ifdef USE_SIGCHLD
+ static void
+ sigchld_handler(x) {
++	int save_errno = errno;
+ 	WAIT_T		waiter;
+ 	PID_T		pid;
+ 
+@@ -272,10 +273,12 @@
+ 		case -1:
+ 			Debug(DPROC,
+ 				("[%d] sigchld...no children\n", getpid()))
++			errno = save_errno;
+ 			return;
+ 		case 0:
+ 			Debug(DPROC,
+ 				("[%d] sigchld...no dead kids\n", getpid()))
++			errno = save_errno;
+ 			return;
+ 		default:
+ 			Debug(DPROC,
+@@ -283,6 +286,7 @@
+ 				getpid(), pid, WEXITSTATUS(waiter)))
+ 		}
+ 	}
++	errno = save_errno;
+ }
+ #endif /*USE_SIGCHLD*/
+ 
+@@ -290,6 +294,10 @@
+ static void
+ sighup_handler(x) {
+ 	log_close();
++
++	/* we should use sigaction for proper signal blocking as this 
++	   has a race, but... */
++	signal(SIGHUP, sighup_handler);
+ }
+ 
+ 
+Index: patched/popen.c
+===================================================================
+--- patched.orig/popen.c	2010-05-06 18:18:30.896560600 +0200
++++ patched/popen.c	2010-05-06 18:18:38.504560854 +0200
+@@ -181,7 +181,7 @@
+ 	FILE *iop;
+ {
+ 	register int fdes;
+-	int omask;
++	sigset_t omask, mask;
+ 	WAIT_T stat_loc;
+ 	PID_T pid;
+ 
+@@ -192,10 +192,15 @@
+ 	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
+ 		return(-1);
+ 	(void)fclose(iop);
+-	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+-	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
+-		;
+-	(void)sigsetmask(omask);
++	sigemptyset(&mask);
++	sigaddset(&mask, SIGQUIT);
++	sigaddset(&mask, SIGINT);
++	sigaddset(&mask, SIGHUP);
++	sigprocmask(SIG_BLOCK, &mask, &omask);
++	pid = waitpid(pids[fdes], &stat_loc, 0);
++	sigprocmask(SIG_SETMASK, &omask, NULL);
+ 	pids[fdes] = 0;
+-	return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
++	if (pid == -1 || !WIFEXITED(stat_loc))
++		return -1;
++	return WEXITSTATUS(stat_loc);
+ }
diff --git a/debian/patches/fixes/tolerate-empty-editor-and-visual-envs b/debian/patches/fixes/tolerate-empty-editor-and-visual-envs
new file mode 100644
index 0000000..812c746
--- /dev/null
+++ b/debian/patches/fixes/tolerate-empty-editor-and-visual-envs
@@ -0,0 +1,28 @@
+Subject: Tolerate empty EDITOR and VISUAL envvars
+Last-Updated: 2010-04-11
+
+Empty EDITOR and VISUAL environment variables (as opposed to unset ones) should
+not cause fatal errors.
+
+Bug-Debian: http://bugs.debian.org/148809
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/crontab.c
+===================================================================
+--- patched.orig/crontab.c	2010-05-06 18:18:30.213560954 +0200
++++ patched/crontab.c	2010-05-06 18:18:33.711435964 +0200
+@@ -388,8 +388,12 @@
+ 	}
+ 	mtime = statbuf.st_mtime;
+ 
+-	if ((!(editor = getenv("VISUAL")))
+-	 && (!(editor = getenv("EDITOR")))
++
++
++        /* Okay, edit the file */
++
++	if ((!((editor = getenv("VISUAL")) && strlen(editor)))
++	 && (!((editor = getenv("EDITOR")) && strlen(editor)))
+ 	    ) {
+ 		editor = EDITOR;
+ 	}
diff --git a/debian/patches/fixes/use-stdlib-for-time b/debian/patches/fixes/use-stdlib-for-time
new file mode 100644
index 0000000..6f9625c
--- /dev/null
+++ b/debian/patches/fixes/use-stdlib-for-time
@@ -0,0 +1,61 @@
+Subject: Use standard library functions for time stuff
+Last-Update: 2010-04-11
+
+Use standard library functions for time stuff
+
+Acked-by: Christian Kastner <debian at kvr.at>
+Index: patched/misc.c
+===================================================================
+--- patched.orig/misc.c	2010-05-06 18:18:28.844435899 +0200
++++ patched/misc.c	2010-05-06 18:18:37.114561029 +0200
+@@ -632,26 +632,36 @@
+ 
+ 
+ #ifdef MAIL_DATE
+-/* Sat, 27 Feb 93 11:44:51 CST
+- * 123456789012345678901234567
++/* Sat, 27 Feb 1993 11:44:51 -0800 (CST)
++ * 1234567890123456789012345678901234567
+  */
+ char *
+ arpadate(clock)
+ 	time_t *clock;
+ {
+-	time_t t = clock ?*clock :time(0L);
++	static char ret[64];	/* zone name might be >3 chars */
++	time_t t = clock ? *clock : time(NULL);
+ 	struct tm *tm = localtime(&t);
+-	static char ret[30];	/* zone name might be >3 chars */
+-	
+-	(void) snprintf(ret, 30, "%s, %2d %s %2d %02d:%02d:%02d %s",
+-		       DowNames[tm->tm_wday],
+-		       tm->tm_mday,
+-		       MonthNames[tm->tm_mon],
+-		       tm->tm_year,
+-		       tm->tm_hour,
+-		       tm->tm_min,
+-		       tm->tm_sec,
+-		       TZONE(*tm));
++	char *qmark;
++	size_t len;
++	int hours = tm->tm_gmtoff / 3600;
++	int minutes = (tm->tm_gmtoff - (hours * 3600)) / 60;
++
++	if (minutes < 0)
++		minutes = -minutes;
++
++	/* Defensive coding (almost) never hurts... */
++	len = strftime(ret, sizeof(ret), "%a, %e %b %Y %T ????? (%Z)", tm);
++	if (len == 0) {
++		ret[0] = '?';
++		ret[1] = '\0';
++		return ret;
++	}
++	qmark = strchr(ret, '?');
++	if (qmark && len - (qmark - ret) >= 6) {
++		snprintf(qmark, 6, "% .2d%.2d", hours, minutes);
++		qmark[5] = ' ';
++	}
+ 	return ret;
+ }
+ #endif /*MAIL_DATE*/
diff --git a/debian/patches/fixes/various-mail-fixes b/debian/patches/fixes/various-mail-fixes
new file mode 100644
index 0000000..b61baf6
--- /dev/null
+++ b/debian/patches/fixes/various-mail-fixes
@@ -0,0 +1,97 @@
+Subject: Various mail fixes
+Last-Update: 2010-04-11
+
+* rDoS fix: Unchecked contents of MAILTO would allow sending arbitrary commands
+  to sendmail. Prevent this.
+* Don't terminate when finding a dot "." on a line by itself. (sendmail -i)
+* Don't force immediate delivery
+* Style/formatting
+
+Bug-Debian: http://bugs.debian.org/36338
+Bug-Debian: http://bugs.debian.org/146224
+
+
+POSSIBLE BUG:
+  
+   mailto += strspn(mailto, " \t\n");
+
+why is mailto altered, apparently without reversing the effect?
+
+The entire MAILTO sanitation code appears a bit dodgy and could use a rewrite
+(ie, a correct parsing for a valid local or remote address).
+
+NOT-Acked as of 4010-04-11
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:30.896560600 +0200
++++ patched/do_command.c	2010-05-06 18:18:31.634435779 +0200
+@@ -96,6 +96,21 @@
+ 	usernm = env_get("LOGNAME", e->envp);
+ 	mailto = env_get("MAILTO", e->envp);
+ 
++	/* Check for arguments */
++	if (mailto) {
++		const char	*end;
++
++		/* These chars have to match those cron_popen()
++		 * uses to split the command string */
++		mailto += strspn(mailto, " \t\n");
++		end = mailto + strcspn(mailto, " \t\n");
++		if (*mailto == '-' || *end != '\0') {
++			printf("Bad Mailto karma.\n");
++			log_it("CRON",getpid(),"error","bad mailto");
++			mailto = NULL;
++		}
++	}
++
+ #ifdef USE_SIGCHLD
+ 	/* our parent is watching for our death by catching SIGCHLD.  we
+ 	 * do not care to watch for our children's deaths this way -- we
+Index: patched/config.h
+===================================================================
+--- patched.orig/config.h	2010-05-06 18:18:14.096435742 +0200
++++ patched/config.h	2010-05-06 18:18:31.635435778 +0200
+@@ -42,22 +42,27 @@
+ 			 */
+ 
+ #define MAILCMD _PATH_SENDMAIL					/*-*/
+-#define MAILARGS "%s -FCronDaemon -odi -oem -or0s %s"		/*-*/
+-			/* -Fx	 = set full-name of sender
++/* #define MAILARGS "%s -i -FCronDaemon -odi -oem  %s"		/*-*/
++#define MAILARGS "%s -i -FCronDaemon -oem  %s"		/*-*/
++			/* -i    = don't terminate on "." by itself
++                         * -Fx	 = set full-name of sender
+ 			 * -odi	 = Option Deliverymode Interactive
+ 			 * -oem	 = Option Errors Mailedtosender
++ 			 * -t    = read recipient from header of message
+ 			 * -or0s = Option Readtimeout -- don't time out
++			 * XXX: sendmail doesn't allow -or0s when invoked
++			 * by joe user.  --okir
+ 			 */
+ 
+-/* #define MAILCMD "/bin/mail"			/*-*/
+-/* #define MAILARGS "%s -d  %s"			/*-*/
++/* #define MAILCMD "/bin/mail"			-*/
++/* #define MAILARGS "%s -d  %s"			-*/
+ 			/* -d = undocumented but common flag: deliver locally?
+ 			 */
+ 
+-/* #define MAILCMD "/usr/mmdf/bin/submit"	/*-*/
+-/* #define MAILARGS "%s -mlrxto %s"		/*-*/
++/* #define MAILCMD "/usr/mmdf/bin/submit"	-*/
++/* #define MAILARGS "%s -mlrxto %s"		-*/
+ 
+-/* #define MAIL_DATE				/*-*/
++/* #define MAIL_DATE				-*/
+ 			/* should we include an ersatz Date: header in
+ 			 * generated mail?  if you are using sendmail
+ 			 * for MAILCMD, it is better to let sendmail
+@@ -68,7 +73,7 @@
+ 			 * defined but neither exists, should crontab(1) be
+ 			 * usable only by root?
+ 			 */
+-/*#define ALLOW_ONLY_ROOT			/*-*/
++/*#define ALLOW_ONLY_ROOT			-*/
+ 
+ 			/* if you want to use syslog(3) instead of appending
+ 			 * to CRONDIR/LOG_FILE (/var/cron/log, e.g.), define
diff --git a/debian/patches/other/DEAD-CODE b/debian/patches/other/DEAD-CODE
new file mode 100644
index 0000000..6102538
--- /dev/null
+++ b/debian/patches/other/DEAD-CODE
@@ -0,0 +1,18 @@
+Index: patched/do_command.c
+===================================================================
+--- patched.orig/do_command.c	2010-05-06 18:18:59.713435868 +0200
++++ patched/do_command.c	2010-05-06 18:19:06.789435772 +0200
+@@ -349,6 +349,13 @@
+ 				_exit(OK_EXIT);
+ 			}
+ # endif /*DEBUGGING*/
++#if 0
++			{
++			  struct sigaction oact;
++			  sigaction(SIGCHLD, NULL, &oact);
++			}
++			fprintf(stdout,"error");
++#endif
+ #ifdef WITH_SELINUX
+ 			if (is_selinux_enabled() > 0) {
+ 			    if (u->scontext != 0L) {
diff --git a/debian/patches/other/changes-to-cron-8 b/debian/patches/other/changes-to-cron-8
new file mode 100644
index 0000000..13cb98a
--- /dev/null
+++ b/debian/patches/other/changes-to-cron-8
@@ -0,0 +1,158 @@
+Index: patched/cron.8
+===================================================================
+--- patched.orig/cron.8	2010-05-06 18:17:51.496436204 +0200
++++ patched/cron.8	2010-05-06 18:19:04.696435830 +0200
+@@ -17,28 +17,87 @@
+ .\" 
+ .\" $Id: cron.8,v 2.2 1993/12/28 08:34:43 vixie Exp $
+ .\" 
+-.TH CRON 8 "20 December 1993"
++.TH CRON 8 "19 April 2010"
+ .UC 4
+ .SH NAME
+ cron \- daemon to execute scheduled commands (Vixie Cron)
+ .SH SYNOPSIS
+ cron
++.RB [ -f ]
++.RB [ -l ]
++.RB [ -L
++.IR loglevel ]
+ .SH DESCRIPTION
+-.I Cron
+-should be started from /etc/rc or /etc/rc.local.  It will return immediately,
+-so you don't need to start it with '&'.
+-.PP
+-.I Cron
+-searches /var/cron/tabs for crontab files which are named after accounts in
+-/etc/passwd; crontabs found are loaded into memory.
+-.I Cron
+-also searches for /etc/crontab which is in a different format (see
+-.IR crontab(5)).
+-.I Cron
+-then wakes up every minute, examining all stored crontabs, checking each
+-command to see if it should be run in the current minute.  When executing
+-commands, any output is mailed to the owner of the crontab (or to the user
+-named in the MAILTO environment variable in the crontab, if such exists).
++.I cron
++is started automatically from /etc/init.d on entering multi-user
++runlevels.
++.SH OPTIONS
++.TP 8
++.B -f
++Stay in foreground mode, don't daemonize.
++.TP
++.B -l
++Enable LSB compliant names for /etc/cron.d files
++.TP
++.B -L loglevel
++Sets the loglevel for cron. The standard logging level (1) will log 
++the start of all the cron jobs. A higher loglevel (2) will cause
++cron to log also the end of all cronjobs, which can be useful to
++audit the behaviour of tasks run by cron. Logging will be disabled
++if the \fIloglevel\fR is set to zero (0).
++.SH NOTES
++.PP
++.I cron
++searches its spool area (/var/spool/cron/crontabs) for crontab
++files (which are named after accounts in
++/etc/passwd); crontabs found are loaded into memory.  Note that
++crontabs in this directory should not be accessed directly -
++the
++.I crontab
++command should be used to access and update them.
++
++.I cron
++also reads /etc/crontab, which is in a slightly different format (see
++.IR crontab(5) ). 
++Additionally,
++.I cron
++reads the files in /etc/cron.d: it
++treats the files in /etc/cron.d as in the same way as the /etc/crontab file (they
++follow the special format of that file, i.e. they include the 
++.I user
++field). However, they are independent of /etc/crontab: they do not, for 
++example, inherit environment variable settings from it. The intended purpose
++of this feature is to allow packages that require
++finer control of their scheduling than the /etc/cron.{daily,weekly,monthly} 
++directories to add a crontab file to /etc/cron.d. Such files
++should be named after the package that supplies them. Files must
++conform to the same naming convention as used by 
++.IR run-parts(8) :
++they
++must consist solely of upper- and lower-case letters, digits, underscores,
++and hyphens. If the 
++.B -l
++option is specified, then they must conform to the LSB namespace specification,
++exactly as in the
++.B --lsbsysinit
++option in 
++.IR run-parts .
++
++Like /etc/crontab, the files in the /etc/cron.d directory are
++monitored for changes. In general, the admin should not use /etc/cron.d/,
++but use the standard system crontab /etc/crontab.
++
++In contrast to the spool area, files in /etc/cron.d may be symlinks, provided
++that both the symlink and the file it points to are owned by root.
++
++.I cron
++then wakes up every minute, examining all stored crontabs, checking
++each command to see if it should be run in the current minute.  When
++executing commands, any output is mailed to the owner of the crontab
++(or to the user named in the MAILTO environment variable in the
++crontab, if such exists).  The children copies of cron running these
++processes have their name coerced to uppercase, as will be seen in the
++syslog and ps output.
+ .PP
+ Additionally,
+ .I cron
+@@ -51,9 +110,48 @@
+ changed.  Thus
+ .I cron
+ need not be restarted whenever a crontab file is modified.  Note that the
+-.IR Crontab (1)
++.IR crontab (1)
+ command updates the modtime of the spool directory whenever it changes a
+ crontab.
++.PP
++Special considerations exist when the clock is changed by less than 3
++hours, for example at the beginning and end of daylight savings
++time. If the time has moved forwards, those jobs which would have
++run in the time that was skipped will be run soon after the change. 
++Conversely, if the time has moved backwards by less than 3 hours,
++those jobs that fall into the repeated time will not be re-run.
++.PP
++Only jobs that run at a particular time (not specified as
++ at hourly, nor with '*' in the hour or minute specifier) are
++affected. Jobs which are specified with wildcards are run based on the
++new time immediately.
++.PP
++Clock changes of more than 3 hours are considered to be corrections to
++the clock, and the new time is used immediately.
++.PP
++.I cron
++logs its action to the syslog facility 'cron', and logging may be
++controlled using the standard syslogd(8) facility.
++.SH ENVIRONMENT
++If configured in
++.I /etc/default/cron
++in Debian systems, the
++.I cron
++daemon localisation settings environment can be managed through the use of 
++.I /etc/environment
++or through the use of
++.I /etc/default/locale
++whichever is available (with the latter one taking precedence). These
++files are read and they will use to setup the LANG, LC_ALL, and
++LC_CTYPE environment variables.
++.PP
++The daemon will use, if present, the definition from
++.I /etc/timezone
++for the timezone.
++.PP
++The environment can be redefined in user's crontab definitions but
++.I cron
++will only handle tasks in a single timezone.
+ .SH "SEE ALSO"
+ crontab(1), crontab(5)
+ .SH AUTHOR
diff --git a/debian/patches/other/changes-to-crontab-1 b/debian/patches/other/changes-to-crontab-1
new file mode 100644
index 0000000..33747de
--- /dev/null
+++ b/debian/patches/other/changes-to-crontab-1
@@ -0,0 +1,170 @@
+Index: patched/crontab.1
+===================================================================
+--- patched.orig/crontab.1	2010-05-06 18:17:51.441435609 +0200
++++ patched/crontab.1	2010-05-06 18:19:05.363435648 +0200
+@@ -17,40 +17,54 @@
+ .\"
+ .\" $Id: crontab.1,v 2.4 1993/12/31 10:47:33 vixie Exp $
+ .\"
+-.TH CRONTAB 1 "29 December 1993"
++.TH CRONTAB 1 "19 April 2010"
+ .UC 4
+ .SH NAME
+-crontab \- maintain crontab files for individual users (V3)
++crontab \- maintain crontab files for individual users (Vixie Cron)
+ .SH SYNOPSIS
+ crontab [ -u user ] file
+ .br
+-crontab [ -u user ] { -l | -r | -e }
++crontab [ -u user ] [ -i ] { -e | -l | -r }
+ .SH DESCRIPTION
+-.I Crontab
++.I crontab
+ is the program used to install, deinstall or list the tables
+ used to drive the
+ .IR cron (8)
+ daemon in Vixie Cron.  Each user can have their own crontab, and though
+-these are files in /var, they are not intended to be edited directly.
++these are files in /var/spool/cron/crontabs,
++they are not intended to be edited directly.
+ .PP
+ If the
+-.I allow
+-file exists, then you must be listed therein in order to be allowed to use
+-this command.  If the
+-.I allow
++.I /etc/cron.allow
++file exists, then you must be listed (one user per line) therein in order to be
++allowed to use this command.  If the
++.I /etc/cron.allow
+ file does not exist but the
+-.I deny
++.I /etc/cron.deny
+ file does exist, then you must \fBnot\fR be listed in the
+-.I deny
+-file in order to use this command.  If neither of these files exists, then
+-depending on site-dependent configuration parameters, only the super user
+-will be allowed to use this command, or all users will be able to use this
+-command.
++.I /etc/cron.deny
++file in order to use this command. 
++.PP
++If neither of these files exists, then depending on site-dependent
++configuration parameters, only the super user will be allowed to use this
++command, or all users will be able to use this command. 
++.PP
++If both files exist then 
++.I /etc/cron.allow
++takes precendence. Which means that 
++.I /etc/cron.deny
++is not considered and your user must be listed in 
++.I /etc/cron.allow
++in order to be able to use the crontab.
++.PP
++Regardless of the existance of any of these files, the root administrative
++user is always allowed to setup a crontab.  For standard Debian systems, all
++users may use this command.
+ .PP
+ If the
+ .I -u
+ option is given, it specifies the name of the user whose crontab is to be
+-tweaked.  If this option is not given,
++used (when listing) or modified (when editing). If this option is not given,
+ .I crontab
+ examines "your" crontab, i.e., the crontab of the person executing the
+ command.  Note that
+@@ -58,7 +72,7 @@
+ can confuse
+ .I crontab
+ and that if you are running inside of
+-.IR su (8)
++.IR su (8) 
+ you should always use the
+ .I -u
+ option for safety's sake.
+@@ -68,7 +82,10 @@
+ .PP
+ The
+ .I -l
+-option causes the current crontab to be displayed on standard output.
++option causes the current crontab to be displayed on standard output. See
++the note under 
++.B DEBIAN SPECIFIC
++below.
+ .PP
+ The
+ .I -r
+@@ -77,24 +94,69 @@
+ The
+ .I -e
+ option is used to edit the current crontab using the editor specified by
+-the \s-1VISUAL\s+1 or \s-1EDITOR\s+1 environment variables.  After you exit
+-from the editor, the modified crontab will be installed automatically.
++the \s-1VISUAL\s+1 or \s-1EDITOR\s+1 environment variables.
++After you exit
++from the editor, the modified crontab will be installed automatically. If
++neither of the environment variables is defined, then the
++default editor /usr/bin/editor is used.
++.PP
++The
++.I -i
++option modifies the -r option to prompt the user for a 'y/Y' response
++before actually removing the crontab.
++.SH DEBIAN SPECIFIC
++The "out-of-the-box" behaviour for
++.I crontab -l
++is to display the three line "DO NOT EDIT THIS FILE" header 
++that is placed at the
++beginning of the crontab when it is installed. The problem is that
++it makes the sequence
++.PP
++crontab -l | crontab -
++.PP
++non-idempotent -- you keep adding copies of the header. This causes
++pain to scripts that use sed to edit a crontab. Therefore, the default
++behaviour of the 
++.B -l
++option has been changed to not output such header. You may obtain the
++original behaviour by setting the environment variable 
++.B CRONTAB_NOHEADER
++to 'N', which will cause the
++.I crontab -l
++command to emit the extraneous header.
+ .SH "SEE ALSO"
+ crontab(5), cron(8)
+ .SH FILES
+ .nf
+-/var/cron/allow
+-/var/cron/deny
++/etc/cron.allow
++/etc/cron.deny
++/var/spool/cron/crontabs
+ .fi
++.PP
++There is one file for each user's crontab under the /var/spool/cron/crontabs
++directory. Users are not allowed to edit the files under that directory
++directly to ensure that only users allowed by the system to run periodic tasks
++can add them, and only syntactically correct crontabs will be written there.
++This is enforced by having the directory writable only by the
++.I crontab
++group and configuring
++.I crontab
++command with the setgid bid set for that specific group.
+ .SH STANDARDS
+ The
+ .I crontab
+ command conforms to IEEE Std1003.2-1992 (``POSIX'').  This new command syntax
+ differs from previous versions of Vixie Cron, as well as from the classic
+ SVR3 syntax.
++
+ .SH DIAGNOSTICS
+ A fairly informative usage message appears if you run it with a bad command
+ line.
++
++cron requires that each entry in a crontab end in a newline character. If the
++last entry in a crontab is missing the newline, cron will consider the crontab
++(at least partially) broken and refuse to install it.
++
+ .SH AUTHOR
+ .nf
+ Paul Vixie <paul at vix.com>
diff --git a/debian/patches/other/changes-to-crontab-5 b/debian/patches/other/changes-to-crontab-5
new file mode 100644
index 0000000..e9b1ad0
--- /dev/null
+++ b/debian/patches/other/changes-to-crontab-5
@@ -0,0 +1,268 @@
+Index: patched/crontab.5
+===================================================================
+--- patched.orig/crontab.5	2010-05-06 18:17:51.399560787 +0200
++++ patched/crontab.5	2010-05-06 18:19:06.107981321 +0200
+@@ -17,7 +17,7 @@
+ .\"
+ .\" $Id: crontab.5,v 2.4 1994/01/15 20:43:43 vixie Exp $
+ .\" 
+-.TH CRONTAB 5 "24 January 1994"
++.TH CRONTAB 5 "19 April 2010"
+ .UC 4
+ .SH NAME
+ crontab \- tables for driving cron
+@@ -34,7 +34,7 @@
+ as part of a cron command.
+ .PP
+ Blank lines and leading spaces and tabs are ignored.  Lines whose first
+-non-space character is a pound-sign (#) are comments, and are ignored.
++non-space character is a hash-sign (#) are comments, and are ignored.
+ Note that comments are not allowed on the same line as cron commands, since
+ they will be taken to be part of the command.  Similarly, comments are not
+ allowed on the same line as environment variable settings.
+@@ -52,15 +52,41 @@
+ The
+ .I value
+ string may be placed in quotes (single or double, but matching) to preserve
+-leading or trailing blanks.
++leading or trailing blanks. To define an empty variable, quotes
++.B must
++be used. The  
++.I value
++string is 
++.B not
++parsed for environmental substitutions or replacement of variables, thus lines
++like
++.PP
++    PATH = $HOME/bin:$PATH
++.PP
++will not work as you might expect. And neither will this work
++.PP
++    A=1
++    B=2
++    C=$A $B
++.PP
++There will not be any subsitution for the defined variables in the
++last value.
+ .PP
+-Several environment variables are set up
+-automatically by the
++An alternative for setting up the commands path is using the fact that
++many shells will treat the tilde(~) as substitution of $HOME, so if you use 
++.I bash
++for your tasks you can use this:
++.PP
++     SHELL=/bin/bash
++     PATH=~/bin:/usr/bin/:/bin
++.PP
++Several environment variables are set up automatically by the
+ .IR cron (8)
+ daemon.
+ SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd 
+-line of the crontab's owner.
+-HOME and SHELL may be overridden by settings in the crontab; LOGNAME may not.
++line of the crontab's owner. PATH is set to "/usr/bin:/bin".
++HOME, SHELL, and PATH may be overridden by settings in the crontab;
++LOGNAME is the user that the job is running from, and may not be changed.
+ .PP
+ (Another note: the LOGNAME variable is sometimes called USER on BSD systems...
+ on these systems, USER will be set also.)
+@@ -69,16 +95,45 @@
+ .IR cron (8)
+ will look at MAILTO if it has any reason to send mail as a result of running
+ commands in ``this'' crontab.  If MAILTO is defined (and non-empty), mail is
+-sent to the user so named.  If MAILTO is defined but empty (MAILTO=""), no
+-mail will be sent.  Otherwise mail is sent to the owner of the crontab.  This
+-option is useful if you decide on /bin/mail instead of /usr/lib/sendmail as
+-your mailer when you install cron -- /bin/mail doesn't do aliasing, and UUCP
+-usually doesn't read its mail.
++sent to the user so named.  MAILTO may also be used to direct mail to multiple
++recipients by separating recipient users with a comma. If MAILTO is defined
++but empty (MAILTO=""), no mail will be sent.  Otherwise mail is sent to the
++owner of the crontab.
++.PP
++On the Debian GNU/Linux system, cron supports the
++.B pam_env
++module, and loads the environment specified by 
++.IR /etc/environment
++and
++.IR /etc/security/pam_env.conf .
++However, the PAM setting do
++.B NOT
++override the settings described above nor any settings in the 
++.I crontab
++file itself. Note in particular that if you want a PATH other than
++"/usr/bin:/bin", you will need to set it in the crontab file.
++.PP
++By default, cron will send mail using the mail "Content-Type:" header of
++"text/plain" with the "charset=" parameter set to the charmap / codeset of the
++locale in which
++.IR crond (8)
++is started up - ie. either the default system locale, if no LC_* environment
++variables are set, or the locale specified by the LC_* environment variables 
++( see
++.IR locale (7) ).
++You can use different character encodings for mailed cron job output by
++setting the CONTENT_TYPE and CONTENT_TRANSFER_ENCODING variables in crontabs,
++to the correct values of the mail headers of those names.
+ .PP
+ The format of a cron command is very much the V7 standard, with a number of
+ upward-compatible extensions.  Each line has five time and date fields,
+-followed by a user name if this is the system crontab file,
+-followed by a command.  Commands are executed by
++followed by a command, followed by a newline character ('\\n').  
++The system crontab (/etc/crontab) uses the same format, except that
++the username for the command is specified after the time and
++date fields and before the command. The fields may be separated
++by spaces or tabs.
++.PP
++Commands are executed by
+ .IR cron (8)
+ when the minute, hour, and month of year fields match the current time,
+ .I and
+@@ -97,9 +152,9 @@
+ .br
+ hour	0-23
+ .br
+-day of month	0-31
++day of month	1-31
+ .br
+-month	0-12 (or names, see below)
++month	1-12 (or names, see below)
+ .br
+ day of week	0-7 (0 or 7 is Sun, or use names)
+ .br
+@@ -131,26 +186,51 @@
+ run.
+ The entire command portion of the line, up to a newline or %
+ character, will be executed by /bin/sh or by the shell
+-specified in the SHELL variable of the cronfile.
++specified in the SHELL variable of the crontab file.
+ Percent-signs (%) in the command, unless escaped with backslash
+ (\\), will be changed into newline characters, and all data
+ after the first % will be sent to the command as standard
+-input.
++input. There is no way to split a single command line onto multiple
++lines, like the shell's trailing "\\".
+ .PP
+ Note: The day of a command's execution can be specified by two
+ fields \(em day of month, and day of week.  If both fields are
+-restricted (ie, aren't *), the command will be run when
++restricted (i.e., aren't *), the command will be run when
+ .I either
+ field matches the current time.  For example,
+ .br
+ ``30 4 1,15 * 5''
+ would cause a command to be run at 4:30 am on the 1st and 15th of each
+ month, plus every Friday.
++.PP
++Instead of the first five fields, one of eight special strings may appear:
++.IP
++.ta 1.5i
++string	meaning
++.br
++------	-------
++.br
++ at reboot	Run once, at startup.
++.br
++ at yearly	Run once a year, "0 0 1 1 *".
++.br
++ at annually	(same as @yearly)
++.br
++ at monthly	Run once a month, "0 0 1 * *".
++.br
++ at weekly	Run once a week, "0 0 * * 0".
++.br
++ at daily	Run once a day, "0 0 * * *".
++.br
++ at midnight	(same as @daily)
++.br
++ at hourly	Run once an hour, "0 * * * *".
++.br
+ .SH EXAMPLE CRON FILE
+ .nf
+ 
+-# use /bin/sh to run commands, no matter what /etc/passwd says
+-SHELL=/bin/sh
++# use /bin/bash to run commands, instead of the default /bin/sh
++SHELL=/bin/bash
+ # mail any output to `paul', no matter whose crontab this is
+ MAILTO=paul
+ #
+@@ -159,30 +239,71 @@
+ # run at 2:15pm on the first of every month -- output mailed to paul
+ 15 14 1 * *     $HOME/bin/monthly
+ # run at 10 pm on weekdays, annoy Joe
+-0 22 * * 1-5	mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
++0 22 * * 1-5    mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
+ 23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
+ 5 4 * * sun     echo "run at 5 after 4 every sunday"
+ .fi
++.SH EXAMPLE SYSTEM CRON FILE
++This has the username field, as used by /etc/crontab.
++.nf
++# /etc/crontab: system-wide crontab
++# Unlike any other crontab you don't have to run the `crontab'
++# command to install the new version when you edit this file
++# and files in /etc/cron.d. These files also have username fields,
++# that none of other the crontabs do.
++
++SHELL=/bin/sh
++PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
++
++# m h dom mon dow user    command
++42 6 * * *        root    run-parts --report /etc/cron.daily
++47 6 * * 7        root    run-parts --report /etc/cron.weekly
++52 6 1 * *        root    run-parts --report /etc/cron.monthly
++#
++# Removed invocation of anacron, as this is now handled by a 
++# /etc/cron.d file
++.fi
+ .SH SEE ALSO
+ cron(8), crontab(1)
+ .SH EXTENSIONS
+ When specifying day of week, both day 0 and day 7 will be considered Sunday.
+-BSD and ATT seem to disagree about this.
++BSD and AT&T seem to disagree about this.
+ .PP
+ Lists and ranges are allowed to co-exist in the same field.  "1-3,7-9" would
+-be rejected by ATT or BSD cron -- they want to see "1-3" or "7,8,9" ONLY.
++be rejected by AT&T or BSD cron -- they want to see "1-3" or "7,8,9" ONLY.
+ .PP
+ Ranges can include "steps", so "1-9/2" is the same as "1,3,5,7,9".
+ .PP
+-Names of months or days of the week can be specified by name.
++Months or days of the week can be specified by name.
+ .PP
+-Environment variables can be set in the crontab.  In BSD or ATT, the
++Environment variables can be set in the crontab.  In BSD or AT&T, the
+ environment handed to child processes is basically the one from /etc/rc.
+ .PP
+ Command output is mailed to the crontab owner (BSD can't do this), can be
+ mailed to a person other than the crontab owner (SysV can't do this), or the
+ feature can be turned off and no mail will be sent at all (SysV can't do this
+ either).
++.PP
++All of the `@' commands that can appear in place of the first five fields
++are extensions.
++.SH LIMITATIONS
++The
++.I cron
++daemon runs with a defined timezone. It currently does not support 
++per-user timezones. All the tasks: system's and user's will be run based on the
++configured timezone. Even if a user specifies the 
++.I TZ
++environment variable in his
++.I crontab
++this will affect only the commands executed in the crontab, not the execution
++of the crontab tasks themselves.
++
++.SH DIAGNOSTICS
++cron requires that each entry in a crontab end in a newline character. If the
++last entry in a crontab is missing a newline (ie, terminated by EOF), cron will
++consider the crontab (at least partially) broken. A warning will be written to
++syslog.
++
+ .SH AUTHOR
+ .nf
+ Paul Vixie <paul at vix.com>
diff --git a/debian/patches/other/changes-to-upstream-README b/debian/patches/other/changes-to-upstream-README
new file mode 100644
index 0000000..a9326d9
--- /dev/null
+++ b/debian/patches/other/changes-to-upstream-README
@@ -0,0 +1,17 @@
+Index: patched/README
+===================================================================
+--- patched.orig/README	2010-05-06 18:17:51.539561005 +0200
++++ patched/README	2010-05-06 18:19:04.037962120 +0200
+@@ -24,6 +24,12 @@
+ [V1.0 was May 6, 1987]
+ Paul Vixie
+ 
++[Note from Debian cron maintainer: This is the original README from
++the the vixie-cron package. The location of many cron files has been
++changed in order to comply with Debian policy and common sense -- look
++in the cron(8), crontab(1) and crontab(5) man pages for more info, as
++well as the README.Debian file in this directory.]
++
+ This is a version of 'cron' that is known to run on BSD 4.[23] systems.  It
+ is functionally based on the SysV cron, which means that each user can have
+ their own crontab file (all crontab files are stored in a read-protected
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..e4e0988
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,62 @@
+fixes/make-it-buildable
+fixes/general-platform-issues
+fixes/missing-or-broken-defs-and-decls
+fixes/general-coding-errors
+fixes/limit-args-for-commands
+fixes/crontab-file-parsing
+fixes/crontab-entry-parsing
+fixes/crontab-time-parsing
+fixes/memory-management-issues
+fixes/protect-against-buffer-overflows
+fixes/correct-use-of-error-messages
+fixes/proper-handling-of-stdstreams
+fixes/allow-crontab-by-users
+fixes/drop-privileges
+fixes/various-mail-fixes
+fixes/abort-crontabs-with-errors
+fixes/handle-escapes-in-commands
+fixes/tolerate-empty-editor-and-visual-envs
+fixes/root-does-not-override-allowdeny
+fixes/correct-flag-setting-in-crontab-entry
+fixes/check-for-broken-command
+fixes/dont-log-temp-files
+fixes/use-stdlib-for-time
+fixes/set-umask-while-editing-crontab
+fixes/signal-handling-issues
+fixes/properly-wait-for-spawned-editor
+fixes/prevent-tmpfiles-attack
+fixes/check-for-full-disk
+fixes/allow-editors-with-tmpfiles
+fixes/dont-give-root-on-repeated-edits
+fixes/compilation-issues
+features/debian-specific-issues
+features/better-debugging-support
+features/debian-paths-and-commands
+features/pam-support
+features/pam-env-support
+features/selinux-support
+features/support-for-drop.d-directory
+features/debian-logging-configuration
+features/properly-handle-time-skips
+features/swap-both-uid-and-gid
+features/security-make-crontab-setgid-crontab
+features/auditlog-support
+features/run-on-reboot
+features/set-contenttype-in-mail
+features/allow-running-cron-in-foreground
+features/control-header-output
+features/confirm-crontab-deletion
+features/add-helpmsg-to-new-crontab
+features/option-log-completed-jobs
+features/mailcmd-dont-timeout
+features/dont-fail-on-missing-MTA
+features/no-argument-is-stdin
+features/dont-die-on-missing-dirs
+features/crontab-refuse-eof-without-nl
+features/recover-from-broken-symlinks
+features/backport-envparser
+other/changes-to-upstream-README
+other/changes-to-cron-8
+other/changes-to-crontab-1
+other/changes-to-crontab-5
+other/DEAD-CODE
diff --git a/debian/standard.daily b/debian/standard.daily
new file mode 100644
index 0000000..fce6ef0
--- /dev/null
+++ b/debian/standard.daily
@@ -0,0 +1,134 @@
+#!/bin/sh
+# /etc/cron.daily/standard: standard daily maintenance script
+# Written by Ian A. Murdock <imurdock at gnu.ai.mit.edu>
+# Modified by Ian Jackson <ijackson at nyx.cs.du.edu>
+# Modified by Steve Greenland <stevegr at debian.org>
+
+# Start in the root filesystem, make SElinux happy
+cd /
+bak=/var/backups
+LOCKFILE=/var/lock/cron.daily
+umask 022
+
+#
+# Avoid running more than one at a time 
+#
+
+if [ -x /usr/bin/lockfile-create ] ; then
+    lockfile-create $LOCKFILE
+    if [ $? -ne 0 ] ; then
+	cat <<EOF
+
+Unable to run /etc/cron.daily/standard because lockfile $LOCKFILE
+acquisition failed. This probably means that the previous day's
+instance is still running. Please check and correct if necessary.
+
+EOF
+	exit 1
+    fi
+
+    # Keep lockfile fresh
+    lockfile-touch $LOCKFILE &
+    LOCKTOUCHPID="$!"
+fi
+
+#
+# Backup key system files
+#
+
+if cd $bak ; then
+	cmp -s passwd.bak /etc/passwd || (cp -p /etc/passwd passwd.bak &&
+					  chmod 600 passwd.bak)
+	cmp -s group.bak /etc/group || (cp -p /etc/group group.bak &&
+					chmod 600 group.bak)
+        if [ -f /etc/shadow ] ; then
+	  cmp -s shadow.bak /etc/shadow || (cp -p /etc/shadow shadow.bak &&
+                                            chmod 600 shadow.bak)
+	fi
+        if [ -f /etc/gshadow ] ; then
+	  cmp -s gshadow.bak /etc/gshadow || (cp -p /etc/gshadow gshadow.bak &&
+					      chmod 600 gshadow.bak)
+	fi
+fi
+
+#
+# Check to see if any files are in lost+found directories and warn admin
+#
+# Get a list of the (potential) ext2, ext3, ext4 and xfs l+f directories
+# Discard errors, for systems not using any of these.
+lfdirs=`df -P --type=ext2 --type=ext3 --type=ext4 --type=xfs 2>/dev/null |
+	awk '/\/dev\// { print }' | sed -e 's/ [[:space:]]*/ /g'  |
+	while read mount block used avail perc mp; do
+		[ "$mp" = "/" ] && mp=""
+		echo "$mp/lost+found"
+	done`
+
+# Don't use space as a field separator
+oldifs="$IFS"
+IFS=`printf '\n\t'`
+
+for lfdir in $lfdirs; do
+# In each directory, look for files
+    if [ -d "$lfdir" ] ; then
+	more_lost_found=`ls -1  "$lfdir" 2>/dev/null | grep -v 'lost+found$' | sed 's/^/    /'`
+	if [ -n "$more_lost_found" ] ; then
+	    lost_found="$lost_found
+
+$lfdir:
+$more_lost_found"
+	    # NOTE: above weird line breaks in string are intentional!
+        fi
+    else
+# Do nothing for XFS filesystems they do not need to
+# have a lost and found dir
+        fs=`cat /proc/mounts | grep " ${lfdir%/lost+found} "`
+        case "$fs" in
+            ext*)
+        	no_lost_found="$no_lost_found
+$lfdir"
+                ;;
+            *)
+                ;;
+        esac
+    fi
+done
+
+# Restore IFS
+IFS="$oldifs"
+unset oldifs
+
+# NOTE: This might need to be configurable if systems abound
+# w/o lost+found out there to prevent giving out this warning
+# every day.
+if [ -n "$lost_found" ]; then
+    cat << EOF
+Files were found in lost+found directories. This is probably
+the result of a crash or bad shutdown, or possibly of a disk
+problem. These files may contain important information. You
+should examine them, and move them out of lost+found or delete
+them if they are not important.
+
+The following files were found:
+$lost_found
+EOF
+fi
+
+if [ -n "$no_lost_found" ]; then
+    cat << EOF
+Some local filesystems do not have lost+found directories. This
+means that these filesystems will not be able to recover
+lost files when the filesystem is checked after a crash.
+Consider creating a lost+found directory with mklost+found(8).
+
+The following lost+found directories were not available:
+$no_lost_found
+EOF
+fi
+
+#
+# Clean up lockfile
+#
+if [ -x /usr/bin/lockfile-create ] ; then
+    kill $LOCKTOUCHPID
+    lockfile-remove $LOCKFILE
+fi
diff --git a/debian/standard.monthly b/debian/standard.monthly
new file mode 100644
index 0000000..e5bfaeb
--- /dev/null
+++ b/debian/standard.monthly
@@ -0,0 +1,4 @@
+#!/bin/sh
+# /etc/cron.monthly/standard: standard monthly maintenance script
+
+# rotation of wtmp and btmp taken over by logrotate

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-cron/pkg-cron.git



More information about the Pkg-cron-devel mailing list