12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199 |
- From 59e470381f84f2fdf0640c7bc67827f3f0c64784 Mon Sep 17 00:00:00 2001
- From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
- Date: Fri, 2 Nov 2018 22:39:39 +0000
- Subject: [PATCH 11/32] Free config file values on parsing errors.
- This time I have a little bit more controversal patches. But I think
- still useful. They fixes memory leaks that might occur in some cases.
- Most dnsmasq errors is fatal, so it does not matter. But some are not.
- Some parts are reloaded on SIGHUP signal, so it might leak more than once.
- Some example when it changes the failures. Use dhcp-options file with
- this content:
- tag:error,vendor:redhat
- option:ntp-server,1.2.3.4.5
- option6:ntp-server,[:::]
- Is not fatal and dnsmasq will start. On each reload command, it would
- leak some memory. I validated it using valgrind --leak-check=full
- dnsmasq -d. This patch fixes it. It introduces something that might be
- considered constructor and destructor of selected structures.
- Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
- ---
- src/option.c | 533 ++++++++++++++++++++++++++++++++++-----------------
- 1 file changed, 352 insertions(+), 181 deletions(-)
- --- a/src/option.c
- +++ b/src/option.c
- @@ -577,14 +577,15 @@ static void *opt_malloc(size_t size)
- return ret;
- }
-
- -static char *opt_string_alloc(char *cp)
- +static char *opt_string_alloc(const char *cp)
- {
- char *ret = NULL;
- + size_t len;
-
- - if (cp && strlen(cp) != 0)
- + if (cp && (len = strlen(cp)) != 0)
- {
- - ret = opt_malloc(strlen(cp)+1);
- - strcpy(ret, cp);
- + ret = opt_malloc(len+1);
- + memcpy(ret, cp, len+1);
-
- /* restore hidden metachars */
- unhide_metas(ret);
- @@ -759,6 +760,8 @@ static void do_usage(void)
- }
-
- #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
- +#define ret_err_free(x,m) do { strcpy(errstr, (x)); free((m)); return 0; } while (0)
- +#define goto_err(x) do { strcpy(errstr, (x)); goto on_error; } while (0)
-
- static char *parse_mysockaddr(char *arg, union mysockaddr *addr)
- {
- @@ -904,6 +907,8 @@ static struct server *add_rev4(struct in
- p += sprintf(p, "%d.", (a >> 24) & 0xff);
- break;
- default:
- + free(serv->domain);
- + free(serv);
- return NULL;
- }
-
- @@ -958,6 +963,97 @@ static char *set_prefix(char *arg)
- return arg;
- }
-
- +static struct dhcp_netid *
- +dhcp_netid_create(const char *net, struct dhcp_netid *next)
- +{
- + struct dhcp_netid *tt;
- + tt = opt_malloc(sizeof (struct dhcp_netid));
- + tt->net = opt_string_alloc(net);
- + tt->next = next;
- + return tt;
- +}
- +
- +static void dhcp_netid_free(struct dhcp_netid *nid)
- +{
- + while (nid)
- + {
- + struct dhcp_netid *tmp = nid;
- + nid = nid->next;
- + free(tmp->net);
- + free(tmp);
- + }
- +}
- +
- +/* Parse one or more tag:s before parameters.
- + * Moves arg to the end of tags. */
- +static struct dhcp_netid * dhcp_tags(char **arg)
- +{
- + struct dhcp_netid *id = NULL;
- +
- + while (is_tag_prefix(*arg))
- + {
- + char *comma = split(*arg);
- + id = dhcp_netid_create((*arg)+4, id);
- + *arg = comma;
- + };
- + if (!*arg)
- + {
- + dhcp_netid_free(id);
- + id = NULL;
- + }
- + return id;
- +}
- +
- +static void dhcp_netid_list_free(struct dhcp_netid_list *netid)
- +{
- + while (netid)
- + {
- + struct dhcp_netid_list *tmplist = netid;
- + netid = netid->next;
- + dhcp_netid_free(tmplist->list);
- + free(tmplist);
- + }
- +}
- +
- +static void dhcp_config_free(struct dhcp_config *config)
- +{
- + if (config)
- + {
- + struct hwaddr_config *hwaddr = config->hwaddr;
- + while (hwaddr)
- + {
- + struct hwaddr_config *tmp = hwaddr;
- + hwaddr = hwaddr->next;
- + free(tmp);
- + }
- + dhcp_netid_list_free(config->netid);
- + if (config->flags & CONFIG_CLID)
- + free(config->clid);
- + free(config);
- + }
- +}
- +
- +static void dhcp_context_free(struct dhcp_context *ctx)
- +{
- + if (ctx)
- + {
- + dhcp_netid_free(ctx->filter);
- + free(ctx->netid.net);
- + free(ctx->template_interface);
- + free(ctx);
- + }
- +}
- +
- +static void dhcp_opt_free(struct dhcp_opt *opt)
- +{
- + if (opt->flags & DHOPT_VENDOR)
- + free(opt->u.vendor_class);
- + dhcp_netid_free(opt->netid);
- + free(opt->val);
- + free(opt);
- +}
- +
- +
- /* This is too insanely large to keep in-line in the switch */
- static int parse_dhcp_opt(char *errstr, char *arg, int flags)
- {
- @@ -965,7 +1061,6 @@ static int parse_dhcp_opt(char *errstr,
- char lenchar = 0, *cp;
- int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
- char *comma = NULL;
- - struct dhcp_netid *np = NULL;
- u16 opt_len = 0;
- int is6 = 0;
- int option_ok = 0;
- @@ -1052,14 +1147,9 @@ static int parse_dhcp_opt(char *errstr,
- }
- else
- {
- - new->netid = opt_malloc(sizeof (struct dhcp_netid));
- /* allow optional "net:" or "tag:" for consistency */
- - if (is_tag_prefix(arg))
- - new->netid->net = opt_string_alloc(arg+4);
- - else
- - new->netid->net = opt_string_alloc(set_prefix(arg));
- - new->netid->next = np;
- - np = new->netid;
- + const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg);
- + new->netid = dhcp_netid_create(name, new->netid);
- }
-
- arg = comma;
- @@ -1069,7 +1159,7 @@ static int parse_dhcp_opt(char *errstr,
- if (is6)
- {
- if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
- - ret_err(_("unsupported encapsulation for IPv6 option"));
- + goto_err(_("unsupported encapsulation for IPv6 option"));
-
- if (opt_len == 0 &&
- !(new->flags & DHOPT_RFC3925))
- @@ -1083,7 +1173,7 @@ static int parse_dhcp_opt(char *errstr,
-
- /* option may be missing with rfc3925 match */
- if (!option_ok)
- - ret_err(_("bad dhcp-option"));
- + goto_err(_("bad dhcp-option"));
-
- if (comma)
- {
- @@ -1151,10 +1241,10 @@ static int parse_dhcp_opt(char *errstr,
- is_string = is_dec = is_hex = 0;
-
- if (!is6 && (!is_addr || dots == 0))
- - ret_err(_("bad IP address"));
- + goto_err(_("bad IP address"));
-
- if (is6 && !is_addr6)
- - ret_err(_("bad IPv6 address"));
- + goto_err(_("bad IPv6 address"));
- }
- /* or names */
- else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
- @@ -1247,7 +1337,7 @@ static int parse_dhcp_opt(char *errstr,
- comma = split(cp);
- slash = split_chr(cp, '/');
- if (!inet_pton(AF_INET, cp, &in))
- - ret_err(_("bad IPv4 address"));
- + goto_err(_("bad IPv4 address"));
- if (!slash)
- {
- memcpy(op, &in, INADDRSZ);
- @@ -1292,8 +1382,8 @@ static int parse_dhcp_opt(char *errstr,
- op += IN6ADDRSZ;
- continue;
- }
- -
- - ret_err(_("bad IPv6 address"));
- +
- + goto_err(_("bad IPv6 address"));
- }
- new->len = op - new->val;
- }
- @@ -1320,7 +1410,7 @@ static int parse_dhcp_opt(char *errstr,
- if (strcmp (arg, ".") != 0)
- {
- if (!(dom = canonicalise_opt(arg)))
- - ret_err(_("bad domain in dhcp-option"));
- + goto_err(_("bad domain in dhcp-option"));
-
- domlen = strlen(dom) + 2;
- }
- @@ -1414,7 +1504,7 @@ static int parse_dhcp_opt(char *errstr,
- {
- char *dom = canonicalise_opt(arg);
- if (!dom)
- - ret_err(_("bad domain in dhcp-option"));
- + goto_err(_("bad domain in dhcp-option"));
-
- newp = opt_malloc(len + strlen(dom) + 2);
-
- @@ -1452,14 +1542,14 @@ static int parse_dhcp_opt(char *errstr,
- ((new->len > 255) ||
- (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
- (new->len > 250 && (new->flags & DHOPT_RFC3925))))
- - ret_err(_("dhcp-option too long"));
- + goto_err(_("dhcp-option too long"));
-
- if (flags == DHOPT_MATCH)
- {
- if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
- !new->netid ||
- new->netid->next)
- - ret_err(_("illegal dhcp-match"));
- + goto_err(_("illegal dhcp-match"));
-
- if (is6)
- {
- @@ -1484,6 +1574,9 @@ static int parse_dhcp_opt(char *errstr,
- }
-
- return 1;
- +on_error:
- + dhcp_opt_free(new);
- + return 0;
- }
-
- #endif
- @@ -1498,6 +1591,16 @@ void reset_option_bool(unsigned int opt)
- option_var(opt) &= ~(option_val(opt));
- }
-
- +static void server_list_free(struct server *list)
- +{
- + while (list)
- + {
- + struct server *tmp = list;
- + list = list->next;
- + free(tmp);
- + }
- +}
- +
- static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
- {
- int i;
- @@ -1679,13 +1782,13 @@ static int one_opt(int option, char *arg
- /* has subnet+len */
- err = parse_mysockaddr(arg, &new->addr);
- if (err)
- - ret_err(err);
- + ret_err_free(err, new);
- if (!atoi_check(end, &new->mask))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- new->addr_used = 1;
- }
- else if (!atoi_check(arg, &new->mask))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
-
- daemon->add_subnet4 = new;
-
- @@ -1697,15 +1800,15 @@ static int one_opt(int option, char *arg
- /* has subnet+len */
- err = parse_mysockaddr(comma, &new->addr);
- if (err)
- - ret_err(err);
- + ret_err_free(err, new);
- if (!atoi_check(end, &new->mask))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- new->addr_used = 1;
- }
- else
- {
- if (!atoi_check(comma, &new->mask))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- }
-
- daemon->add_subnet6 = new;
- @@ -1912,7 +2015,10 @@ static int one_opt(int option, char *arg
- else if (strcmp(fam, "6") == 0)
- new->addr.sa.sa_family = AF_INET6;
- else
- - ret_err(gen_err);
- + {
- + free(new->name);
- + ret_err_free(gen_err, new);
- + }
- }
- }
- new->next = daemon->authinterface;
- @@ -2077,7 +2183,7 @@ static int one_opt(int option, char *arg
-
- arg = split(netpart);
- if (!atoi_check(netpart, &msize))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- else if (inet_pton(AF_INET, comma, &new->start))
- {
- int mask = (1 << (32 - msize)) - 1;
- @@ -2090,18 +2196,18 @@ static int one_opt(int option, char *arg
- {
- if (!(new->prefix = canonicalise_opt(arg)) ||
- strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
- - ret_err(_("bad prefix"));
- + ret_err_free(_("bad prefix"), new);
- }
- else if (strcmp(arg, "local") != 0 ||
- (msize != 8 && msize != 16 && msize != 24))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- else
- {
- /* generate the equivalent of
- local=/xxx.yyy.zzz.in-addr.arpa/ */
- struct server *serv = add_rev4(new->start, msize);
- if (!serv)
- - ret_err(_("bad prefix"));
- + ret_err_free(_("bad prefix"), new);
-
- serv->flags |= SERV_NO_ADDR;
-
- @@ -2130,17 +2236,17 @@ static int one_opt(int option, char *arg
- setaddr6part(&new->end6, addrpart | mask);
-
- if (msize < 64)
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- else if (arg)
- {
- if (option != 's')
- {
- if (!(new->prefix = canonicalise_opt(arg)) ||
- strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
- - ret_err(_("bad prefix"));
- + ret_err_free(_("bad prefix"), new);
- }
- else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- else
- {
- /* generate the equivalent of
- @@ -2159,7 +2265,7 @@ static int one_opt(int option, char *arg
- }
- }
- else
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- }
- else
- {
- @@ -2173,7 +2279,7 @@ static int one_opt(int option, char *arg
- if (!arg)
- new->end.s_addr = new->start.s_addr;
- else if (!inet_pton(AF_INET, arg, &new->end))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- }
- else if (inet_pton(AF_INET6, comma, &new->start6))
- {
- @@ -2181,16 +2287,16 @@ static int one_opt(int option, char *arg
- if (!arg)
- memcpy(&new->end6, &new->start6, IN6ADDRSZ);
- else if (!inet_pton(AF_INET6, arg, &new->end6))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- }
- else
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
-
- if (option != 's' && prefstr)
- {
- if (!(new->prefix = canonicalise_opt(prefstr)) ||
- strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
- - ret_err(_("bad prefix"));
- + ret_err_free(_("bad prefix"), new);
- }
- }
-
- @@ -2352,7 +2458,7 @@ static int one_opt(int option, char *arg
- #endif
- }
- else
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
-
- new->used = 0;
- if (option == 'a')
- @@ -2423,7 +2529,10 @@ static int one_opt(int option, char *arg
- {
- newlist->flags |= SERV_LITERAL_ADDRESS;
- if (!(newlist->flags & SERV_TYPE))
- - ret_err(gen_err);
- + {
- + server_list_free(newlist);
- + ret_err(gen_err);
- + }
- }
- else if (option == LOPT_NO_REBIND)
- newlist->flags |= SERV_NO_REBIND;
- @@ -2440,7 +2549,10 @@ static int one_opt(int option, char *arg
- {
- char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
- if (err)
- - ret_err(err);
- + {
- + server_list_free(newlist);
- + ret_err(err);
- + }
- }
-
- serv = newlist;
- @@ -2776,21 +2888,19 @@ static int one_opt(int option, char *arg
- {
- if (is_tag_prefix(arg))
- {
- - struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
- - tt->net = opt_string_alloc(arg+4);
- - tt->next = new->filter;
- /* ignore empty tag */
- - if (tt->net)
- - new->filter = tt;
- + if (arg[4])
- + new->filter = dhcp_netid_create(arg+4, new->filter);
- }
- else
- {
- if (new->netid.net)
- - ret_err(_("only one tag allowed"));
- - else if (strstr(arg, "set:") == arg)
- - new->netid.net = opt_string_alloc(arg+4);
- + {
- + dhcp_context_free(new);
- + ret_err(_("only one tag allowed"));
- + }
- else
- - new->netid.net = opt_string_alloc(arg);
- + new->netid.net = opt_string_alloc(set_prefix(arg));
- }
- arg = comma;
- }
- @@ -2806,7 +2916,10 @@ static int one_opt(int option, char *arg
- break;
-
- if (k < 2)
- - ret_err(_("bad dhcp-range"));
- + {
- + dhcp_context_free(new);
- + ret_err(_("bad dhcp-range"));
- + }
-
- if (inet_pton(AF_INET, a[0], &new->start))
- {
- @@ -2818,7 +2931,10 @@ static int one_opt(int option, char *arg
- else if (strcmp(a[1], "proxy") == 0)
- new->flags |= CONTEXT_PROXY;
- else if (!inet_pton(AF_INET, a[1], &new->end))
- - ret_err(_("bad dhcp-range"));
- + {
- + dhcp_context_free(new);
- + ret_err(_("bad dhcp-range"));
- + }
-
- if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
- {
- @@ -2833,7 +2949,10 @@ static int one_opt(int option, char *arg
- new->flags |= CONTEXT_NETMASK;
- leasepos = 3;
- if (!is_same_net(new->start, new->end, new->netmask))
- - ret_err(_("inconsistent DHCP range"));
- + {
- + dhcp_context_free(new);
- + ret_err(_("inconsistent DHCP range"));
- + }
-
-
- if (k >= 4 && strchr(a[3], '.') &&
- @@ -2847,6 +2966,8 @@ static int one_opt(int option, char *arg
- #ifdef HAVE_DHCP6
- else if (inet_pton(AF_INET6, a[0], &new->start6))
- {
- + const char *err = NULL;
- +
- new->flags |= CONTEXT_V6;
- new->prefix = 64; /* default */
- new->end6 = new->start6;
- @@ -2892,19 +3013,24 @@ static int one_opt(int option, char *arg
- }
- }
-
- - if (new->prefix != 64)
- + if (new->prefix > 64)
- {
- if (new->flags & CONTEXT_RA)
- - ret_err(_("prefix length must be exactly 64 for RA subnets"));
- + err=(_("prefix length must be exactly 64 for RA subnets"));
- else if (new->flags & CONTEXT_TEMPLATE)
- - ret_err(_("prefix length must be exactly 64 for subnet constructors"));
- + err=(_("prefix length must be exactly 64 for subnet constructors"));
- }
- -
- - if (new->prefix < 64)
- - ret_err(_("prefix length must be at least 64"));
- + else if (new->prefix < 64)
- + err=(_("prefix length must be at least 64"));
-
- - if (!is_same_net6(&new->start6, &new->end6, new->prefix))
- - ret_err(_("inconsistent DHCPv6 range"));
- + if (!err && !is_same_net6(&new->start6, &new->end6, new->prefix))
- + err=(_("inconsistent DHCPv6 range"));
- +
- + if (err)
- + {
- + dhcp_context_free(new);
- + ret_err(err);
- + }
-
- /* dhcp-range=:: enables DHCP stateless on any interface */
- if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
- @@ -2915,7 +3041,10 @@ static int one_opt(int option, char *arg
- struct in6_addr zero;
- memset(&zero, 0, sizeof(zero));
- if (!is_same_net6(&zero, &new->start6, new->prefix))
- - ret_err(_("prefix must be zero with \"constructor:\" argument"));
- + {
- + dhcp_context_free(new);
- + ret_err(_("prefix must be zero with \"constructor:\" argument"));
- + }
- }
-
- if (addr6part(&new->start6) > addr6part(&new->end6))
- @@ -2927,12 +3056,18 @@ static int one_opt(int option, char *arg
- }
- #endif
- else
- - ret_err(_("bad dhcp-range"));
- + {
- + dhcp_context_free(new);
- + ret_err(_("bad dhcp-range"));
- + }
-
- if (leasepos < k)
- {
- if (leasepos != k-1)
- - ret_err(_("bad dhcp-range"));
- + {
- + dhcp_context_free(new);
- + ret_err(_("bad dhcp-range"));
- + }
-
- if (strcmp(a[leasepos], "infinite") == 0)
- new->lease_time = 0xffffffff;
- @@ -2971,7 +3106,7 @@ static int one_opt(int option, char *arg
- break;
-
- if (*cp || (leasepos+1 < k))
- - ret_err(_("bad dhcp-range"));
- + ret_err_free(_("bad dhcp-range"), new);
-
- new->lease_time = atoi(a[leasepos]) * fac;
- /* Leases of a minute or less confuse
- @@ -2998,6 +3133,7 @@ static int one_opt(int option, char *arg
- new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
- new->hwaddr = NULL;
- new->netid = NULL;
- + new->clid = NULL;
-
- if ((a[0] = arg))
- for (k = 1; k < 7; k++)
- @@ -3028,7 +3164,10 @@ static int one_opt(int option, char *arg
- }
-
- if (len == -1)
- - ret_err(_("bad hex constant"));
- + {
- + dhcp_config_free(new);
- + ret_err(_("bad hex constant"));
- + }
- else if ((new->clid = opt_malloc(len)))
- {
- new->flags |= CONFIG_CLID;
- @@ -3040,17 +3179,17 @@ static int one_opt(int option, char *arg
- /* dhcp-host has strange backwards-compat needs. */
- else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
- {
- - struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
- struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
- - newtag->net = opt_malloc(strlen(arg + 4) + 1);
- newlist->next = new->netid;
- new->netid = newlist;
- - newlist->list = newtag;
- - strcpy(newtag->net, arg+4);
- - unhide_metas(newtag->net);
- + newlist->list = dhcp_netid_create(arg+4, NULL);
- }
- else if (strstr(arg, "tag:") == arg)
- - ret_err(_("cannot match tags in --dhcp-host"));
- + {
- +
- + dhcp_config_free(new);
- + ret_err(_("cannot match tags in --dhcp-host"));
- + }
- #ifdef HAVE_DHCP6
- else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
- {
- @@ -3058,7 +3197,10 @@ static int one_opt(int option, char *arg
- arg++;
-
- if (!inet_pton(AF_INET6, arg, &new->addr6))
- - ret_err(_("bad IPv6 address"));
- + {
- + dhcp_config_free(new);
- + ret_err(_("bad IPv6 address"));
- + }
-
- for (i= 0; i < 8; i++)
- if (new->addr6.s6_addr[i] != 0)
- @@ -3076,10 +3218,13 @@ static int one_opt(int option, char *arg
- struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
- if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX,
- &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
- - ret_err(_("bad hex constant"));
- + {
- + free(newhw);
- + dhcp_config_free(new);
- + ret_err(_("bad hex constant"));
- + }
- else
- {
- -
- newhw->next = new->hwaddr;
- new->hwaddr = newhw;
- }
- @@ -3156,7 +3301,10 @@ static int one_opt(int option, char *arg
- {
- if (!(new->hostname = canonicalise_opt(a[j])) ||
- !legal_hostname(new->hostname))
- - ret_err(_("bad DHCP host name"));
- + {
- + dhcp_config_free(new);
- + ret_err(_("bad DHCP host name"));
- + }
-
- new->flags |= CONFIG_NAME;
- new->domain = strip_hostname(new->hostname);
- @@ -3209,10 +3357,7 @@ static int one_opt(int option, char *arg
- }
- else
- {
- - struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
- - newtag->net = opt_malloc(len - 3);
- - strcpy(newtag->net, arg+4);
- - unhide_metas(newtag->net);
- + struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL);
-
- if (strstr(arg, "set:") == arg)
- {
- @@ -3229,7 +3374,7 @@ static int one_opt(int option, char *arg
- else
- {
- new->set = NULL;
- - free(newtag);
- + dhcp_netid_free(newtag);
- break;
- }
- }
- @@ -3238,7 +3383,11 @@ static int one_opt(int option, char *arg
- }
-
- if (!new->set)
- - ret_err(_("bad tag-if"));
- + {
- + dhcp_netid_free(new->tag);
- + dhcp_netid_list_free(new->set);
- + ret_err_free(_("bad tag-if"), new);
- + }
-
- break;
- }
- @@ -3281,19 +3430,12 @@ static int one_opt(int option, char *arg
-
- case 'M': /* --dhcp-boot */
- {
- - struct dhcp_netid *id = NULL;
- - while (is_tag_prefix(arg))
- - {
- - struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
- - newid->next = id;
- - id = newid;
- - comma = split(arg);
- - newid->net = opt_string_alloc(arg+4);
- - arg = comma;
- - };
- + struct dhcp_netid *id = dhcp_tags(&arg);
-
- - if (!arg)
- - ret_err(gen_err);
- + if (!id)
- + {
- + ret_err(gen_err);
- + }
- else
- {
- char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
- @@ -3339,19 +3481,12 @@ static int one_opt(int option, char *arg
-
- case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
- {
- - struct dhcp_netid *id = NULL;
- - while (is_tag_prefix(arg))
- - {
- - struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
- - newid->next = id;
- - id = newid;
- - comma = split(arg);
- - newid->net = opt_string_alloc(arg+4);
- - arg = comma;
- - };
- + struct dhcp_netid *id = dhcp_tags(&arg);
-
- - if (!arg)
- - ret_err(gen_err);
- + if (!id)
- + {
- + ret_err(gen_err);
- + }
- else
- {
- struct delay_config *new;
- @@ -3376,19 +3511,13 @@ static int one_opt(int option, char *arg
-
- new->netid = NULL;
- new->opt = 10; /* PXE_MENU_PROMPT */
- -
- - while (is_tag_prefix(arg))
- - {
- - struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
- - comma = split(arg);
- - nn->next = new->netid;
- - new->netid = nn;
- - nn->net = opt_string_alloc(arg+4);
- - arg = comma;
- - }
- + new->netid = dhcp_tags(&arg);
-
- - if (!arg)
- - ret_err(gen_err);
- + if (!new->netid)
- + {
- + dhcp_opt_free(new);
- + ret_err(gen_err);
- + }
- else
- {
- comma = split(arg);
- @@ -3424,17 +3553,8 @@ static int one_opt(int option, char *arg
- new->netid = NULL;
- new->sname = NULL;
- new->server.s_addr = 0;
- + new->netid = dhcp_tags(&arg);
-
- - while (is_tag_prefix(arg))
- - {
- - struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
- - comma = split(arg);
- - nn->next = new->netid;
- - new->netid = nn;
- - nn->net = opt_string_alloc(arg+4);
- - arg = comma;
- - }
- -
- if (arg && (comma = split(arg)))
- {
- for (i = 0; CSA[i]; i++)
- @@ -3511,7 +3631,10 @@ static int one_opt(int option, char *arg
- unhide_metas(comma);
- new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
- if (new->hwaddr_len == -1)
- - ret_err(gen_err);
- + {
- + free(new->netid.net);
- + ret_err_free(gen_err, new);
- + }
- else
- {
- new->next = daemon->dhcp_macs;
- @@ -3528,7 +3651,7 @@ static int one_opt(int option, char *arg
-
- if (!(comma = split(arg)) ||
- !atoi_check16(comma, &new->class))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
-
- new->tag.net = opt_string_alloc(set_prefix(arg));
- new->next = daemon->prefix_classes;
- @@ -3550,7 +3673,7 @@ static int one_opt(int option, char *arg
- struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
-
- if (!(comma = split(arg)))
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
-
- new->netid.net = opt_string_alloc(set_prefix(arg));
- /* check for hex string - must digits may include : must not have nothing else,
- @@ -3560,7 +3683,10 @@ static int one_opt(int option, char *arg
- if ((comma = split(arg)))
- {
- if (option != 'U' || strstr(arg, "enterprise:") != arg)
- - ret_err(gen_err);
- + {
- + free(new->netid.net);
- + ret_err_free(gen_err, new);
- + }
- else
- new->enterprise = atoi(arg+11);
- }
- @@ -3662,14 +3788,8 @@ static int one_opt(int option, char *arg
- }
-
- while (arg) {
- - struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
- comma = split(arg);
- - member->next = list;
- - list = member;
- - if (is_tag_prefix(arg))
- - member->net = opt_string_alloc(arg+4);
- - else
- - member->net = opt_string_alloc(arg);
- + list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list);
- arg = comma;
- }
-
- @@ -3683,7 +3803,7 @@ static int one_opt(int option, char *arg
- struct addr_list *new = opt_malloc(sizeof(struct addr_list));
- comma = split(arg);
- if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
- - ret_err(_("bad dhcp-proxy address"));
- + ret_err_free(_("bad dhcp-proxy address"), new);
- new->next = daemon->override_relays;
- daemon->override_relays = new;
- arg = comma;
- @@ -3709,7 +3829,10 @@ static int one_opt(int option, char *arg
- }
- #endif
- else
- - ret_err(_("Bad dhcp-relay"));
- + {
- + free(new->interface);
- + ret_err_free(_("Bad dhcp-relay"), new);
- + }
-
- break;
- }
- @@ -3749,8 +3872,11 @@ static int one_opt(int option, char *arg
- arg = split(comma);
- if (!atoi_check(comma, &new->interval) ||
- (arg && !atoi_check(arg, &new->lifetime)))
- + {
- err:
- - ret_err(_("bad RA-params"));
- + free(new->name);
- + ret_err_free(_("bad RA-params"), new);
- + }
-
- new->next = daemon->ra_interfaces;
- daemon->ra_interfaces = new;
- @@ -3799,7 +3925,7 @@ err:
- (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
- !is_same_net(new->in, new->end, new->mask) ||
- ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
- - ret_err(_("invalid alias range"));
- + ret_err_free(_("invalid alias range"), new);
-
- break;
- }
- @@ -3832,7 +3958,7 @@ err:
- else if (strcmp(arg, "6") == 0)
- new->family = AF_INET6;
- else
- - ret_err(gen_err);
- + ret_err_free(gen_err, new);
- }
- new->intr = opt_string_alloc(comma);
- break;
- @@ -3864,11 +3990,19 @@ err:
- alias = canonicalise_opt(arg);
-
- if (!alias || !target)
- - ret_err(_("bad CNAME"));
- + {
- + free(target);
- + free(alias);
- + ret_err(_("bad CNAME"));
- + }
-
- for (new = daemon->cnames; new; new = new->next)
- if (hostname_isequal(new->alias, alias))
- - ret_err(_("duplicate CNAME"));
- + {
- + free(target);
- + free(alias);
- + ret_err(_("duplicate CNAME"));
- + }
- new = opt_malloc(sizeof(struct cname));
- new->next = daemon->cnames;
- daemon->cnames = new;
- @@ -3891,7 +4025,11 @@ err:
-
- if (!(dom = canonicalise_opt(arg)) ||
- (comma && !(target = canonicalise_opt(comma))))
- - ret_err(_("bad PTR record"));
- + {
- + free(dom);
- + free(target);
- + ret_err(_("bad PTR record"));
- + }
- else
- {
- new = opt_malloc(sizeof(struct ptr_record));
- @@ -3909,7 +4047,7 @@ err:
- int k = 0;
- struct naptr *new;
- int order, pref;
- - char *name, *replace = NULL;
- + char *name=NULL, *replace = NULL;
-
- if ((a[0] = arg))
- for (k = 1; k < 7; k++)
- @@ -3922,7 +4060,11 @@ err:
- !atoi_check16(a[1], &order) ||
- !atoi_check16(a[2], &pref) ||
- (k == 7 && !(replace = canonicalise_opt(a[6]))))
- - ret_err(_("bad NAPTR record"));
- + {
- + free(name);
- + free(replace);
- + ret_err(_("bad NAPTR record"));
- + }
- else
- {
- new = opt_malloc(sizeof(struct naptr));
- @@ -3944,22 +4086,26 @@ err:
- struct txt_record *new;
- size_t len = 0;
- char *data;
- - int val;
- + int class;
-
- comma = split(arg);
- data = split(comma);
-
- new = opt_malloc(sizeof(struct txt_record));
- - new->next = daemon->rr;
- - daemon->rr = new;
- + new->name = NULL;
-
- - if (!atoi_check(comma, &val) ||
- + if (!atoi_check(comma, &class) ||
- !(new->name = canonicalise_opt(arg)) ||
- (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
- - ret_err(_("bad RR record"));
- -
- - new->class = val;
- + {
- + free(new->name);
- + ret_err_free(_("bad RR record"), new);
- + }
- +
- new->len = 0;
- + new->class = class;
- + new->next = daemon->rr;
- + daemon->rr = new;
-
- if (data)
- {
- @@ -4011,14 +4157,14 @@ err:
- comma = split(arg);
-
- new = opt_malloc(sizeof(struct txt_record));
- - new->next = daemon->txt;
- - daemon->txt = new;
- new->class = C_IN;
- new->stat = 0;
-
- if (!(new->name = canonicalise_opt(arg)))
- - ret_err(_("bad TXT record"));
- + ret_err_free(_("bad TXT record"), new);
-
- + new->next = daemon->txt;
- + daemon->txt = new;
- len = comma ? strlen(comma) : 0;
- len += (len/255) + 1; /* room for extra counts */
- new->txt = p = opt_malloc(len);
- @@ -4065,24 +4211,32 @@ err:
- arg = comma;
- comma = split(arg);
- if (!(target = canonicalise_opt(arg)))
- - ret_err(_("bad SRV target"));
- + ret_err_free(_("bad SRV target"), name);
-
- if (comma)
- {
- arg = comma;
- comma = split(arg);
- if (!atoi_check16(arg, &port))
- - ret_err(_("invalid port number"));
- + {
- + free(name);
- + ret_err_free(_("invalid port number"), target);
- + }
-
- if (comma)
- {
- arg = comma;
- comma = split(arg);
- if (!atoi_check16(arg, &priority))
- - ret_err(_("invalid priority"));
- -
- + {
- + free(name);
- + ret_err_free(_("invalid priority"), target);
- + }
- if (comma && !atoi_check16(comma, &weight))
- - ret_err(_("invalid weight"));
- + {
- + free(name);
- + ret_err_free(_("invalid weight"), target);
- + }
- }
- }
- }
- @@ -4101,13 +4255,15 @@ err:
-
- case LOPT_HOST_REC: /* --host-record */
- {
- - struct host_record *new = opt_malloc(sizeof(struct host_record));
- - memset(new, 0, sizeof(struct host_record));
- - new->ttl = -1;
- + struct host_record *new;
-
- if (!arg || !(comma = split(arg)))
- ret_err(_("Bad host-record"));
-
- + new = opt_malloc(sizeof(struct host_record));
- + memset(new, 0, sizeof(struct host_record));
- + new->ttl = -1;
- +
- while (arg)
- {
- struct all_addr addr;
- @@ -4126,10 +4282,19 @@ err:
- {
- int nomem;
- char *canon = canonicalise(arg, &nomem);
- - struct name_list *nl = opt_malloc(sizeof(struct name_list));
- + struct name_list *nl;
- if (!canon)
- - ret_err(_("Bad name in host-record"));
- + {
- + struct name_list *tmp = new->names, *next;
- + for (tmp = new->names; tmp; tmp = next)
- + {
- + next = tmp->next;
- + free(tmp);
- + }
- + ret_err_free(_("Bad name in host-record"), new);
- + }
-
- + nl = opt_malloc(sizeof(struct name_list));
- nl->name = canon;
- /* keep order, so that PTR record goes to first name */
- nl->next = NULL;
- @@ -4179,6 +4344,7 @@ err:
- int len;
-
- new->class = C_IN;
- + new->name = NULL;
-
- if ((comma = split(arg)) && (algo = split(comma)))
- {
- @@ -4203,7 +4369,7 @@ err:
- !atoi_check8(algo, &new->algo) ||
- !atoi_check8(digest, &new->digest_type) ||
- !(new->name = canonicalise_opt(arg)))
- - ret_err(_("bad trust anchor"));
- + ret_err_free(_("bad trust anchor"), new);
-
- /* Upper bound on length */
- len = (2*strlen(keyhex))+1;
- @@ -4217,7 +4383,10 @@ err:
- else
- cp++;
- if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
- - ret_err(_("bad HEX in trust anchor"));
- + {
- + free(new->name);
- + ret_err_free(_("bad HEX in trust anchor"), new);
- + }
-
- new->next = daemon->ds;
- daemon->ds = new;
- @@ -4686,8 +4855,8 @@ void read_opts(int argc, char **argv, ch
- size_t argbuf_size = MAXDNAME;
- char *argbuf = opt_malloc(argbuf_size);
- char *buff = opt_malloc(MAXDNAME);
- - int option, conffile_opt = '7', testmode = 0;
- - char *arg, *conffile = CONFFILE;
- + int option, testmode = 0;
- + char *arg, *conffile = NULL;
-
- opterr = 0;
-
- @@ -4796,7 +4965,8 @@ void read_opts(int argc, char **argv, ch
- }
- else if (option == 'C')
- {
- - conffile_opt = 0; /* file must exist */
- + if (conffile)
- + free(conffile);
- conffile = opt_string_alloc(arg);
- }
- else
- @@ -4814,10 +4984,11 @@ void read_opts(int argc, char **argv, ch
-
- if (conffile)
- {
- - one_file(conffile, conffile_opt);
- - if (conffile_opt == 0)
- - free(conffile);
- + one_file(conffile, 0);
- + free(conffile);
- }
- + else
- + one_file(CONFFILE, '7');
-
- /* port might not be known when the address is parsed - fill in here */
- if (daemon->servers)
|