Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 May 2002 14:35:47 +0200 (CEST)
From:      Thomas Quinot <thomas@cuivre.fr.eu.org>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   bin/38374: [patch] crontab environment variable parsing is broken
Message-ID:  <20020521123547.6EAB62C3D1@melusine.cuivre.fr.eu.org>

next in thread | raw e-mail | index | archive | help

>Number:         38374
>Category:       bin
>Synopsis:       [patch] crontab environment variable parsing is broken
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Tue May 21 05:40:02 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     Thomas Quinot
>Release:        FreeBSD 4.5-STABLE i386
>Organization:
>Environment:
System: FreeBSD melusine.cuivre.fr.eu.org 4.5-STABLE FreeBSD 4.5-STABLE #36: Sun Apr 28 22:12:31 CEST 2002 thomas@melusine.cuivre.fr.eu.org:/usr2/obj/usr2/src/sys/MELUSINE i386


	
>Description:
	load_env(), the function that attempts to parse a crontab
	line as an environment variable assignment, is broken
	and not conformant to its description in the manual page.
>How-To-Repeat:
	First:
	------

	Make a /etc/crontab entry containing
	*<tab>*<tab>*<tab>*<tab>*<tab>PATH=/some/path some_command
	(note that there are no spaces before the '=' sign).

	Note (using cron -x pars) that load_env will incorrectly
	report success parsing that line as a variable assignment.

	Note (looking at /var/log/cron) that this line has not been
	parsed as a command entry, and that some_command is never executed.

>Fix:
	Here is a proposed solution.

Index: env.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/cron/lib/env.c,v
retrieving revision 1.7.2.1
diff -u -r1.7.2.1 env.c
--- env.c	1 Jul 2000 10:35:07 -0000	1.7.2.1
+++ env.c	21 May 2002 12:33:52 -0000
@@ -144,7 +144,18 @@
 	long	filepos;
 	int	fileline;
 	char	name[MAX_ENVSTR], val[MAX_ENVSTR];
-	int	fields;
+	char	quotechar, *c, *str;
+	int	state;
+
+	/* The following states are traversed in order: */
+#define NAMEI	0	/* First char of NAME, may be quote */
+#define NAME	1	/* Subsequent chars of NAME */
+#define EQ1	2	/* After end of name, looking for '=' sign */
+#define EQ2	3	/* After '=', skipping whitespace */
+#define VALUEI	4	/* First char of VALUE, may be quote */
+#define VALUE	5	/* Subsequent chars of VALUE */
+#define FINI	6	/* All done, skipping trailing whitespace */
+#define ERROR	7	/* Error */
 
 	filepos = ftell(f);
 	fileline = LineNumber;
@@ -152,35 +163,77 @@
 	if (EOF == get_string(envstr, MAX_ENVSTR, f, "\n"))
 		return (ERR);
 
-	Debug(DPARS, ("load_env, read <%s>\n", envstr))
+	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 (isspace (*c)) {
+					state++;
+					c++;
+					break;
+				}
+				if (state == NAME && *c == '=') {
+					state++;
+					break;
+				}
+			}
+			*str++ = *c++;
+			break;
+
+		case EQ1:
+			if (*c == '=') {
+				state++;
+				str = val;
+				quotechar = '\0';
+			} else {
+				if (!isspace (*c))
+					state = ERROR;
+			}
+			c++;
+			break;
+		case EQ2:
+		case FINI:
+			if (isspace (*c))
+				c++;
+			else
+				state++;
+			break;
+		}
+	}
+	if (state != FINI && !(state == VALUE && !quotechar)) {
+		Debug(DPARS, ("load_env, parse error, state = %d\n", state))
 		fseek(f, filepos, 0);
 		Set_LineNum(fileline);
 		return (FALSE);
 	}
 
-	/* 2 fields from scanf; looks like an env setting
-	 */
-
-	/*
-	 * process value string
+	/* 2 fields from parser; looks like an env setting
 	 */
-	/*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)
 		return (FALSE);

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

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




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