dnsmasq: backport latest patches
[oweals/openwrt.git] / package / network / services / dnsmasq / patches / 0011-Free-config-file-values-on-parsing-errors.patch
1 From 59e470381f84f2fdf0640c7bc67827f3f0c64784 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
3 Date: Fri, 2 Nov 2018 22:39:39 +0000
4 Subject: [PATCH 11/57] Free config file values on parsing errors.
5
6 This time I have a little bit more controversal patches. But I think
7 still useful. They fixes memory leaks that might occur in some cases.
8 Most dnsmasq errors is fatal, so it does not matter. But some are not.
9 Some parts are reloaded on SIGHUP signal, so it might leak more than once.
10
11 Some example when it changes the failures. Use dhcp-options file with
12 this content:
13
14 tag:error,vendor:redhat
15 option:ntp-server,1.2.3.4.5
16 option6:ntp-server,[:::]
17
18 Is not fatal and dnsmasq will start. On each reload command, it would
19 leak some memory. I validated it using valgrind --leak-check=full
20 dnsmasq -d. This patch fixes it. It introduces something that might be
21 considered constructor and destructor of selected structures.
22
23 Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
24 ---
25  src/option.c | 533 ++++++++++++++++++++++++++++++++++-----------------
26  1 file changed, 352 insertions(+), 181 deletions(-)
27
28 --- a/src/option.c
29 +++ b/src/option.c
30 @@ -577,14 +577,15 @@ static void *opt_malloc(size_t size)
31    return ret;
32  }
33  
34 -static char *opt_string_alloc(char *cp)
35 +static char *opt_string_alloc(const char *cp)
36  {
37    char *ret = NULL;
38 +  size_t len;
39    
40 -  if (cp && strlen(cp) != 0)
41 +  if (cp && (len = strlen(cp)) != 0)
42      {
43 -      ret = opt_malloc(strlen(cp)+1);
44 -      strcpy(ret, cp); 
45 +      ret = opt_malloc(len+1);
46 +      memcpy(ret, cp, len+1); 
47        
48        /* restore hidden metachars */
49        unhide_metas(ret);
50 @@ -759,6 +760,8 @@ static void do_usage(void)
51  }
52  
53  #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
54 +#define ret_err_free(x,m) do { strcpy(errstr, (x)); free((m)); return 0; } while (0)
55 +#define goto_err(x) do { strcpy(errstr, (x)); goto on_error; } while (0)
56  
57  static char *parse_mysockaddr(char *arg, union mysockaddr *addr) 
58  {
59 @@ -904,6 +907,8 @@ static struct server *add_rev4(struct in
60        p += sprintf(p, "%d.", (a >> 24) & 0xff);
61        break;
62      default:
63 +      free(serv->domain);
64 +      free(serv);
65        return NULL;
66      }
67  
68 @@ -958,6 +963,97 @@ static char *set_prefix(char *arg)
69     return arg;
70  }
71  
72 +static struct dhcp_netid *
73 +dhcp_netid_create(const char *net, struct dhcp_netid *next)
74 +{
75 +  struct dhcp_netid *tt;
76 +  tt = opt_malloc(sizeof (struct dhcp_netid));
77 +  tt->net = opt_string_alloc(net);
78 +  tt->next = next;
79 +  return tt;
80 +}
81 +
82 +static void dhcp_netid_free(struct dhcp_netid *nid)
83 +{
84 +  while (nid)
85 +    {
86 +      struct dhcp_netid *tmp = nid;
87 +      nid = nid->next;
88 +      free(tmp->net);
89 +      free(tmp);
90 +    }
91 +}
92 +
93 +/* Parse one or more tag:s before parameters.
94 + * Moves arg to the end of tags. */
95 +static struct dhcp_netid * dhcp_tags(char **arg)
96 +{
97 +  struct dhcp_netid *id = NULL;
98 +
99 +  while (is_tag_prefix(*arg))
100 +    {
101 +      char *comma = split(*arg);
102 +      id = dhcp_netid_create((*arg)+4, id);
103 +      *arg = comma;
104 +    };
105 +  if (!*arg)
106 +    {
107 +      dhcp_netid_free(id);
108 +      id = NULL;
109 +    }
110 +  return id;
111 +}
112 +
113 +static void dhcp_netid_list_free(struct dhcp_netid_list *netid)
114 +{
115 +  while (netid)
116 +    {
117 +      struct dhcp_netid_list *tmplist = netid;
118 +      netid = netid->next;
119 +      dhcp_netid_free(tmplist->list);
120 +      free(tmplist);
121 +    }
122 +}
123 +
124 +static void dhcp_config_free(struct dhcp_config *config)
125 +{
126 +  if (config)
127 +    {
128 +      struct hwaddr_config *hwaddr = config->hwaddr;
129 +      while (hwaddr)
130 +        {
131 +         struct hwaddr_config *tmp = hwaddr;
132 +          hwaddr = hwaddr->next;
133 +         free(tmp);
134 +        }
135 +      dhcp_netid_list_free(config->netid);
136 +      if (config->flags & CONFIG_CLID)
137 +        free(config->clid);
138 +      free(config);
139 +    }
140 +}
141 +
142 +static void dhcp_context_free(struct dhcp_context *ctx)
143 +{
144 +  if (ctx)
145 +    {
146 +      dhcp_netid_free(ctx->filter);
147 +      free(ctx->netid.net);
148 +      free(ctx->template_interface);
149 +      free(ctx);
150 +    }
151 +}
152 +
153 +static void dhcp_opt_free(struct dhcp_opt *opt)
154 +{
155 +  if (opt->flags & DHOPT_VENDOR)
156 +    free(opt->u.vendor_class);
157 +  dhcp_netid_free(opt->netid);
158 +  free(opt->val);
159 +  free(opt);
160 +}
161 +
162 +
163  /* This is too insanely large to keep in-line in the switch */
164  static int parse_dhcp_opt(char *errstr, char *arg, int flags)
165  {
166 @@ -965,7 +1061,6 @@ static int parse_dhcp_opt(char *errstr,
167    char lenchar = 0, *cp;
168    int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
169    char *comma = NULL;
170 -  struct dhcp_netid *np = NULL;
171    u16 opt_len = 0;
172    int is6 = 0;
173    int option_ok = 0;
174 @@ -1052,14 +1147,9 @@ static int parse_dhcp_opt(char *errstr,
175         }
176        else
177         {
178 -         new->netid = opt_malloc(sizeof (struct dhcp_netid));
179           /* allow optional "net:" or "tag:" for consistency */
180 -         if (is_tag_prefix(arg))
181 -           new->netid->net = opt_string_alloc(arg+4);
182 -         else
183 -           new->netid->net = opt_string_alloc(set_prefix(arg));
184 -         new->netid->next = np;
185 -         np = new->netid;
186 +         const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg);
187 +         new->netid = dhcp_netid_create(name, new->netid);
188         }
189        
190        arg = comma; 
191 @@ -1069,7 +1159,7 @@ static int parse_dhcp_opt(char *errstr,
192    if (is6)
193      {
194        if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
195 -       ret_err(_("unsupported encapsulation for IPv6 option"));
196 +       goto_err(_("unsupported encapsulation for IPv6 option"));
197        
198        if (opt_len == 0 &&
199           !(new->flags & DHOPT_RFC3925))
200 @@ -1083,7 +1173,7 @@ static int parse_dhcp_opt(char *errstr,
201    
202    /* option may be missing with rfc3925 match */
203    if (!option_ok)
204 -    ret_err(_("bad dhcp-option"));
205 +    goto_err(_("bad dhcp-option"));
206    
207    if (comma)
208      {
209 @@ -1151,10 +1241,10 @@ static int parse_dhcp_opt(char *errstr,
210           is_string = is_dec = is_hex = 0;
211           
212           if (!is6 && (!is_addr || dots == 0))
213 -           ret_err(_("bad IP address"));
214 +           goto_err(_("bad IP address"));
215  
216            if (is6 && !is_addr6)
217 -            ret_err(_("bad IPv6 address"));
218 +            goto_err(_("bad IPv6 address"));
219         }
220        /* or names */
221        else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
222 @@ -1247,7 +1337,7 @@ static int parse_dhcp_opt(char *errstr,
223               comma = split(cp);
224               slash = split_chr(cp, '/');
225               if (!inet_pton(AF_INET, cp, &in))
226 -               ret_err(_("bad IPv4 address"));
227 +               goto_err(_("bad IPv4 address"));
228               if (!slash)
229                 {
230                   memcpy(op, &in, INADDRSZ);
231 @@ -1292,8 +1382,8 @@ static int parse_dhcp_opt(char *errstr,
232                   op += IN6ADDRSZ;
233                   continue;
234                 }
235 -         
236 -             ret_err(_("bad IPv6 address"));
237 +
238 +             goto_err(_("bad IPv6 address"));
239             } 
240           new->len = op - new->val;
241         }
242 @@ -1320,7 +1410,7 @@ static int parse_dhcp_opt(char *errstr,
243                   if (strcmp (arg, ".") != 0)
244                     {
245                       if (!(dom = canonicalise_opt(arg)))
246 -                       ret_err(_("bad domain in dhcp-option"));
247 +                       goto_err(_("bad domain in dhcp-option"));
248                         
249                       domlen = strlen(dom) + 2;
250                     }
251 @@ -1414,7 +1504,7 @@ static int parse_dhcp_opt(char *errstr,
252                 {
253                   char *dom = canonicalise_opt(arg);
254                   if (!dom)
255 -                   ret_err(_("bad domain in dhcp-option"));
256 +                   goto_err(_("bad domain in dhcp-option"));
257                                   
258                   newp = opt_malloc(len + strlen(dom) + 2);
259                   
260 @@ -1452,14 +1542,14 @@ static int parse_dhcp_opt(char *errstr,
261        ((new->len > 255) || 
262        (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
263         (new->len > 250 && (new->flags & DHOPT_RFC3925))))
264 -    ret_err(_("dhcp-option too long"));
265 +    goto_err(_("dhcp-option too long"));
266    
267    if (flags == DHOPT_MATCH)
268      {
269        if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
270           !new->netid ||
271           new->netid->next)
272 -       ret_err(_("illegal dhcp-match"));
273 +       goto_err(_("illegal dhcp-match"));
274         
275        if (is6)
276         {
277 @@ -1484,6 +1574,9 @@ static int parse_dhcp_opt(char *errstr,
278      }
279      
280    return 1;
281 +on_error:
282 +  dhcp_opt_free(new);
283 +  return 0;
284  }
285  
286  #endif
287 @@ -1498,6 +1591,16 @@ void reset_option_bool(unsigned int opt)
288    option_var(opt) &= ~(option_val(opt));
289  }
290  
291 +static void server_list_free(struct server *list)
292 +{
293 +  while (list)
294 +    {
295 +      struct server *tmp = list;
296 +      list = list->next;
297 +      free(tmp);
298 +    }
299 +}
300 +
301  static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
302  {      
303    int i;
304 @@ -1679,13 +1782,13 @@ static int one_opt(int option, char *arg
305               /* has subnet+len */
306               err = parse_mysockaddr(arg, &new->addr);
307               if (err)
308 -               ret_err(err);
309 +               ret_err_free(err, new);
310               if (!atoi_check(end, &new->mask))
311 -               ret_err(gen_err);
312 +               ret_err_free(gen_err, new);
313               new->addr_used = 1;
314             } 
315           else if (!atoi_check(arg, &new->mask))
316 -           ret_err(gen_err);
317 +           ret_err_free(gen_err, new);
318             
319            daemon->add_subnet4 = new;
320  
321 @@ -1697,15 +1800,15 @@ static int one_opt(int option, char *arg
322                   /* has subnet+len */
323                    err = parse_mysockaddr(comma, &new->addr);
324                    if (err)
325 -                    ret_err(err);
326 +                    ret_err_free(err, new);
327                    if (!atoi_check(end, &new->mask))
328 -                    ret_err(gen_err);
329 +                    ret_err_free(gen_err, new);
330                    new->addr_used = 1;
331                  }
332                else
333                  {
334                    if (!atoi_check(comma, &new->mask))
335 -                    ret_err(gen_err);
336 +                    ret_err_free(gen_err, new);
337                  }
338            
339               daemon->add_subnet6 = new;
340 @@ -1912,7 +2015,10 @@ static int one_opt(int option, char *arg
341                   else if (strcmp(fam, "6") == 0)
342                     new->addr.sa.sa_family = AF_INET6;
343                   else
344 -                   ret_err(gen_err);
345 +                 {
346 +                   free(new->name);
347 +                   ret_err_free(gen_err, new);
348 +                 }
349                 } 
350             }
351           new->next = daemon->authinterface;
352 @@ -2077,7 +2183,7 @@ static int one_opt(int option, char *arg
353  
354                       arg = split(netpart);
355                       if (!atoi_check(netpart, &msize))
356 -                       ret_err(gen_err);
357 +                       ret_err_free(gen_err, new);
358                       else if (inet_pton(AF_INET, comma, &new->start))
359                         {
360                           int mask = (1 << (32 - msize)) - 1;
361 @@ -2090,18 +2196,18 @@ static int one_opt(int option, char *arg
362                                 {
363                                   if (!(new->prefix = canonicalise_opt(arg)) ||
364                                       strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
365 -                                   ret_err(_("bad prefix"));
366 +                                   ret_err_free(_("bad prefix"), new);
367                                 }
368                               else if (strcmp(arg, "local") != 0 ||
369                                        (msize != 8 && msize != 16 && msize != 24))
370 -                               ret_err(gen_err);
371 +                               ret_err_free(gen_err, new);
372                               else
373                                 {
374                                    /* generate the equivalent of
375                                       local=/xxx.yyy.zzz.in-addr.arpa/ */
376                                   struct server *serv = add_rev4(new->start, msize);
377                                   if (!serv)
378 -                                   ret_err(_("bad prefix"));
379 +                                   ret_err_free(_("bad prefix"), new);
380  
381                                   serv->flags |= SERV_NO_ADDR;
382  
383 @@ -2130,17 +2236,17 @@ static int one_opt(int option, char *arg
384                           setaddr6part(&new->end6, addrpart | mask);
385                           
386                           if (msize < 64)
387 -                           ret_err(gen_err);
388 +                           ret_err_free(gen_err, new);
389                           else if (arg)
390                             {
391                               if (option != 's')
392                                 {
393                                   if (!(new->prefix = canonicalise_opt(arg)) ||
394                                       strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
395 -                                   ret_err(_("bad prefix"));
396 +                                   ret_err_free(_("bad prefix"), new);
397                                 }       
398                               else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
399 -                               ret_err(gen_err);
400 +                               ret_err_free(gen_err, new);
401                               else 
402                                 {
403                                   /* generate the equivalent of
404 @@ -2159,7 +2265,7 @@ static int one_opt(int option, char *arg
405                             }
406                         }
407                       else
408 -                       ret_err(gen_err);
409 +                       ret_err_free(gen_err, new);
410                     }
411                   else
412                     {
413 @@ -2173,7 +2279,7 @@ static int one_opt(int option, char *arg
414                           if (!arg)
415                             new->end.s_addr = new->start.s_addr;
416                           else if (!inet_pton(AF_INET, arg, &new->end))
417 -                           ret_err(gen_err);
418 +                           ret_err_free(gen_err, new);
419                         }
420                       else if (inet_pton(AF_INET6, comma, &new->start6))
421                         {
422 @@ -2181,16 +2287,16 @@ static int one_opt(int option, char *arg
423                           if (!arg)
424                             memcpy(&new->end6, &new->start6, IN6ADDRSZ);
425                           else if (!inet_pton(AF_INET6, arg, &new->end6))
426 -                           ret_err(gen_err);
427 +                           ret_err_free(gen_err, new);
428                         }
429                       else 
430 -                       ret_err(gen_err);
431 +                       ret_err_free(gen_err, new);
432  
433                       if (option != 's' && prefstr)
434                         {
435                           if (!(new->prefix = canonicalise_opt(prefstr)) ||
436                               strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
437 -                           ret_err(_("bad prefix"));
438 +                           ret_err_free(_("bad prefix"), new);
439                         }
440                     }
441  
442 @@ -2352,7 +2458,7 @@ static int one_opt(int option, char *arg
443  #endif
444           }
445         else
446 -         ret_err(gen_err);
447 +         ret_err_free(gen_err, new);
448  
449         new->used = 0;
450         if (option == 'a')
451 @@ -2423,7 +2529,10 @@ static int one_opt(int option, char *arg
452           {
453             newlist->flags |= SERV_LITERAL_ADDRESS;
454             if (!(newlist->flags & SERV_TYPE))
455 -             ret_err(gen_err);
456 +             {
457 +               server_list_free(newlist);
458 +               ret_err(gen_err);
459 +             }
460           }
461         else if (option == LOPT_NO_REBIND)
462           newlist->flags |= SERV_NO_REBIND;
463 @@ -2440,7 +2549,10 @@ static int one_opt(int option, char *arg
464           {
465             char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
466             if (err)
467 -             ret_err(err);
468 +             {
469 +               server_list_free(newlist);
470 +               ret_err(err);
471 +             }
472           }
473         
474         serv = newlist;
475 @@ -2776,21 +2888,19 @@ static int one_opt(int option, char *arg
476               {
477                 if (is_tag_prefix(arg))
478                   {
479 -                   struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
480 -                   tt->net = opt_string_alloc(arg+4);
481 -                   tt->next = new->filter;
482                     /* ignore empty tag */
483 -                   if (tt->net)
484 -                     new->filter = tt;
485 +                   if (arg[4])
486 +                     new->filter = dhcp_netid_create(arg+4, new->filter);
487                   }
488                 else
489                   {
490                     if (new->netid.net)
491 -                     ret_err(_("only one tag allowed"));
492 -                   else if (strstr(arg, "set:") == arg)
493 -                     new->netid.net = opt_string_alloc(arg+4);
494 +                     {
495 +                       dhcp_context_free(new);
496 +                       ret_err(_("only one tag allowed"));
497 +                     }
498                     else
499 -                     new->netid.net = opt_string_alloc(arg);
500 +                     new->netid.net = opt_string_alloc(set_prefix(arg));
501                   }
502                 arg = comma;
503               }
504 @@ -2806,7 +2916,10 @@ static int one_opt(int option, char *arg
505             break;
506         
507         if (k < 2)
508 -         ret_err(_("bad dhcp-range"));
509 +         {
510 +           dhcp_context_free(new);
511 +           ret_err(_("bad dhcp-range"));
512 +         }
513         
514         if (inet_pton(AF_INET, a[0], &new->start))
515           {
516 @@ -2818,7 +2931,10 @@ static int one_opt(int option, char *arg
517             else if (strcmp(a[1], "proxy") == 0)
518               new->flags |= CONTEXT_PROXY;
519             else if (!inet_pton(AF_INET, a[1], &new->end))
520 -             ret_err(_("bad dhcp-range"));
521 +             {
522 +               dhcp_context_free(new);
523 +               ret_err(_("bad dhcp-range"));
524 +             }
525             
526             if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
527               {
528 @@ -2833,7 +2949,10 @@ static int one_opt(int option, char *arg
529                 new->flags |= CONTEXT_NETMASK;
530                 leasepos = 3;
531                 if (!is_same_net(new->start, new->end, new->netmask))
532 -                 ret_err(_("inconsistent DHCP range"));
533 +                 {
534 +                   dhcp_context_free(new);
535 +                   ret_err(_("inconsistent DHCP range"));
536 +                 }
537                 
538             
539                 if (k >= 4 && strchr(a[3], '.') &&  
540 @@ -2847,6 +2966,8 @@ static int one_opt(int option, char *arg
541  #ifdef HAVE_DHCP6
542         else if (inet_pton(AF_INET6, a[0], &new->start6))
543           {
544 +           const char *err = NULL;
545 +
546             new->flags |= CONTEXT_V6; 
547             new->prefix = 64; /* default */
548             new->end6 = new->start6;
549 @@ -2892,19 +3013,24 @@ static int one_opt(int option, char *arg
550                   }
551               }
552             
553 -           if (new->prefix != 64)
554 +           if (new->prefix > 64)
555               {
556                 if (new->flags & CONTEXT_RA)
557 -                 ret_err(_("prefix length must be exactly 64 for RA subnets"));
558 +                 err=(_("prefix length must be exactly 64 for RA subnets"));
559                 else if (new->flags & CONTEXT_TEMPLATE)
560 -                 ret_err(_("prefix length must be exactly 64 for subnet constructors"));
561 +                 err=(_("prefix length must be exactly 64 for subnet constructors"));
562               }
563 -
564 -           if (new->prefix < 64)
565 -             ret_err(_("prefix length must be at least 64"));
566 +           else if (new->prefix < 64)
567 +             err=(_("prefix length must be at least 64"));
568             
569 -           if (!is_same_net6(&new->start6, &new->end6, new->prefix))
570 -             ret_err(_("inconsistent DHCPv6 range"));
571 +           if (!err && !is_same_net6(&new->start6, &new->end6, new->prefix))
572 +             err=(_("inconsistent DHCPv6 range"));
573 +
574 +           if (err)
575 +             {
576 +               dhcp_context_free(new);
577 +               ret_err(err);
578 +             }
579  
580             /* dhcp-range=:: enables DHCP stateless on any interface */
581             if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
582 @@ -2915,7 +3041,10 @@ static int one_opt(int option, char *arg
583                 struct in6_addr zero;
584                 memset(&zero, 0, sizeof(zero));
585                 if (!is_same_net6(&zero, &new->start6, new->prefix))
586 -                 ret_err(_("prefix must be zero with \"constructor:\" argument"));
587 +                 {
588 +                   dhcp_context_free(new);
589 +                   ret_err(_("prefix must be zero with \"constructor:\" argument"));
590 +                 }
591               }
592             
593             if (addr6part(&new->start6) > addr6part(&new->end6))
594 @@ -2927,12 +3056,18 @@ static int one_opt(int option, char *arg
595           }
596  #endif
597         else
598 -         ret_err(_("bad dhcp-range"));
599 +         {
600 +           dhcp_context_free(new);
601 +           ret_err(_("bad dhcp-range"));
602 +         }
603         
604         if (leasepos < k)
605           {
606             if (leasepos != k-1)
607 -             ret_err(_("bad dhcp-range"));
608 +             {
609 +               dhcp_context_free(new);
610 +               ret_err(_("bad dhcp-range"));
611 +             }
612             
613             if (strcmp(a[leasepos], "infinite") == 0)
614               new->lease_time = 0xffffffff;
615 @@ -2971,7 +3106,7 @@ static int one_opt(int option, char *arg
616                         break;
617  
618                     if (*cp || (leasepos+1 < k))
619 -                     ret_err(_("bad dhcp-range"));
620 +                     ret_err_free(_("bad dhcp-range"), new);
621                     
622                     new->lease_time = atoi(a[leasepos]) * fac;
623                     /* Leases of a minute or less confuse
624 @@ -2998,6 +3133,7 @@ static int one_opt(int option, char *arg
625         new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
626         new->hwaddr = NULL;
627         new->netid = NULL;
628 +       new->clid = NULL;
629  
630         if ((a[0] = arg))
631           for (k = 1; k < 7; k++)
632 @@ -3028,7 +3164,10 @@ static int one_opt(int option, char *arg
633                         }
634  
635                       if (len == -1)
636 -                       ret_err(_("bad hex constant"));
637 +                       {
638 +                         dhcp_config_free(new);
639 +                         ret_err(_("bad hex constant"));
640 +                       }
641                       else if ((new->clid = opt_malloc(len)))
642                         {
643                           new->flags |= CONFIG_CLID;
644 @@ -3040,17 +3179,17 @@ static int one_opt(int option, char *arg
645               /* dhcp-host has strange backwards-compat needs. */
646               else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
647                 {
648 -                 struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
649                   struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
650 -                 newtag->net = opt_malloc(strlen(arg + 4) + 1);
651                   newlist->next = new->netid;
652                   new->netid = newlist;
653 -                 newlist->list = newtag;
654 -                 strcpy(newtag->net, arg+4);
655 -                 unhide_metas(newtag->net);
656 +                 newlist->list = dhcp_netid_create(arg+4, NULL);
657                 }
658               else if (strstr(arg, "tag:") == arg)
659 -               ret_err(_("cannot match tags in --dhcp-host"));
660 +               {
661 +                 
662 +                 dhcp_config_free(new);
663 +                 ret_err(_("cannot match tags in --dhcp-host"));
664 +               }
665  #ifdef HAVE_DHCP6
666               else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
667                 {
668 @@ -3058,7 +3197,10 @@ static int one_opt(int option, char *arg
669                   arg++;
670                   
671                   if (!inet_pton(AF_INET6, arg, &new->addr6))
672 -                   ret_err(_("bad IPv6 address"));
673 +                   {
674 +                     dhcp_config_free(new);
675 +                     ret_err(_("bad IPv6 address"));
676 +                   }
677  
678                   for (i= 0; i < 8; i++)
679                     if (new->addr6.s6_addr[i] != 0)
680 @@ -3076,10 +3218,13 @@ static int one_opt(int option, char *arg
681                   struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
682                   if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX, 
683                                                      &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
684 -                   ret_err(_("bad hex constant"));
685 +                   {
686 +                     free(newhw);
687 +                     dhcp_config_free(new);
688 +                     ret_err(_("bad hex constant"));
689 +                   }
690                   else
691                     {
692 -                     
693                       newhw->next = new->hwaddr;
694                       new->hwaddr = newhw;
695                     }               
696 @@ -3156,7 +3301,10 @@ static int one_opt(int option, char *arg
697                     {
698                       if (!(new->hostname = canonicalise_opt(a[j])) ||
699                           !legal_hostname(new->hostname))
700 -                       ret_err(_("bad DHCP host name"));
701 +                       {
702 +                         dhcp_config_free(new);
703 +                         ret_err(_("bad DHCP host name"));
704 +                       }
705                      
706                       new->flags |= CONFIG_NAME;
707                       new->domain = strip_hostname(new->hostname);                      
708 @@ -3209,10 +3357,7 @@ static int one_opt(int option, char *arg
709               }
710             else
711               {
712 -               struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
713 -               newtag->net = opt_malloc(len - 3);
714 -               strcpy(newtag->net, arg+4);
715 -               unhide_metas(newtag->net);
716 +               struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL);
717  
718                 if (strstr(arg, "set:") == arg)
719                   {
720 @@ -3229,7 +3374,7 @@ static int one_opt(int option, char *arg
721                 else 
722                   {
723                     new->set = NULL;
724 -                   free(newtag);
725 +                   dhcp_netid_free(newtag);
726                     break;
727                   }
728               }
729 @@ -3238,7 +3383,11 @@ static int one_opt(int option, char *arg
730           }
731  
732         if (!new->set)
733 -         ret_err(_("bad tag-if"));
734 +         {
735 +           dhcp_netid_free(new->tag);
736 +           dhcp_netid_list_free(new->set);
737 +           ret_err_free(_("bad tag-if"), new);
738 +         }
739           
740         break;
741        }
742 @@ -3281,19 +3430,12 @@ static int one_opt(int option, char *arg
743        
744      case 'M': /* --dhcp-boot */
745        {
746 -       struct dhcp_netid *id = NULL;
747 -       while (is_tag_prefix(arg))
748 -         {
749 -           struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
750 -           newid->next = id;
751 -           id = newid;
752 -           comma = split(arg);
753 -           newid->net = opt_string_alloc(arg+4);
754 -           arg = comma;
755 -         };
756 +       struct dhcp_netid *id = dhcp_tags(&arg);
757         
758 -       if (!arg)
759 -         ret_err(gen_err);
760 +       if (!id)
761 +         {
762 +           ret_err(gen_err);
763 +         }
764         else 
765           {
766             char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
767 @@ -3339,19 +3481,12 @@ static int one_opt(int option, char *arg
768  
769      case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
770        {
771 -       struct dhcp_netid *id = NULL;
772 -       while (is_tag_prefix(arg))
773 -         {
774 -           struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
775 -           newid->next = id;
776 -           id = newid;
777 -           comma = split(arg);
778 -           newid->net = opt_string_alloc(arg+4);
779 -           arg = comma;
780 -         };
781 +       struct dhcp_netid *id = dhcp_tags(&arg);
782         
783 -       if (!arg)
784 -         ret_err(gen_err);
785 +       if (!id)
786 +         {
787 +           ret_err(gen_err);
788 +         }
789         else
790           {
791             struct delay_config *new;
792 @@ -3376,19 +3511,13 @@ static int one_opt(int option, char *arg
793          
794          new->netid = NULL;
795          new->opt = 10; /* PXE_MENU_PROMPT */
796 -
797 -        while (is_tag_prefix(arg))
798 -         {
799 -            struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
800 -            comma = split(arg);
801 -            nn->next = new->netid;
802 -            new->netid = nn;
803 -            nn->net = opt_string_alloc(arg+4);
804 -            arg = comma;
805 -          }
806 +        new->netid = dhcp_tags(&arg);
807          
808 -        if (!arg)
809 -          ret_err(gen_err);
810 +        if (!new->netid)
811 +          {
812 +            dhcp_opt_free(new);
813 +            ret_err(gen_err);
814 +          }
815          else
816            {
817              comma = split(arg);
818 @@ -3424,17 +3553,8 @@ static int one_opt(int option, char *arg
819          new->netid = NULL;
820          new->sname = NULL;
821          new->server.s_addr = 0;
822 +        new->netid = dhcp_tags(&arg);
823  
824 -        while (is_tag_prefix(arg))
825 -          {
826 -            struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
827 -            comma = split(arg);
828 -            nn->next = new->netid;
829 -            new->netid = nn;
830 -            nn->net = opt_string_alloc(arg+4);
831 -            arg = comma;
832 -          }
833 -       
834          if (arg && (comma = split(arg)))
835            {
836              for (i = 0; CSA[i]; i++)
837 @@ -3511,7 +3631,10 @@ static int one_opt(int option, char *arg
838             unhide_metas(comma);
839             new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
840             if (new->hwaddr_len == -1)
841 -             ret_err(gen_err);
842 +             {
843 +               free(new->netid.net);
844 +               ret_err_free(gen_err, new);
845 +             }
846             else
847               {
848                 new->next = daemon->dhcp_macs;
849 @@ -3528,7 +3651,7 @@ static int one_opt(int option, char *arg
850         
851         if (!(comma = split(arg)) ||
852             !atoi_check16(comma, &new->class))
853 -         ret_err(gen_err);
854 +         ret_err_free(gen_err, new);
855         
856         new->tag.net = opt_string_alloc(set_prefix(arg));
857         new->next = daemon->prefix_classes;
858 @@ -3550,7 +3673,7 @@ static int one_opt(int option, char *arg
859          struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
860          
861          if (!(comma = split(arg)))
862 -          ret_err(gen_err);
863 +          ret_err_free(gen_err, new);
864         
865          new->netid.net = opt_string_alloc(set_prefix(arg));
866          /* check for hex string - must digits may include : must not have nothing else, 
867 @@ -3560,7 +3683,10 @@ static int one_opt(int option, char *arg
868          if ((comma = split(arg)))
869            {
870              if (option  != 'U' || strstr(arg, "enterprise:") != arg)
871 -              ret_err(gen_err);
872 +              {
873 +                free(new->netid.net);
874 +                ret_err_free(gen_err, new);
875 +              }
876              else
877                new->enterprise = atoi(arg+11);
878            }
879 @@ -3662,14 +3788,8 @@ static int one_opt(int option, char *arg
880           }
881         
882         while (arg) {
883 -         struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
884           comma = split(arg);
885 -         member->next = list;
886 -         list = member;
887 -         if (is_tag_prefix(arg))
888 -           member->net = opt_string_alloc(arg+4);
889 -         else
890 -           member->net = opt_string_alloc(arg);
891 +         list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list);
892           arg = comma;
893         }
894         
895 @@ -3683,7 +3803,7 @@ static int one_opt(int option, char *arg
896         struct addr_list *new = opt_malloc(sizeof(struct addr_list));
897         comma = split(arg);
898         if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
899 -         ret_err(_("bad dhcp-proxy address"));
900 +         ret_err_free(_("bad dhcp-proxy address"), new);
901         new->next = daemon->override_relays;
902         daemon->override_relays = new;
903         arg = comma;
904 @@ -3709,7 +3829,10 @@ static int one_opt(int option, char *arg
905           }
906  #endif
907         else
908 -         ret_err(_("Bad dhcp-relay"));
909 +         {
910 +           free(new->interface);
911 +           ret_err_free(_("Bad dhcp-relay"), new);
912 +         }
913         
914         break;
915        }
916 @@ -3749,8 +3872,11 @@ static int one_opt(int option, char *arg
917            arg = split(comma);
918            if (!atoi_check(comma, &new->interval) || 
919               (arg && !atoi_check(arg, &new->lifetime)))
920 +             {
921  err:
922 -           ret_err(_("bad RA-params"));
923 +              free(new->name);
924 +              ret_err_free(_("bad RA-params"), new);
925 +             }
926           
927           new->next = daemon->ra_interfaces;
928           daemon->ra_interfaces = new;
929 @@ -3799,7 +3925,7 @@ err:
930             (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
931              !is_same_net(new->in, new->end, new->mask) ||
932              ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
933 -         ret_err(_("invalid alias range"));
934 +         ret_err_free(_("invalid alias range"), new);
935         
936         break;
937        }
938 @@ -3832,7 +3958,7 @@ err:
939             else if (strcmp(arg, "6") == 0)
940               new->family = AF_INET6;
941             else
942 -             ret_err(gen_err);
943 +             ret_err_free(gen_err, new);
944           } 
945         new->intr = opt_string_alloc(comma);
946         break;
947 @@ -3864,11 +3990,19 @@ err:
948             alias = canonicalise_opt(arg);
949  
950             if (!alias || !target)
951 -             ret_err(_("bad CNAME"));
952 +             {
953 +               free(target);
954 +               free(alias);
955 +               ret_err(_("bad CNAME"));
956 +             }
957             
958             for (new = daemon->cnames; new; new = new->next)
959               if (hostname_isequal(new->alias, alias))
960 -               ret_err(_("duplicate CNAME"));
961 +               {
962 +                 free(target);
963 +                 free(alias);
964 +                 ret_err(_("duplicate CNAME"));
965 +               }
966             new = opt_malloc(sizeof(struct cname));
967             new->next = daemon->cnames;
968             daemon->cnames = new;
969 @@ -3891,7 +4025,11 @@ err:
970         
971         if (!(dom = canonicalise_opt(arg)) ||
972             (comma && !(target = canonicalise_opt(comma))))
973 -         ret_err(_("bad PTR record"));
974 +         {
975 +           free(dom);
976 +           free(target);
977 +           ret_err(_("bad PTR record"));
978 +         }
979         else
980           {
981             new = opt_malloc(sizeof(struct ptr_record));
982 @@ -3909,7 +4047,7 @@ err:
983         int k = 0;
984         struct naptr *new;
985         int order, pref;
986 -       char *name, *replace = NULL;
987 +       char *name=NULL, *replace = NULL;
988  
989         if ((a[0] = arg))
990           for (k = 1; k < 7; k++)
991 @@ -3922,7 +4060,11 @@ err:
992             !atoi_check16(a[1], &order) || 
993             !atoi_check16(a[2], &pref) ||
994             (k == 7 && !(replace = canonicalise_opt(a[6]))))
995 -         ret_err(_("bad NAPTR record"));
996 +          {
997 +           free(name);
998 +           free(replace);
999 +           ret_err(_("bad NAPTR record"));
1000 +          }
1001         else
1002           {
1003             new = opt_malloc(sizeof(struct naptr));
1004 @@ -3944,22 +4086,26 @@ err:
1005                 struct txt_record *new;
1006         size_t len = 0;
1007         char *data;
1008 -       int val;
1009 +       int class;
1010  
1011         comma = split(arg);
1012         data = split(comma);
1013                 
1014         new = opt_malloc(sizeof(struct txt_record));
1015 -       new->next = daemon->rr;
1016 -       daemon->rr = new;
1017 +       new->name = NULL;
1018         
1019 -       if (!atoi_check(comma, &val) || 
1020 +       if (!atoi_check(comma, &class) || 
1021             !(new->name = canonicalise_opt(arg)) ||
1022             (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
1023 -         ret_err(_("bad RR record"));
1024 -               
1025 -       new->class = val;
1026 +          {
1027 +            free(new->name);
1028 +           ret_err_free(_("bad RR record"), new);
1029 +          }
1030 +
1031         new->len = 0;
1032 +       new->class = class;
1033 +       new->next = daemon->rr;
1034 +       daemon->rr = new;
1035         
1036         if (data)
1037           {
1038 @@ -4011,14 +4157,14 @@ err:
1039         comma = split(arg);
1040                 
1041         new = opt_malloc(sizeof(struct txt_record));
1042 -       new->next = daemon->txt;
1043 -       daemon->txt = new;
1044         new->class = C_IN;
1045         new->stat = 0;
1046  
1047         if (!(new->name = canonicalise_opt(arg)))
1048 -         ret_err(_("bad TXT record"));
1049 +         ret_err_free(_("bad TXT record"), new);
1050         
1051 +       new->next = daemon->txt;
1052 +       daemon->txt = new;
1053         len = comma ? strlen(comma) : 0;
1054         len += (len/255) + 1; /* room for extra counts */
1055         new->txt = p = opt_malloc(len);
1056 @@ -4065,24 +4211,32 @@ err:
1057             arg = comma;
1058             comma = split(arg);
1059             if (!(target = canonicalise_opt(arg)))
1060 -             ret_err(_("bad SRV target"));
1061 +             ret_err_free(_("bad SRV target"), name);
1062                 
1063             if (comma)
1064               {
1065                 arg = comma;
1066                 comma = split(arg);
1067                 if (!atoi_check16(arg, &port))
1068 -                 ret_err(_("invalid port number"));
1069 +                  {
1070 +                    free(name);
1071 +                   ret_err_free(_("invalid port number"), target);
1072 +                  }
1073                 
1074                 if (comma)
1075                   {
1076                     arg = comma;
1077                     comma = split(arg);
1078                     if (!atoi_check16(arg, &priority))
1079 -                     ret_err(_("invalid priority"));
1080 -                       
1081 +                      {
1082 +                        free(name);
1083 +                       ret_err_free(_("invalid priority"), target);
1084 +                     }
1085                     if (comma && !atoi_check16(comma, &weight))
1086 -                     ret_err(_("invalid weight"));
1087 +                      {
1088 +                        free(name);
1089 +                       ret_err_free(_("invalid weight"), target);
1090 +                      }
1091                   }
1092               }
1093           }
1094 @@ -4101,13 +4255,15 @@ err:
1095        
1096      case LOPT_HOST_REC: /* --host-record */
1097        {
1098 -       struct host_record *new = opt_malloc(sizeof(struct host_record));
1099 -       memset(new, 0, sizeof(struct host_record));
1100 -       new->ttl = -1;
1101 +       struct host_record *new;
1102  
1103         if (!arg || !(comma = split(arg)))
1104           ret_err(_("Bad host-record"));
1105         
1106 +       new = opt_malloc(sizeof(struct host_record));
1107 +       memset(new, 0, sizeof(struct host_record));
1108 +       new->ttl = -1;
1109 +
1110         while (arg)
1111           {
1112             struct all_addr addr;
1113 @@ -4126,10 +4282,19 @@ err:
1114               {
1115                 int nomem;
1116                 char *canon = canonicalise(arg, &nomem);
1117 -               struct name_list *nl = opt_malloc(sizeof(struct name_list));
1118 +               struct name_list *nl;
1119                 if (!canon)
1120 -                 ret_err(_("Bad name in host-record"));
1121 +                  {
1122 +                   struct name_list *tmp = new->names, *next;
1123 +                   for (tmp = new->names; tmp; tmp = next)
1124 +                     {
1125 +                       next = tmp->next;
1126 +                       free(tmp);
1127 +                     }
1128 +                   ret_err_free(_("Bad name in host-record"), new);
1129 +                  }
1130  
1131 +               nl = opt_malloc(sizeof(struct name_list));
1132                 nl->name = canon;
1133                 /* keep order, so that PTR record goes to first name */
1134                 nl->next = NULL;
1135 @@ -4179,6 +4344,7 @@ err:
1136         int len;
1137         
1138         new->class = C_IN;
1139 +       new->name = NULL;
1140  
1141         if ((comma = split(arg)) && (algo = split(comma)))
1142           {
1143 @@ -4203,7 +4369,7 @@ err:
1144             !atoi_check8(algo, &new->algo) ||
1145             !atoi_check8(digest, &new->digest_type) ||
1146             !(new->name = canonicalise_opt(arg)))
1147 -         ret_err(_("bad trust anchor"));
1148 +         ret_err_free(_("bad trust anchor"), new);
1149             
1150         /* Upper bound on length */
1151         len = (2*strlen(keyhex))+1;
1152 @@ -4217,7 +4383,10 @@ err:
1153           else
1154             cp++;
1155         if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
1156 -         ret_err(_("bad HEX in trust anchor"));
1157 +         {
1158 +           free(new->name);
1159 +           ret_err_free(_("bad HEX in trust anchor"), new);
1160 +         }
1161         
1162         new->next = daemon->ds;
1163         daemon->ds = new;
1164 @@ -4686,8 +4855,8 @@ void read_opts(int argc, char **argv, ch
1165    size_t argbuf_size = MAXDNAME;
1166    char *argbuf = opt_malloc(argbuf_size);
1167    char *buff = opt_malloc(MAXDNAME);
1168 -  int option, conffile_opt = '7', testmode = 0;
1169 -  char *arg, *conffile = CONFFILE;
1170 +  int option, testmode = 0;
1171 +  char *arg, *conffile = NULL;
1172        
1173    opterr = 0;
1174  
1175 @@ -4796,7 +4965,8 @@ void read_opts(int argc, char **argv, ch
1176          }
1177        else if (option == 'C')
1178         {
1179 -         conffile_opt = 0; /* file must exist */
1180 +          if (conffile)
1181 +            free(conffile);
1182           conffile = opt_string_alloc(arg);
1183         }
1184        else
1185 @@ -4814,10 +4984,11 @@ void read_opts(int argc, char **argv, ch
1186  
1187    if (conffile)
1188      {
1189 -      one_file(conffile, conffile_opt);
1190 -      if (conffile_opt == 0)
1191 -       free(conffile);
1192 +      one_file(conffile, 0);
1193 +      free(conffile);
1194      }
1195 +  else
1196 +    one_file(CONFFILE, '7');
1197  
1198    /* port might not be known when the address is parsed - fill in here */
1199    if (daemon->servers)