Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 20 Jul 2001 14:51:38 -0400
From:      Garance A Drosihn <drosih@rpi.edu>
To:        freebsd-audit@freebsd.org
Cc:        freebsd-print@bostonradio.org, Anton Berezin <tobez@tobez.org>
Subject:   Better error-processing in lpd's dofork() rtn
Message-ID:  <p05101015b77e2b80f910@[128.113.24.47]>
In-Reply-To: <p0510100db77d1591d36e@[128.113.24.47]>
References:  <3B5713AB.79322FDA@vangelderen.org> <20010719234413.A64433@heechee.tobez.org> <20010720001429.A65236@heechee.tobez.org> <p0510100db77d1591d36e@[128.113.24.47]>

next in thread | previous in thread | raw e-mail | index | archive | help
 From the "Re: initgroups unsolicited warning?" thread...

On 7/19/01, Garance A Drosihn wrote to -stable:
>
>At 12:14 AM +0200, Anton Berezin wrote:
>>  Here OK means that the caller checks initgroups() return code
>>  and acts appropriately.  NOK means that initgroups() is called
>>  without return code checking.
>        [...]
>>  usr.sbin/lpr/lpd/printjob.c		NOK
>
>Somehow I "just knew" that something in lpr would end up on a
>list of things with not-OK code...     :-)
>
>I'll try to look at that (just the call in lpd) if you wish.

Here is a patch which adds error-checking for initgroups, and
some other system-calls in the area.  When testing this error-
recovery, I found out that some of the error-checking already
in dofork() was dangerously wrong.  So, by the time I was done
here, I had basically rewritten dofork() -- not that there is
all that much there to rewrite...  This all works in my testing,
but please eyeball it and let me know if I've missed anything.

I hope to install this in -current soon, so it can sit there
for a week and still get MFC'ed into stable well before any
code freeze for 4.4-release.

note: you may get errors trying to apply this patch, because
my email client sometimes puts an extra blank as the first
character of some lines...

Index: lpd/printjob.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/lpr/lpd/printjob.c,v
retrieving revision 1.40
diff -u -r1.40 printjob.c
--- lpd/printjob.c	2001/07/15 00:09:46	1.40
+++ lpd/printjob.c	2001/07/20 18:35:56
@@ -77,8 +77,8 @@
  #include "pathnames.h"
  #include "extern.h"

-#define DORETURN	0	/* absorb fork error */
-#define DOABORT		1	/* abort if dofork fails */
+#define DORETURN	0	/* dofork should return "can't fork" error */
+#define DOABORT		1	/* dofork should just die if 
fork() fails */

  /*
   * Error tokens
@@ -106,6 +106,10 @@
  static char	 title[80];	/* ``pr'' title */
  static char      locale[80];    /* ``pr'' locale */

+/* these two are set from pp->daemon_user, but only if they are needed */
+static char	*daemon_uname;	/* set from pwd->pw_name */
+static int	 daemon_defgid;
+
  static char	class[32];		/* classification field */
  static char	origin_host[MAXHOSTNAMELEN];	/* user's host machine */
  				/* indentation size in static characters */
@@ -1408,11 +1412,24 @@
  static int
  dofork(const struct printer *pp, int action)
  {
-	register int i, forkpid;
+	int i, fail, forkpid;
  	struct passwd *pwd;

+	forkpid = -1;
+	if (daemon_uname == NULL) {
+		pwd = getpwuid(pp->daemon_user);
+		if (pwd == NULL) {
+			syslog(LOG_ERR, "%s: Can't lookup default 
daemon uid (%ld) in password file",
+			    pp->printer, pp->daemon_user);
+			goto error_ret;
+		}
+		daemon_uname = strdup(pwd->pw_name);
+		daemon_defgid = pwd->pw_gid;
+	}
+
  	for (i = 0; i < 20; i++) {
-		if ((forkpid = fork()) < 0) {
+		forkpid = fork();
+		if (forkpid < 0) {
  			sleep((unsigned)(i*i));
  			continue;
  		}
@@ -1420,25 +1437,49 @@
  		 * Child should run as daemon instead of root
  		 */
  		if (forkpid == 0) {
-			if ((pwd = getpwuid(pp->daemon_user)) == NULL) {
-				syslog(LOG_ERR, "Can't lookup default 
daemon uid (%ld) in password file",
-				    pp->daemon_user);
+			errno = 0;
+			fail = initgroups(daemon_uname, daemon_defgid);
+			if (fail) {
+				syslog(LOG_ERR, "%s: initgroups(%s,%u): %m",
+				    pp->printer, daemon_uname, daemon_defgid);
  				break;
  			}
-			initgroups(pwd->pw_name, pwd->pw_gid);
-			setgid(pwd->pw_gid);
-			setuid(pp->daemon_user);
+			fail = setgid(daemon_defgid);
+			if (fail) {
+				syslog(LOG_ERR, "%s: setgid(%u): %m",
+				    pp->printer, daemon_defgid);
+				break;
+			}
+			fail = setuid(pp->daemon_user);
+			if (fail) {
+				syslog(LOG_ERR, "%s: setuid(%ld): %m",
+				    pp->printer, pp->daemon_user);
+				break;
+			}
  		}
-		return(forkpid);
+		return forkpid;
+	}
+
+	/*
+	 * An error occurred.  If the error is in the child process, then
+	 * this routine must ALWAYS exit().  DORETURN only effects how
+	 * errors should be handled in the parent process.
+	 */
+error_ret:
+	if (forkpid == 0) {
+		syslog(LOG_ERR, "%s: dofork(): aborting child process...",
+		    pp->printer);
+		exit(1);
  	}
-	syslog(LOG_ERR, "can't fork");
+	syslog(LOG_ERR, "%s: dofork(): failure in fork", pp->printer);

+	sleep(1);		/* throttle errors, as a safety measure */
  	switch (action) {
  	case DORETURN:
-		return (-1);
+		return -1;
  	default:
  		syslog(LOG_ERR, "bad action (%d) to dofork", action);
-		/*FALL THRU*/
+		/* FALLTHROUGH */
  	case DOABORT:
  		exit(1);
  	}

-- 
Garance Alistair Drosehn            =   gad@eclipse.acs.rpi.edu
Senior Systems Programmer           or  gad@freebsd.org
Rensselaer Polytechnic Institute    or  drosih@rpi.edu

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-audit" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?p05101015b77e2b80f910>