bin/97002: crond fails quietly if /usr/sbin/sendmail is missing

John Hood jh at sirocco.sandstorm.net
Mon May 8 23:50:30 UTC 2006


>Number:         97002
>Category:       bin
>Synopsis:       crond fails quietly if /usr/sbin/sendmail is missing
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon May 08 23:50:10 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     John Hood
>Release:        FreeBSD 6.0-RELEASE i386
>Organization:
Sandstorm Enterprises, Inc.
>Environment:
System: FreeBSD faster.sandstorm.net 6.0-RELEASE FreeBSD 6.0-RELEASE #0: Thu Nov  3 09:36:13 UTC 2005     root at x64.samsco.home:/usr/obj/usr/src/sys/GENERIC  i386

>Description:

If cron's job-running child fails to exec /usr/sbin/sendmail and the
cron job writes to stdout, hijinks ensue (thanks for the phrase,
regis!)  The cron job writes on a pipe to a crond process, which
copies it to another pipe to what should be a sendmail.  If this exits
early and the pipe is closed, the cron child process gets killed with
a SIGPIPE.  Since cron delays running sendmail and doing any of this
until it's received something from the cron job, the cron job executes
before any of this happens.  If the cron job writes again on *its*
pipe, it gets a SIGPIPE too, and may fail mysteriously.  There's code
in cron to log mail failures, but the SIGPIPE prevents that code from
running.

>How-To-Repeat:

rm /usr/sbin/sendmail
echo '* * * * * tee /tmp/termcap < /etc/termcap' | crontab -
tail -f /var/log/cron
ls -l /etc/termcap /tmp/termcap

>Fix:

Patch to fix this problem by ignoring SIGPIPE, add logging of failure
to exec /usr/sbin/sendmail, and minor cleanup of logging functions to
get *that* to work.

diff -r -u /usr/src/usr.sbin/cron/Makefile.inc ./Makefile.inc
Only in ./cron: cron
Only in ./cron: cron.8.gz
Only in ./cron: cron.o
Only in ./cron: database.o
diff -r -u /usr/src/usr.sbin/cron/cron/do_command.c ./cron/do_command.c
--- /usr/src/usr.sbin/cron/cron/do_command.c	Sun May 16 15:29:33 2004
+++ ./cron/do_command.c	Mon May  8 17:12:02 2006
@@ -26,9 +26,6 @@
 #if defined(sequent)
 # include <sys/universe.h>
 #endif
-#if defined(SYSLOG)
-# include <syslog.h>
-#endif
 #if defined(LOGIN_CAP)
 # include <login_cap.h>
 #endif
@@ -187,9 +184,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.
 		 */
@@ -388,6 +383,8 @@
 			register FILE	*mail;
 			register int	bytes = 1;
 			int		status = 0;
+
+			signal(SIGPIPE, SIG_IGN);
 
 			Debug(DPROC|DEXT,
 				("[%d] got data (%x:%c) from grandchild\n",
Only in ./cron: do_command.o
Only in ./cron: job.o
diff -r -u /usr/src/usr.sbin/cron/cron/popen.c ./cron/popen.c
--- /usr/src/usr.sbin/cron/cron/popen.c	Tue Feb  5 21:00:07 2002
+++ ./cron/popen.c	Mon May  8 16:01:24 2006
@@ -35,9 +35,6 @@
 #include <sys/signal.h>
 #include <fcntl.h>
 #include <paths.h>
-#if defined(SYSLOG)
-# include <syslog.h>
-#endif
 #if defined(LOGIN_CAP)
 # include <login_cap.h>
 #endif
@@ -65,6 +62,7 @@
 	PID_T pid;
 	char *usernm;
 	char *argv[MAX_ARGS + 1];
+	int status;
 # if defined(LOGIN_CAP)
 	struct passwd	*pwd;
 	login_cap_t *lc;
@@ -112,7 +110,7 @@
 #endif
 
 	iop = NULL;
-	switch(pid = vfork()) {
+	switch(pid = fork()) {
 	case -1:			/* error */
 		(void)close(pdes[0]);
 		(void)close(pdes[1]);
@@ -120,10 +118,7 @@
 		/* NOTREACHED */
 	case 0:				/* child */
 		if (e != NULL) {
-#ifdef SYSLOG
-			closelog();
-#endif
-
+			log_close();
 			/* get new pgrp, void tty, etc.
 			 */
 			(void) setsid();
@@ -173,7 +168,7 @@
 				(void) endpwent();
 # endif
 				/* set our directory, uid and gid.  Set gid first,
-				 * since once we set uid, we've lost root privledges.
+				 * since once we set uid, we've lost root privileges.
 				 */
 				setgid(e->gid);
 # if defined(BSD)
@@ -193,6 +188,7 @@
 #else
 		execvp(argv[0], argv);
 #endif
+		log_it("CRON", getpid(), "CAN'T EXEC", argv[0]);
 		_exit(1);
 	}
 	/* parent; assume fdopen can't fail...  */
Only in ./cron: popen.o
Only in ./cron: user.o
Only in ./crontab: crontab
Only in ./crontab: crontab.1.gz
Only in ./crontab: crontab.5.gz
Only in ./crontab: crontab.o
Only in ./lib: entry.o
Only in ./lib: env.o
Only in ./lib: libcron.a
diff -r -u /usr/src/usr.sbin/cron/lib/misc.c ./lib/misc.c
--- /usr/src/usr.sbin/cron/lib/misc.c	Wed Feb  9 08:02:43 2005
+++ ./lib/misc.c	Mon May  8 14:37:33 2006
@@ -49,6 +49,11 @@
 
 static int		LogFD = ERR;
 
+#if defined(SYSLOG)
+static int		syslog_open = 0;
+#endif
+
+
 
 int
 strcmp_until(left, right, until)
@@ -459,10 +464,6 @@
 	register struct tm	*t = localtime(&now);
 #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.
 	 */
@@ -535,10 +536,18 @@
 
 void
 log_close() {
+#if defined(LOG_FILE)
 	if (LogFD != ERR) {
 		close(LogFD);
 		LogFD = ERR;
 	}
+#endif
+#ifdef SYSLOG
+	if (syslog_open) {
+		closelog();
+		syslog_open = 0;
+	}
+#endif
 }
 
 
Only in ./lib: misc.o

>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list