diff options
author | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-12-21 18:23:11 +0000 |
---|---|---|
committer | Kenneth R Westerback <krw@cvs.openbsd.org> | 2013-12-21 18:23:11 +0000 |
commit | 45834281aca02d043cae32052d109dd0c3246b74 (patch) | |
tree | 9dad449b8d25a62d9a89c8f8b7b3852e2ba65ba8 | |
parent | 4e0df04c58f0b09f710e9f3b30418ed863704e65 (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.c | 29 | ||||
-rw-r--r-- | sbin/dhclient/dhcpd.h | 3 | ||||
-rw-r--r-- | sbin/dhclient/options.c | 91 |
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)); |