From: Roy Marples Date: Mon, 7 Jan 2008 18:14:51 +0000 (+0000) Subject: Stop using static inflexable buffers when cleaning metas and reading files. X-Git-Tag: v3.2.3~121 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b5d0d901da7cd53ea7f2b3a21c4ef6cbb4ce69c0;p=thirdparty%2Fdhcpcd.git Stop using static inflexable buffers when cleaning metas and reading files. --- diff --git a/common.c b/common.c index 815933d1..2330889f 100644 --- a/common.c +++ b/common.c @@ -41,6 +41,33 @@ #include "common.h" #include "logger.h" +/* Handy routine to read very long lines in text files. + * This means we read the whole line and avoid any nasty buffer overflows. */ +char *getline (FILE *fp) +{ + char *line = NULL; + char *p; + size_t len = 0; + size_t last = 0; + + if (feof (fp)) + return (NULL); + + do { + len += BUFSIZ; + line = xrealloc (line, sizeof (char) * len); + p = line + last; + fgets (p, BUFSIZ, fp); + last += strlen (p); + } while (! feof (fp) && line[last - 1] != '\n'); + + /* Trim the trailing newline */ + if (line[--last] == '\n') + line[last] = '\0'; + + return (line); +} + /* OK, this should be in dhcpcd.c * It's here to make dhcpcd more readable */ #ifdef __linux__ @@ -174,6 +201,17 @@ void *xmalloc (size_t s) exit (EXIT_FAILURE); } +void *xrealloc (void *ptr, size_t s) +{ + void *value = realloc (ptr, s); + + if (value) + return (value); + + logger (LOG_ERR, "memory exhausted"); + exit (EXIT_FAILURE); +} + char *xstrdup (const char *str) { char *value; diff --git a/common.h b/common.h index 727eb178..a4a0a1ae 100644 --- a/common.h +++ b/common.h @@ -30,6 +30,7 @@ /* string.h pulls in features.h so the below define checks work */ #include +#include #include /* Only GLIBC doesn't support strlcpy */ @@ -44,9 +45,11 @@ void srandomdev (void); #endif void close_fds (void); +char *getline (FILE *fp); int get_time (struct timeval *tp); long uptime (void); void writepid (int fd, pid_t pid); +void *xrealloc (void *ptr, size_t size); void *xmalloc (size_t size); char *xstrdup (const char *str); diff --git a/configure.c b/configure.c index c2d27d4f..44551fdd 100644 --- a/configure.c +++ b/configure.c @@ -209,13 +209,12 @@ static void restore_resolv (const char *ifname) } #ifdef ENABLE_NTP -#define BUFFERSIZE 1024 static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) { FILE *f; address_t *address; char *a; - char *buffer; + char *line; int tomatch = 0; char *token; bool ntp = false; @@ -231,16 +230,18 @@ static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) return -1; } } else { - buffer = xmalloc (sizeof (char) * BUFFERSIZE); - memset (buffer, 0, BUFFERSIZE); - while (fgets (buffer, BUFFERSIZE, f)) { - a = buffer; + while ((line = getline (f))) { + a = line; token = strsep (&a, " "); - if (! token || strcmp (token, "server") != 0) + if (! token || strcmp (token, "server") != 0) { + free (line); continue; + } - if ((token = strsep (&a, " \n")) == NULL) + if ((token = strsep (&a, " \n")) == NULL) { + free (line); continue; + } for (address = dhcp->ntpservers; address; address = address->next) if (strcmp (token, inet_ntoa (address->address)) == 0) { @@ -248,10 +249,11 @@ static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) break; } - if (tomatch == 0) + if (tomatch == 0) { + free (line); break; + } } - free (buffer); fclose (f); /* File has the same name servers that we do, so no need to restart ntp */ diff --git a/info.c b/info.c index 4da29395..0a9766cd 100644 --- a/info.c +++ b/info.c @@ -43,33 +43,49 @@ #include "info.h" #ifdef ENABLE_INFO -#define BUFFERSIZE 1024 +/* Create a malloced string of cstr, changing ' to '\'' + * so the contents work in a shell */ static char *cleanmetas (const char *cstr) { - /* The largest single element we can have is 256 bytes according to the RFC, - so this buffer size should be safe even if it's all ' */ - static char buffer[BUFFERSIZE]; - char *b = buffer; + const char *p = cstr; + char *new; + char *n; + size_t len; - memset (buffer, 0, sizeof (buffer)); - if (cstr == NULL || strlen (cstr) == 0) - return b; + if (cstr == NULL || (len = strlen (cstr)) == 0) + return (xstrdup ("")); + n = new = xmalloc (sizeof (char) * len + 1); do - if (*cstr == 39) { - *b++ = '\''; - *b++ = '\\'; - *b++ = '\''; - *b++ = '\''; + if (*p == '\'') { + size_t pos = n - new; + len += 3; + new = xrealloc (new, sizeof (char) * len + 1); + n = new + pos; + *n++ = '\''; + *n++ = '\\'; + *n++ = '\''; + *n++ = '\''; } else - *b++ = *cstr; - while (*cstr++); + *n++ = *p; + while (*p++); - *b++ = 0; - b = buffer; + /* Terminate the sucker */ + *n++ = '\0'; - return b; + return (new); +} + +static void print_clean (FILE *f, const char *name, const char *value) { + char *clean; + + if (! value) + return; + + clean = cleanmetas (value); + fprintf (f, "%s='%s'\n", name, clean); + free (clean); } bool write_info(const interface_t *iface, const dhcp_t *dhcp, @@ -129,14 +145,9 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp, fprintf (f, "'\n"); } - if (dhcp->hostname) - fprintf (f, "HOSTNAME='%s'\n", cleanmetas (dhcp->hostname)); - - if (dhcp->dnsdomain) - fprintf (f, "DNSDOMAIN='%s'\n", cleanmetas (dhcp->dnsdomain)); - - if (dhcp->dnssearch) - fprintf (f, "DNSSEARCH='%s'\n", cleanmetas (dhcp->dnssearch)); + print_clean (f, "HOSTNAME", dhcp->hostname); + print_clean (f, "DNSDOMAIN", dhcp->dnsdomain); + print_clean (f, "DNSSEARCH", dhcp->dnssearch); if (dhcp->dnsservers) { fprintf (f, "DNSSERVERS='"); @@ -152,7 +163,7 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp, fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags); fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1); fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2); - fprintf (f, "FQDNHOSTNAME='%s'\n", dhcp->fqdn->name); + print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name); } if (dhcp->ntpservers) { @@ -165,9 +176,7 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp, fprintf (f, "'\n"); } - if (dhcp->nisdomain) - fprintf (f, "NISDOMAIN='%s'\n", cleanmetas (dhcp->nisdomain)); - + print_clean (f, "NISDOMAIN", dhcp->nisdomain); if (dhcp->nisservers) { fprintf (f, "NISSERVERS='"); for (address = dhcp->nisservers; address; address = address->next) { @@ -178,16 +187,14 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp, fprintf (f, "'\n"); } - if (dhcp->rootpath) - fprintf (f, "ROOTPATH='%s'\n", cleanmetas (dhcp->rootpath)); - - if (dhcp->sipservers) - fprintf (f, "SIPSERVERS='%s'\n", cleanmetas (dhcp->sipservers)); + print_clean (f, "ROOTPATH", dhcp->rootpath); + print_clean (f, "SIPSERVERS", dhcp->sipservers); if (dhcp->serveraddress.s_addr) fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); if (dhcp->servername[0]) - fprintf (f, "DHCPSNAME='%s'\n", cleanmetas (dhcp->servername)); + print_clean (f, "DHCPSNAME", dhcp->servername); + if (! options->doinform && dhcp->address.s_addr) { if (! options->test) fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom); @@ -195,10 +202,13 @@ bool write_info(const interface_t *iface, const dhcp_t *dhcp, fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); } - fprintf (f, "INTERFACE='%s'\n", iface->name); - fprintf (f, "CLASSID='%s'\n", cleanmetas (options->classid)); - if (options->clientid_len > 0) - fprintf (f, "CLIENTID='00:%s'\n", cleanmetas (options->clientid)); + print_clean (f, "INTERFACE", iface->name); + print_clean (f, "CLASSID", options->classid); + if (options->clientid_len > 0) { + char *clean = cleanmetas (options->clientid); + fprintf (f, "CLIENTID='00:%s'\n", clean); + free (clean); + } #ifdef ENABLE_DUID else if (iface->duid_length > 0 && options->clientid_len != -1) { unsigned char *duid; @@ -327,7 +337,7 @@ static bool parse_addresses (address_t **address, char *value, const char *var) bool read_info (const interface_t *iface, dhcp_t *dhcp) { FILE *fp; - char *buffer; + char *line; char *var; char *value; char *p; @@ -346,10 +356,8 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) dhcp->frominfo = true; - buffer = xmalloc (sizeof (char) * BUFFERSIZE); - memset (buffer, 0, BUFFERSIZE); - while ((fgets (buffer, BUFFERSIZE, fp))) { - var = buffer; + while ((line = getline (fp))) { + var = line; /* Strip leading spaces/tabs */ while ((*var == ' ') || (*var == '\t')) @@ -360,14 +368,13 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) if (*p == '\n') *p = 0; - /* Skip comments */ if (*var == '#') - continue; + goto next; /* If we don't have an equals sign then skip it */ if (! (p = strchr (var, '='))) - continue; + goto next; /* Terminate the = so we have two strings */ *p = 0; @@ -382,7 +389,7 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) /* Don't process null vars or values */ if (! *var || ! *value) - continue; + goto next; if (strcmp (var, "IPADDR") == 0) parse_address (&dhcp->address, value, "IPADDR"); @@ -404,7 +411,7 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) if (! dest || ! net || ! gate) { logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route", dest, net, gate); - continue; + goto next; } /* See if we can create a route */ @@ -414,19 +421,19 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address", dest); free (route); - continue; + goto next; } if (inet_aton (dest, &route->netmask) == 0) { logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address", net); free (route); - continue; + goto next; } if (inet_aton (dest, &route->gateway) == 0) { logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address", gate); free (route); - continue; + goto next; } /* OK, now add our route */ @@ -482,10 +489,12 @@ bool read_info (const interface_t *iface, dhcp_t *dhcp) parse_uint (&dhcp->renewaltime, value, "RENEWALTIME"); else if (strcmp (var, "REBINDTIME") == 0) parse_uint (&dhcp->rebindtime, value, "REBINDTIME"); + +next: + free (line); } fclose (fp); - free (buffer); return (true); }