diff --git a/src/cache.c b/src/cache.c index 32192c1..aec9a0b 100644 --- a/src/cache.c +++ b/src/cache.c @@ -1407,9 +1407,10 @@ static int eatspace(FILE *f) } } -static int gettok(FILE *f, char *token) +static int gettok(FILE *f, char *token, size_t buffsz) { - int c, count = 0; + int c; + unsigned int count = 0; while (1) { @@ -1422,7 +1423,7 @@ static int gettok(FILE *f, char *token) return eatspace(f); } - if (count < (MAXDNAMESTR - 1)) + if (count < (buffsz - 1)) { token[count++] = c; token[count] = 0; @@ -1447,7 +1448,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr lineno += eatspace(f); - while ((atnl = gettok(f, token)) != -1) + while ((atnl = gettok(f, token, MAXDNAMESTR)) != -1) { if (inet_pton(AF_INET, token, &addr) > 0) { @@ -1465,7 +1466,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr { my_syslog(LOG_ERR, _("bad address at %s line %d"), filename, lineno); while (atnl == 0) - atnl = gettok(f, token); + atnl = gettok(f, token, MAXDNAMESTR); lineno += atnl; continue; } @@ -1483,7 +1484,7 @@ int read_hostsfile(char *filename, unsigned int index, int cache_size, struct cr int fqdn, nomem; char *canon; - if ((atnl = gettok(f, token)) == -1) + if ((atnl = gettok(f, token, MAXDNAMESTR)) == -1) break; fqdn = !!strchr(token, '.'); diff --git a/src/dhcp.c b/src/dhcp.c index 3f8dc29..6546741 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -925,7 +925,8 @@ void dhcp_read_ethers(void) { FILE *f = fopen(ETHERSFILE, "r"); unsigned int flags; - char *buff = daemon->namebuff; + size_t linesz = 0; + char *line = NULL; char *ip, *cp; struct in_addr addr; unsigned char hwaddr[ETHER_ADDR_LEN]; @@ -958,22 +959,22 @@ void dhcp_read_ethers(void) up = &config->next; } - while (fgets(buff, MAXDNAMESTR, f)) + while (get_line_alloc(f, &line, &linesz)) { char *host = NULL; lineno++; - while (strlen(buff) > 0 && isspace((unsigned char)buff[strlen(buff)-1])) - buff[strlen(buff)-1] = 0; + while (strlen(line) > 0 && isspace((unsigned char)line[strlen(line)-1])) + line[strlen(line)-1] = 0; - if ((*buff == '#') || (*buff == '+') || (*buff == 0)) + if ((*line == '#') || (*line == '+') || (*line == 0)) continue; - for (ip = buff; *ip && !isspace((unsigned char)*ip); ip++); + for (ip = line; *ip && !isspace((unsigned char)*ip); ip++); for(; *ip && isspace((unsigned char)*ip); ip++) *ip = 0; - if (!*ip || parse_hex(buff, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN) + if (!*ip || parse_hex(line, hwaddr, ETHER_ADDR_LEN, NULL, NULL) != ETHER_ADDR_LEN) { my_syslog(MS_DHCP | LOG_ERR, _("bad line at %s line %d"), ETHERSFILE, lineno); continue; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 9bec05b..447b940 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -1516,6 +1516,7 @@ void *whine_malloc_real(const char *func, unsigned int line, size_t size); void *whine_realloc_real(const char *wrapper, const char *func, unsigned int line, void *ptr, size_t size); int expand_buf_real(const char *func, unsigned int line, struct iovec *iov, size_t size); int expand_workspace_real(const char *func, unsigned int line, unsigned char ***wkspc, int *szp, int new); +int get_line_alloc(FILE *f, char **buffp, size_t *sizep); int sa_len(union mysockaddr *addr); int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2); int sockaddr_isnull(const union mysockaddr *s); diff --git a/src/helper.c b/src/helper.c index a594c26..30a7197 100644 --- a/src/helper.c +++ b/src/helper.c @@ -533,18 +533,12 @@ int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd) close(pipeout[0]); else { - while (fgets(daemon->packet, daemon->packet_buff_sz, fp)) - { - /* do not include new lines, log will append them */ - size_t len = strlen(daemon->packet); - if (len > 0) - { - --len; - if (daemon->packet[len] == '\n') - daemon->packet[len] = 0; - } - send_event(event_fd, EVENT_SCRIPT_LOG, 0, daemon->packet); - } + char *line = NULL; + size_t linesz = 0; + + while (get_line_alloc(fp, &line, &linesz)) + send_event(event_fd, EVENT_SCRIPT_LOG, 0, line); + fclose(fp); } } diff --git a/src/network.c b/src/network.c index 8985e84..9015b34 100644 --- a/src/network.c +++ b/src/network.c @@ -1699,19 +1699,19 @@ void check_servers(int no_loop_check) int reload_servers(char *fname) { FILE *f; - char *line; + char *line = NULL; + size_t linesz = 0; int gotone = 0; - /* buff happens to be MAXDNAMESTR long... */ if (!(f = fopen(fname, "r"))) { my_syslog(LOG_ERR, _("failed to read %s: %s"), fname, strerror(errno)); return 0; } - + mark_servers(SERV_FROM_RESOLV); - - while ((line = fgets(daemon->namebuff, MAXDNAMESTR, f))) + + while (get_line_alloc(f, &line, &linesz)) { union mysockaddr addr, source_addr; char *token = strtok(line, " \t\n\r"); diff --git a/src/option.c b/src/option.c index 2bb9e91..1ba8335 100644 --- a/src/option.c +++ b/src/option.c @@ -5471,9 +5471,20 @@ err: static void read_file(char *file, FILE *f, int hard_opt, int from_script) { volatile int lineno = 0; - char *buff = daemon->namebuff; + char *buff; + size_t buffsz; + + /* Memory allocation failure longjmps here if mem_recover == 1 */ + if (hard_opt != 0) + { + setjmp(mem_jmp); + mem_recover = 1; + } - while (fgets(buff, MAXDNAMESTR, f)) + buff = NULL; + buffsz = 0; + + while (get_line_alloc(f, &buff, &buffsz)) { int white, i; volatile int option; @@ -5481,15 +5492,7 @@ static void read_file(char *file, FILE *f, int hard_opt, int from_script) size_t len; option = (hard_opt == LOPT_REV_SERV) ? 0 : hard_opt; - - /* Memory allocation failure longjmps here if mem_recover == 1 */ - if (option != 0 || hard_opt == LOPT_REV_SERV) - { - if (setjmp(mem_jmp)) - continue; - mem_recover = 1; - } - + arg = NULL; lineno++; errmess = NULL; @@ -5949,16 +5952,15 @@ void reread_dhcp(void) void read_opts(int argc, char **argv, char *compile_opts) { size_t argbuf_size = 300; - char *argbuf = opt_malloc(argbuf_size); - char *buff = opt_malloc(MAXDNAMESTR+1); + char *argbuf = safe_malloc(argbuf_size); int option, testmode = 0; char *arg, *conffile = NULL; opterr = 0; - + daemon = opt_malloc(sizeof(struct daemon)); memset(daemon, 0, sizeof(struct daemon)); - daemon->namebuff = buff; + daemon->namebuff = safe_malloc(MAXDNAMESTR+1); daemon->workspacename = safe_malloc(MAXDNAMESTR+1); daemon->addrbuff = safe_malloc(ADDRSTRLEN); @@ -6197,9 +6199,9 @@ void read_opts(int argc, char **argv, char *compile_opts) /* create default, if not specified */ if (daemon->authserver && !daemon->hostmaster) { - strcpy(buff, "hostmaster."); - strcat(buff, daemon->authserver); - daemon->hostmaster = opt_string_alloc(buff); + strcpy(daemon->namebuff, "hostmaster."); + strncat(daemon->namebuff, daemon->authserver, MAXDNAMESTR - strlen(daemon->namebuff)); + daemon->hostmaster = opt_string_alloc(daemon->namebuff); } if (!daemon->dhcp_pxe_vendors) @@ -6214,11 +6216,11 @@ void read_opts(int argc, char **argv, char *compile_opts) { struct mx_srv_record *mx; - if (gethostname(buff, MAXDNAMESTR) == -1) + if (gethostname(daemon->namebuff, MAXDNAMESTR) == -1) die(_("cannot get host-name: %s"), NULL, EC_MISC); for (mx = daemon->mxnames; mx; mx = mx->next) - if (!mx->issrv && hostname_isequal(mx->name, buff)) + if (!mx->issrv && hostname_isequal(mx->name, daemon->namebuff)) break; if ((daemon->mxtarget || option_bool(OPT_LOCALMX)) && !mx) @@ -6227,12 +6229,12 @@ void read_opts(int argc, char **argv, char *compile_opts) mx->next = daemon->mxnames; mx->issrv = 0; mx->target = NULL; - mx->name = opt_string_alloc(buff); + mx->name = opt_string_alloc(daemon->namebuff); daemon->mxnames = mx; } if (!daemon->mxtarget) - daemon->mxtarget = opt_string_alloc(buff); + daemon->mxtarget = opt_string_alloc(daemon->namebuff); for (mx = daemon->mxnames; mx; mx = mx->next) if (!mx->issrv && !mx->target) @@ -6247,7 +6249,8 @@ void read_opts(int argc, char **argv, char *compile_opts) if (option_bool(OPT_RESOLV_DOMAIN)) { - char *line; + char *line = NULL; + size_t linesz = 0; FILE *f; if (option_bool(OPT_NO_RESOLV) || @@ -6258,7 +6261,7 @@ void read_opts(int argc, char **argv, char *compile_opts) if (!(f = fopen((daemon->resolv_files)->name, "r"))) die(_("failed to read %s: %s"), (daemon->resolv_files)->name, EC_FILE); - while ((line = fgets(buff, MAXDNAMESTR, f))) + while (get_line_alloc(f, &line, &linesz)) { char *token = strtok(line, " \t\n\r"); @@ -6278,7 +6281,7 @@ void read_opts(int argc, char **argv, char *compile_opts) if (daemon->domain_suffix) { - /* add domain for any srv record without one. */ + /* add domain for any srv record without one. */ struct mx_srv_record *srv; for (srv = daemon->mxnames; srv; srv = srv->next) @@ -6288,11 +6291,11 @@ void read_opts(int argc, char **argv, char *compile_opts) { if (strlen(srv->name) + 1 + strlen(daemon->domain_suffix) > MAXDNAMESTR) die(_("srv-host name %s too long after domain appended"), srv->name, EC_MISC); - strcpy(buff, srv->name); - strcat(buff, "."); - strcat(buff, daemon->domain_suffix); + strcpy(daemon->namebuff, srv->name); + strcat(daemon->namebuff, "."); + strcat(daemon->namebuff, daemon->domain_suffix); free(srv->name); - if (!(srv->name = canonicalise_opt(buff))) + if (!(srv->name = canonicalise_opt(daemon->namebuff))) die(_("bad srv-host name %s after domain appended"), srv->name, EC_MISC); } } diff --git a/src/util.c b/src/util.c index fe6624c..b41b7c1 100644 --- a/src/util.c +++ b/src/util.c @@ -1027,3 +1027,53 @@ void free_real(const char *func, unsigned int line, void *ptr) free(ptr); } } + +/* get lines from f, expand buffer as required. Buffer is freed when + EOF reached and we return zero. */ +int get_line_alloc(FILE *f, char **buffp, size_t *sizep) +{ + char c; + size_t cnt = 0; + char *buff = *buffp; + + while (1) { + c = getc(f); + + if (cnt == *sizep) + { + void *new; + + if ((new = whine_realloc(*buffp, cnt + 1024))) + { + buff = *buffp = new; + *sizep = cnt + 1024; + } + else + { + /* allocation failed, ignore line. Whine_realloc will have complained. */ + while (c != '\n' && c != EOF) + c = getc(f); + + cnt = 0; + continue; + } + } + + buff[cnt] = 0; + + if (c == '\n') + return 1; + + if (c == EOF) /* handle last line with no '\n' */ + { + /* handle last line without '\n' */ + if (cnt != 0) + return 1; + + free(buff); + return 0; + } + + buff[cnt++] = c; + } +}