summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth R Westerback <krw@cvs.openbsd.org>2013-12-21 18:23:11 +0000
committerKenneth R Westerback <krw@cvs.openbsd.org>2013-12-21 18:23:11 +0000
commit45834281aca02d043cae32052d109dd0c3246b74 (patch)
tree9dad449b8d25a62d9a89c8f8b7b3852e2ba65ba8
parent4e0df04c58f0b09f710e9f3b30418ed863704e65 (diff)
Introduce pretty_print_string() and use for printing both text
valued options and previously snprintf()'d filename and servername lease attributes. Should fix "string constant too long" errors when reading back a lease with filename or servername attributes with escaped characters. Reported by Rivo Nurges.
-rw-r--r--sbin/dhclient/dhclient.c29
-rw-r--r--sbin/dhclient/dhcpd.h3
-rw-r--r--sbin/dhclient/options.c91
3 files changed, 86 insertions, 37 deletions
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index 182472d39a8..9bc527c72ed 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhclient.c,v 1.279 2013/12/15 03:15:47 krw Exp $ */
+/* $OpenBSD: dhclient.c,v 1.280 2013/12/21 18:23:10 krw Exp $ */
/*
* Copyright 2004 Henning Brauer <henning@openbsd.org>
@@ -1761,15 +1761,36 @@ lease_as_string(char *type, struct client_lease *lease)
sz -= rslt;
if (lease->filename) {
- rslt = snprintf(p, sz, " filename \"%s\";\n", lease->filename);
+ rslt = snprintf(p, sz, " filename ");
+ if (rslt == -1 || rslt >= sz)
+ return (NULL);
+ p += rslt;
+ sz -= rslt;
+ rslt = pretty_print_string(p, sz, lease->filename,
+ strlen(lease->filename), 1);
+ if (rslt == -1 || rslt >= sz)
+ return (NULL);
+ p += rslt;
+ sz -= rslt;
+ rslt = snprintf(p, sz, ";\n");
if (rslt == -1 || rslt >= sz)
return (NULL);
p += rslt;
sz -= rslt;
}
if (lease->server_name) {
- rslt = snprintf(p, sz, " server-name \"%s\";\n",
- lease->server_name);
+ rslt = snprintf(p, sz, " server-name ");
+ if (rslt == -1 || rslt >= sz)
+ return (NULL);
+ p += rslt;
+ sz -= rslt;
+ rslt = pretty_print_string(p, sz, lease->server_name,
+ strlen(lease->server_name), 1);
+ if (rslt == -1 || rslt >= sz)
+ return (NULL);
+ p += rslt;
+ sz -= rslt;
+ rslt = snprintf(p, sz, ";\n");
if (rslt == -1 || rslt >= sz)
return (NULL);
p += rslt;
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index 3229c68775c..8d6c382b23e 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dhcpd.h,v 1.126 2013/12/12 00:22:06 krw Exp $ */
+/* $OpenBSD: dhcpd.h,v 1.127 2013/12/21 18:23:10 krw Exp $ */
/*
* Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
@@ -210,6 +210,7 @@ extern volatile sig_atomic_t quit;
/* options.c */
int cons_options(struct option_data *);
char *pretty_print_option(unsigned int, struct option_data *, int);
+int pretty_print_string(unsigned char *, size_t, unsigned char *, size_t, int);
void do_packet(unsigned int, struct in_addr, struct ether_addr *);
/* errwarn.c */
diff --git a/sbin/dhclient/options.c b/sbin/dhclient/options.c
index 59b0c2b4aed..bc8db44a82e 100644
--- a/sbin/dhclient/options.c
+++ b/sbin/dhclient/options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: options.c,v 1.61 2013/12/18 00:37:59 krw Exp $ */
+/* $OpenBSD: options.c,v 1.62 2013/12/21 18:23:10 krw Exp $ */
/* DHCP options parsing and reassembly. */
@@ -191,6 +191,61 @@ cons_options(struct option_data *options)
}
/*
+ * Use vis() to encode characters of src and append encoded characters onto
+ * dst. Also encode ", ', $, ` and \, to ensure resulting strings can be
+ * represented as '"' delimited strings and safely passed to scripts. Surround
+ * result with double quotes if emit_punct is true.
+ */
+int
+pretty_print_string(unsigned char *dst, size_t dstlen, unsigned char *src,
+ size_t srclen, int emit_punct)
+{
+ char visbuf[5];
+ unsigned char *origsrc = src;
+ int opcount = 0, total = 0;
+
+ if (emit_punct) {
+ opcount = snprintf(dst, dstlen, "\"");
+ if (opcount == -1)
+ return (-1);
+ total += opcount;
+ if (opcount >= dstlen)
+ goto done;
+ dstlen -= opcount;
+ dst += opcount;
+ }
+
+ for (; src < origsrc + srclen; src++) {
+ if (*src && strchr("\"'$`\\", *src))
+ opcount = snprintf(dst, dstlen, "\\%c", *src);
+ else {
+ vis(visbuf, *src, VIS_OCTAL, *src+1);
+ opcount = snprintf(dst, dstlen, "%s", visbuf);
+ }
+ if (opcount == -1)
+ return (-1);
+ total += opcount;
+ if (opcount >= dstlen)
+ goto done;
+ dstlen -= opcount;
+ dst += opcount;
+ }
+
+ if (emit_punct) {
+ opcount = snprintf(dst, dstlen, "\"");
+ if (opcount == -1)
+ return (-1);
+ total += opcount;
+ if (opcount >= dstlen)
+ goto done;
+ dstlen -= opcount;
+ dst += opcount;
+ }
+done:
+ return (total);
+}
+
+/*
* Format the specified option so that a human can easily read it.
*/
char *
@@ -199,7 +254,7 @@ pretty_print_option(unsigned int code, struct option_data *option,
{
static char optbuf[32768]; /* XXX */
int hunksize = 0, numhunk = -1, numelem = 0;
- char fmtbuf[32], visbuf[5], *op = optbuf;
+ char fmtbuf[32], *op = optbuf;
int i, j, k, opleft = sizeof(optbuf);
unsigned char *data = option->data;
unsigned char *dp = data;
@@ -321,36 +376,8 @@ pretty_print_option(unsigned int code, struct option_data *option,
for (j = 0; j < numelem; j++) {
switch (fmtbuf[j]) {
case 't':
- if (emit_punct) {
- opcount = snprintf(op, opleft, "\"");
- if (opcount >= opleft || opcount == -1)
- goto toobig;
- opleft -= opcount;
- op += opcount;
- }
- for (; dp < data + len; dp++) {
- if (*dp && strchr("\"'$`\\", *dp))
- opcount = snprintf(op, opleft,
- "\\%c", *dp);
- else {
- vis(visbuf, *dp, VIS_OCTAL,
- *dp+1);
- opcount = snprintf(op, opleft,
- "%s", visbuf);
- }
- if (opcount >= opleft || opcount == -1)
- goto toobig;
- opleft -= opcount;
- op += opcount;
- }
- if (emit_punct) {
- opcount = snprintf(op, opleft, "\"");
- if (opcount >= opleft || opcount == -1)
- goto toobig;
- opleft -= opcount;
- op += opcount;
- }
- opcount = 0; /* Already moved dp & op. */
+ opcount = pretty_print_string(op, opleft,
+ dp, len, emit_punct);
break;
case 'I':
foo.s_addr = htonl(getULong(dp));