Synopsis: dhclient vulnerability
NetBSD versions: NetBSD 1.4, 1.4.1, and 1.4.2
Thanks to: Todd Fries, Itojun, Ted Lemon
Reported in NetBSD Security Advisory: SA2000-008

--- usr.sbin/dhcp/common/options.c.orig	1999/03/30 03:10:46	1.1.1.9
+++ usr.sbin/dhcp/common/options.c	2000/06/28 18:47:02	1.1.1.9.2.1
@@ -47,6 +47,7 @@
 
 #define DHCP_OPTION_DATA
 #include "dhcpd.h"
+#include <ctype.h>
 
 /* Parse all available options out of the specified packet. */
 
@@ -439,7 +440,7 @@
 	int numhunk = -1;
 	int numelem = 0;
 	char fmtbuf [32];
-	int i, j;
+	int i, j, k;
 	char *op = optbuf;
 	unsigned char *dp = data;
 	struct in_addr foo;
@@ -471,11 +472,21 @@
 			numhunk = 0;
 			break;
 		      case 'X':
-			fmtbuf [i] = 'x';
+			for (k = 0; k < len; k++) {
+				if (!isascii (data [k]) ||
+				    !isprint (data [k]))
+					break;
+			}
+			if (k == len) {
+				fmtbuf [i] = 't';
+				numhunk = -2;
+			} else {
+				fmtbuf [i] = 'x';
+				hunksize++;
+				comma = ':';
+				numhunk = 0;
+			}
 			fmtbuf [i + 1] = 0;
-			hunksize++;
-			numhunk = 0;
-			comma = ':';
 			break;
 		      case 't':
 			fmtbuf [i] = 't';
@@ -539,8 +550,22 @@
 			      case 't':
 				if (emit_quotes)
 					*op++ = '"';
-				strcpy (op, (char *)dp);
-				op += strlen ((char *)dp);
+				for (; dp < data + len; dp++) {
+					if (!isascii (*dp) ||
+					    !isprint (*dp)) {
+						sprintf (op, "\\%03o",
+							 *dp);
+						op += 4;
+					} else if (*dp == '"' ||
+						   *dp == '\'' ||
+						   *dp == '$' ||
+						   *dp == '`' ||
+						   *dp == '\\') {
+						*op++ = '\\';
+						*op++ = *dp;
+					} else
+						*op++ = *dp;
+				}
 				if (emit_quotes)
 					*op++ = '"';
 				*op = 0;