Blame SOURCES/dnsmasq-2.79-rh1602477.patch

85f98a
From 8e11d702921e51a5eb00b9ee12925cae69039c22 Mon Sep 17 00:00:00 2001
85f98a
From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com>
85f98a
Date: Thu, 18 Jul 2019 18:49:30 +0200
85f98a
Subject: [PATCH] Fix issues detected by Coverity
85f98a
MIME-Version: 1.0
85f98a
Content-Type: text/plain; charset=UTF-8
85f98a
Content-Transfer-Encoding: 8bit
85f98a
85f98a
Squashed commit of the following:
85f98a
85f98a
commit 6a5fa6c9207961a662f8debbe9172500c752e3ac
85f98a
Author: Kevin Darbyshire-Bryant <kevin@darbyshire-bryant.me.uk>
85f98a
Date:   Mon Dec 10 10:34:35 2018 +0000
85f98a
85f98a
    build failure on master with NO_DHCPv6 and fix....
85f98a
85f98a
    Hi Simon,
85f98a
85f98a
    master has a build error when building without HAVE_DHCPv6
85f98a
85f98a
    option.c: In function 'dhcp_context_free':
85f98a
    option.c:1042:15: error: 'struct dhcp_context' has no member named 'template_interface'
85f98a
           free(ctx->template_interface);
85f98a
85f98a
    Sadly, need to put in a little conditional compilation ifdef'erey
85f98a
85f98a
    Simplest patch in the world attached
85f98a
85f98a
    Cheers,
85f98a
85f98a
    Kevin D-B
85f98a
85f98a
    012C ACB2 28C6 C53E 9775  9123 B3A2 389B 9DE2 334A
85f98a
85f98a
    From 061eb8599636bb360e0b7fa5986935b86db39497 Mon Sep 17 00:00:00 2001
85f98a
    From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
85f98a
    Date: Mon, 10 Dec 2018 10:07:33 +0000
85f98a
    Subject: [PATCH] option: fix non DHCPv6 build error
85f98a
85f98a
    option.c: In function 'dhcp_context_free':
85f98a
    option.c:1042:15: error: 'struct dhcp_context' has no member named 'template_interface'
85f98a
           free(ctx->template_interface);
85f98a
    		^~
85f98a
85f98a
    Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
85f98a
    (cherry picked from commit b683cf37f9f3dd3dc5d95d621ee75850d559b2e4)
85f98a
85f98a
commit a4be120618a5d8517d23e687003cab53e7db11c9
85f98a
Author: Petr Menšík <pemensik@redhat.com>
85f98a
Date:   Sun Dec 16 21:25:29 2018 +0000
85f98a
85f98a
    Fix option parsing errors introduced in 59e470381f84f2fdf0640c7bc67827f3f0c64784
85f98a
85f98a
    Thanks to Kevin Darbyshire-Bryant for spotting this.
85f98a
85f98a
    (cherry picked from commit 137e9f878fafb38369eab7d9dfe84e4228ff5f89)
85f98a
85f98a
commit 3e0752faa67ffd25893ebbcbe6a5788699a2e1c9
85f98a
Author: Petr Menšík <pemensik@redhat.com>
85f98a
Date:   Fri Nov 2 22:39:39 2018 +0000
85f98a
85f98a
    Free config file values on parsing errors.
85f98a
85f98a
    This time I have a little bit more controversal patches. But I think
85f98a
    still useful. They fixes memory leaks that might occur in some cases.
85f98a
    Most dnsmasq errors is fatal, so it does not matter. But some are not.
85f98a
    Some parts are reloaded on SIGHUP signal, so it might leak more than once.
85f98a
85f98a
    Some example when it changes the failures. Use dhcp-options file with
85f98a
    this content:
85f98a
85f98a
    tag:error,vendor:redhat
85f98a
    option:ntp-server,1.2.3.4.5
85f98a
    option6:ntp-server,[:::]
85f98a
85f98a
    Is not fatal and dnsmasq will start. On each reload command, it would
85f98a
    leak some memory. I validated it using valgrind --leak-check=full
85f98a
    dnsmasq -d. This patch fixes it. It introduces something that might be
85f98a
    considered constructor and destructor of selected structures.
85f98a
85f98a
    (cherry picked from commit 59e470381f84f2fdf0640c7bc67827f3f0c64784)
85f98a
85f98a
commit c2a44c21dddffff95346c931feda696704ea73ca
85f98a
Author: Petr Menšík <pemensik@redhat.com>
85f98a
Date:   Wed Oct 24 22:30:18 2018 +0100
85f98a
85f98a
    Do not rely on dead code elimination, use array instead.
85f98a
    Make options bits derived from size and count. Use size of option bits
85f98a
    and last supported bit in computation. No new change would be required
85f98a
    when new options are added. Just change OPT_LAST constant.
85f98a
85f98a
    (cherry picked from commit 24b87607c1353e94689e8a2190571ab3f3b36f31)
85f98a
85f98a
commit 5b9f199a1b16b7aa41cf544e9312c93e893206b3
85f98a
Author: Petr Menšík <pemensik@redhat.com>
85f98a
Date:   Fri Aug 17 10:20:05 2018 +0200
85f98a
85f98a
    Minor improvements in lease-tools
85f98a
85f98a
    Limit max interface name to fit into buffer.
85f98a
    Make sure pointer have to be always positive.
85f98a
    Close socket after received reply.
85f98a
85f98a
    (cherry picked from commit 2b38e3823b12ab13f86c3a44648de436daadb1f6)
85f98a
85f98a
commit d30a8f4c46a1b446b7d9932d022a09f1ee6b4554
85f98a
Author: Petr Menšík <pemensik@redhat.com>
85f98a
Date:   Thu Aug 16 15:48:15 2018 +0200
85f98a
85f98a
    Close socket after received reply
85f98a
85f98a
commit 6e5dedbb8aa3d27c9477558e66f9d260414340a3
85f98a
Author: Petr Menšík <pemensik@redhat.com>
85f98a
Date:   Wed Aug 15 19:41:07 2018 +0200
85f98a
85f98a
    Mark die function as never returning
85f98a
85f98a
    Improves static analysis output and reduces false positives.
85f98a
85f98a
commit 3d7e9ba115d3c229d678814103dbf3401738dcf5
85f98a
Author: Petr Menšík <pemensik@redhat.com>
85f98a
Date:   Wed Aug 15 18:17:00 2018 +0200
85f98a
85f98a
    Fix lengths of interface names
85f98a
85f98a
    Use helper function similar to copy correctly limited names into
85f98a
    buffers.
85f98a
---
85f98a
 contrib/lease-tools/dhcp_lease_time.c |   2 +-
85f98a
 contrib/lease-tools/dhcp_release.c    |   3 +-
85f98a
 contrib/lease-tools/dhcp_release6.c   |   5 +-
85f98a
 src/bpf.c                             |   2 +-
85f98a
 src/dhcp.c                            |   9 +-
85f98a
 src/dnsmasq.h                         |  20 +-
85f98a
 src/log.c                             |   2 +-
85f98a
 src/network.c                         |  12 +-
85f98a
 src/option.c                          | 548 +++++++++++++++++---------
85f98a
 src/rfc2131.c                         |  10 +-
85f98a
 src/tftp.c                            |   2 +-
85f98a
 src/util.c                            |  12 +-
85f98a
 12 files changed, 408 insertions(+), 219 deletions(-)
85f98a
85f98a
diff --git a/contrib/lease-tools/dhcp_lease_time.c b/contrib/lease-tools/dhcp_lease_time.c
85f98a
index f9d7a85..697d627 100644
85f98a
--- a/contrib/lease-tools/dhcp_lease_time.c
85f98a
+++ b/contrib/lease-tools/dhcp_lease_time.c
85f98a
@@ -83,7 +83,7 @@ static unsigned char *option_find1(unsigned char *p, unsigned char *end, int opt
85f98a
           if (p >= end - 2)
85f98a
             return NULL; /* malformed packet */
85f98a
           opt_len = option_len(p);
85f98a
-          if (p >= end - (2 + opt_len))
85f98a
+          if (end - p >= (2 + opt_len))
85f98a
             return NULL; /* malformed packet */
85f98a
           if (*p == opt && opt_len >= minsize)
85f98a
             return p;
85f98a
diff --git a/contrib/lease-tools/dhcp_release.c b/contrib/lease-tools/dhcp_release.c
85f98a
index 201fcd3..59883d4 100644
85f98a
--- a/contrib/lease-tools/dhcp_release.c
85f98a
+++ b/contrib/lease-tools/dhcp_release.c
85f98a
@@ -270,7 +270,8 @@ int main(int argc, char **argv)
85f98a
   
85f98a
   /* This voodoo fakes up a packet coming from the correct interface, which really matters for 
85f98a
      a DHCP server */
85f98a
-  strcpy(ifr.ifr_name, argv[1]);
85f98a
+  strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)-1);
85f98a
+  ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
85f98a
   if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1)
85f98a
     {
85f98a
       perror("cannot setup interface");
85f98a
diff --git a/contrib/lease-tools/dhcp_release6.c b/contrib/lease-tools/dhcp_release6.c
85f98a
index 7f79fa7..d680222 100644
85f98a
--- a/contrib/lease-tools/dhcp_release6.c
85f98a
+++ b/contrib/lease-tools/dhcp_release6.c
85f98a
@@ -376,9 +376,12 @@ int send_release_packet(const char* iface, struct dhcp6_packet* packet)
85f98a
             sleep(1);
85f98a
             continue;
85f98a
 	  }
85f98a
+
85f98a
+        close(sock);
85f98a
         return result;
85f98a
       }
85f98a
-    
85f98a
+
85f98a
+    close(sock);
85f98a
     fprintf(stderr, "Response timed out\n");
85f98a
     return -1;   
85f98a
 }
85f98a
diff --git a/src/bpf.c b/src/bpf.c
85f98a
index 49a11bf..ff66d6d 100644
85f98a
--- a/src/bpf.c
85f98a
+++ b/src/bpf.c
85f98a
@@ -169,7 +169,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
85f98a
 	      struct in6_ifreq ifr6;
85f98a
 
85f98a
 	      memset(&ifr6, 0, sizeof(ifr6));
85f98a
-	      strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
85f98a
+	      safe_strncpy(ifr6.ifr_name, addrs->ifa_name, sizeof(ifr6.ifr_name));
85f98a
 	      
85f98a
 	      ifr6.ifr_addr = *((struct sockaddr_in6 *) addrs->ifa_addr);
85f98a
 	      if (fd != -1 && ioctl(fd, SIOCGIFAFLAG_IN6, &ifr6) != -1)
85f98a
diff --git a/src/dhcp.c b/src/dhcp.c
85f98a
index 5a8daec..26f3287 100644
85f98a
--- a/src/dhcp.c
85f98a
+++ b/src/dhcp.c
85f98a
@@ -232,7 +232,7 @@ void dhcp_packet(time_t now, int pxe_fd)
85f98a
   
85f98a
 #ifdef HAVE_LINUX_NETWORK
85f98a
   /* ARP fiddling uses original interface even if we pretend to use a different one. */
85f98a
-  strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
85f98a
+  safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
85f98a
 #endif 
85f98a
 
85f98a
   /* If the interface on which the DHCP request was received is an
85f98a
@@ -255,7 +255,7 @@ void dhcp_packet(time_t now, int pxe_fd)
85f98a
 	      }
85f98a
 	    else 
85f98a
 	      {
85f98a
-		strncpy(ifr.ifr_name,  bridge->iface, IF_NAMESIZE);
85f98a
+		safe_strncpy(ifr.ifr_name,  bridge->iface, sizeof(ifr.ifr_name));
85f98a
 		break;
85f98a
 	      }
85f98a
 	  }
85f98a
@@ -279,7 +279,7 @@ void dhcp_packet(time_t now, int pxe_fd)
85f98a
       is_relay_reply = 1; 
85f98a
       iov.iov_len = sz;
85f98a
 #ifdef HAVE_LINUX_NETWORK
85f98a
-      strncpy(arp_req.arp_dev, ifr.ifr_name, 16);
85f98a
+      safe_strncpy(arp_req.arp_dev, ifr.ifr_name, sizeof(arp_req.arp_dev));
85f98a
 #endif 
85f98a
     }
85f98a
   else
85f98a
@@ -988,8 +988,7 @@ char *host_from_dns(struct in_addr addr)
85f98a
       if (!legal_hostname(hostname))
85f98a
 	return NULL;
85f98a
       
85f98a
-      strncpy(daemon->dhcp_buff, hostname, 256);
85f98a
-      daemon->dhcp_buff[255] = 0;
85f98a
+      safe_strncpy(daemon->dhcp_buff, hostname, 256);
85f98a
       strip_hostname(daemon->dhcp_buff);
85f98a
 
85f98a
       return daemon->dhcp_buff;
85f98a
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
85f98a
index 6773b69..6b18bb7 100644
85f98a
--- a/src/dnsmasq.h
85f98a
+++ b/src/dnsmasq.h
85f98a
@@ -42,6 +42,12 @@
85f98a
 #  define __EXTENSIONS__
85f98a
 #endif
85f98a
 
85f98a
+#if (defined(__GNUC__) && __GNUC__ >= 3) || defined(__clang__)
85f98a
+#define ATTRIBUTE_NORETURN __attribute__ ((noreturn))
85f98a
+#else
85f98a
+#define ATTRIBUTE_NORETURN
85f98a
+#endif
85f98a
+
85f98a
 /* get these before config.h  for IPv6 stuff... */
85f98a
 #include <sys/types.h> 
85f98a
 #include <sys/socket.h>
85f98a
@@ -190,9 +196,6 @@ struct event_desc {
85f98a
 #define EC_MISC        5
85f98a
 #define EC_INIT_OFFSET 10
85f98a
 
85f98a
-/* Trust the compiler dead-code eliminator.... */
85f98a
-#define option_bool(x) (((x) < 32) ? daemon->options & (1u << (x)) : daemon->options2 & (1u << ((x) - 32)))
85f98a
-
85f98a
 #define OPT_BOGUSPRIV      0
85f98a
 #define OPT_FILTER         1
85f98a
 #define OPT_LOG            2
85f98a
@@ -252,6 +255,12 @@ struct event_desc {
85f98a
 #define OPT_TFTP_APREF_MAC 56
85f98a
 #define OPT_LAST           57
85f98a
 
85f98a
+#define OPTION_BITS (sizeof(unsigned int)*8)
85f98a
+#define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) )
85f98a
+#define option_var(x) (daemon->options[(x) / OPTION_BITS])
85f98a
+#define option_val(x) ((1u) << ((x) % OPTION_BITS))
85f98a
+#define option_bool(x) (option_var(x) & option_val(x))
85f98a
+
85f98a
 /* extra flags for my_syslog, we use a couple of facilities since they are known 
85f98a
    not to occupy the same bits as priorities, no matter how syslog.h is set up. */
85f98a
 #define MS_TFTP   LOG_USER
85f98a
@@ -947,7 +956,7 @@ extern struct daemon {
85f98a
      config file arguments. All set (including defaults)
85f98a
      in option.c */
85f98a
 
85f98a
-  unsigned int options, options2;
85f98a
+  unsigned int options[OPTION_SIZE];
85f98a
   struct resolvc default_resolv, *resolv_files;
85f98a
   time_t last_resolv;
85f98a
   char *servers_file;
85f98a
@@ -1205,6 +1214,7 @@ int legal_hostname(char *name);
85f98a
 char *canonicalise(char *in, int *nomem);
85f98a
 unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit);
85f98a
 void *safe_malloc(size_t size);
85f98a
+void safe_strncpy(char *dest, const char *src, size_t size);
85f98a
 void safe_pipe(int *fd, int read_noblock);
85f98a
 void *whine_malloc(size_t size);
85f98a
 int sa_len(union mysockaddr *addr);
85f98a
@@ -1233,7 +1243,7 @@ int wildcard_match(const char* wildcard, const char* match);
85f98a
 int wildcard_matchn(const char* wildcard, const char* match, int num);
85f98a
 
85f98a
 /* log.c */
85f98a
-void die(char *message, char *arg1, int exit_code);
85f98a
+void die(char *message, char *arg1, int exit_code) ATTRIBUTE_NORETURN;
85f98a
 int log_start(struct passwd *ent_pw, int errfd);
85f98a
 int log_reopen(char *log_file);
85f98a
 
85f98a
diff --git a/src/log.c b/src/log.c
85f98a
index dae8a75..d0d4780 100644
85f98a
--- a/src/log.c
85f98a
+++ b/src/log.c
85f98a
@@ -232,7 +232,7 @@ static void log_write(void)
85f98a
 	      logaddr.sun_len = sizeof(logaddr) - sizeof(logaddr.sun_path) + strlen(_PATH_LOG) + 1; 
85f98a
 #endif
85f98a
 	      logaddr.sun_family = AF_UNIX;
85f98a
-	      strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
85f98a
+	      safe_strncpy(logaddr.sun_path, _PATH_LOG, sizeof(logaddr.sun_path));
85f98a
 	      
85f98a
 	      /* Got connection back? try again. */
85f98a
 	      if (connect(log_fd, (struct sockaddr *)&logaddr, sizeof(logaddr)) != -1)
85f98a
diff --git a/src/network.c b/src/network.c
85f98a
index 0381513..efb7b03 100644
85f98a
--- a/src/network.c
85f98a
+++ b/src/network.c
85f98a
@@ -29,7 +29,7 @@ int indextoname(int fd, int index, char *name)
85f98a
   if (ioctl(fd, SIOCGIFNAME, &ifr) == -1)
85f98a
     return 0;
85f98a
 
85f98a
-  strncpy(name, ifr.ifr_name, IF_NAMESIZE);
85f98a
+  safe_strncpy(name, ifr.ifr_name, IF_NAMESIZE);
85f98a
 
85f98a
   return 1;
85f98a
 }
85f98a
@@ -82,12 +82,12 @@ int indextoname(int fd, int index, char *name)
85f98a
   for (i = lifc.lifc_len / sizeof(struct lifreq); i; i--, lifrp++) 
85f98a
     {
85f98a
       struct lifreq lifr;
85f98a
-      strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
85f98a
+      safe_strncpy(lifr.lifr_name, lifrp->lifr_name, IF_NAMESIZE);
85f98a
       if (ioctl(fd, SIOCGLIFINDEX, &lifr) < 0) 
85f98a
 	return 0;
85f98a
       
85f98a
       if (lifr.lifr_index == index) {
85f98a
-	strncpy(name, lifr.lifr_name, IF_NAMESIZE);
85f98a
+	safe_strncpy(name, lifr.lifr_name, IF_NAMESIZE);
85f98a
 	return 1;
85f98a
       }
85f98a
     }
85f98a
@@ -188,7 +188,7 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
85f98a
   struct ifreq ifr;
85f98a
   struct irec *iface;
85f98a
 
85f98a
-  strncpy(ifr.ifr_name, name, IF_NAMESIZE);
85f98a
+  safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
85f98a
   if (ioctl(fd, SIOCGIFFLAGS, &ifr) != -1 &&
85f98a
       ifr.ifr_flags & IFF_LOOPBACK)
85f98a
     {
85f98a
@@ -1284,7 +1284,7 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname)
85f98a
       return NULL;
85f98a
     }
85f98a
 
85f98a
-  strcpy(sfd->interface, intname); 
85f98a
+  safe_strncpy(sfd->interface, intname, sizeof(sfd->interface)); 
85f98a
   sfd->source_addr = *addr;
85f98a
   sfd->next = daemon->sfds;
85f98a
   sfd->ifindex = ifindex;
85f98a
@@ -1452,7 +1452,7 @@ void add_update_server(int flags,
85f98a
 	serv->flags |= SERV_HAS_DOMAIN;
85f98a
       
85f98a
       if (interface)
85f98a
-	strcpy(serv->interface, interface);      
85f98a
+	safe_strncpy(serv->interface, interface, sizeof(serv->interface));
85f98a
       if (addr)
85f98a
 	serv->addr = *addr;
85f98a
       if (source_addr)
85f98a
diff --git a/src/option.c b/src/option.c
85f98a
index d358d99..9768efb 100644
85f98a
--- a/src/option.c
85f98a
+++ b/src/option.c
85f98a
@@ -559,14 +559,15 @@ static void *opt_malloc(size_t size)
85f98a
   return ret;
85f98a
 }
85f98a
 
85f98a
-static char *opt_string_alloc(char *cp)
85f98a
+static char *opt_string_alloc(const char *cp)
85f98a
 {
85f98a
   char *ret = NULL;
85f98a
+  size_t len;
85f98a
   
85f98a
-  if (cp && strlen(cp) != 0)
85f98a
+  if (cp && (len = strlen(cp)) != 0)
85f98a
     {
85f98a
-      ret = opt_malloc(strlen(cp)+1);
85f98a
-      strcpy(ret, cp); 
85f98a
+      ret = opt_malloc(len+1);
85f98a
+      memcpy(ret, cp, len+1); 
85f98a
       
85f98a
       /* restore hidden metachars */
85f98a
       unhide_metas(ret);
85f98a
@@ -741,6 +742,8 @@ static void do_usage(void)
85f98a
 }
85f98a
 
85f98a
 #define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
85f98a
+#define ret_err_free(x,m) do { strcpy(errstr, (x)); free((m)); return 0; } while (0)
85f98a
+#define goto_err(x) do { strcpy(errstr, (x)); goto on_error; } while (0)
85f98a
 
85f98a
 static char *parse_mysockaddr(char *arg, union mysockaddr *addr) 
85f98a
 {
85f98a
@@ -792,7 +795,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
85f98a
     if (interface_opt)
85f98a
       {
85f98a
 #if defined(SO_BINDTODEVICE)
85f98a
-	strncpy(interface, interface_opt, IF_NAMESIZE - 1);
85f98a
+	safe_strncpy(interface, interface_opt, IF_NAMESIZE);
85f98a
 #else
85f98a
 	return _("interface binding not supported");
85f98a
 #endif
85f98a
@@ -821,7 +824,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
85f98a
 		return _("interface can only be specified once");
85f98a
 	      
85f98a
 	      source_addr->in.sin_addr.s_addr = INADDR_ANY;
85f98a
-	      strncpy(interface, source, IF_NAMESIZE - 1);
85f98a
+	      safe_strncpy(interface, source, IF_NAMESIZE);
85f98a
 #else
85f98a
 	      return _("interface binding not supported");
85f98a
 #endif
85f98a
@@ -856,7 +859,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
85f98a
 		return _("interface can only be specified once");
85f98a
 	      
85f98a
 	      source_addr->in6.sin6_addr = in6addr_any;
85f98a
-	      strncpy(interface, source, IF_NAMESIZE - 1);
85f98a
+	      safe_strncpy(interface, source, IF_NAMESIZE);
85f98a
 #else
85f98a
 	      return _("interface binding not supported");
85f98a
 #endif
85f98a
@@ -894,6 +897,8 @@ static struct server *add_rev4(struct in_addr addr, int msize)
85f98a
       p += sprintf(p, "%d.", (a >> 24) & 0xff);
85f98a
       break;
85f98a
     default:
85f98a
+      free(serv->domain);
85f98a
+      free(serv);
85f98a
       return NULL;
85f98a
     }
85f98a
 
85f98a
@@ -948,6 +953,99 @@ static char *set_prefix(char *arg)
85f98a
    return arg;
85f98a
 }
85f98a
 
85f98a
+static struct dhcp_netid *
85f98a
+dhcp_netid_create(const char *net, struct dhcp_netid *next)
85f98a
+{
85f98a
+  struct dhcp_netid *tt;
85f98a
+  tt = opt_malloc(sizeof (struct dhcp_netid));
85f98a
+  tt->net = opt_string_alloc(net);
85f98a
+  tt->next = next;
85f98a
+  return tt;
85f98a
+}
85f98a
+
85f98a
+static void dhcp_netid_free(struct dhcp_netid *nid)
85f98a
+{
85f98a
+  while (nid)
85f98a
+    {
85f98a
+      struct dhcp_netid *tmp = nid;
85f98a
+      nid = nid->next;
85f98a
+      free(tmp->net);
85f98a
+      free(tmp);
85f98a
+    }
85f98a
+}
85f98a
+
85f98a
+/* Parse one or more tag:s before parameters.
85f98a
+ * Moves arg to the end of tags. */
85f98a
+static struct dhcp_netid * dhcp_tags(char **arg)
85f98a
+{
85f98a
+  struct dhcp_netid *id = NULL;
85f98a
+
85f98a
+  while (is_tag_prefix(*arg))
85f98a
+    {
85f98a
+      char *comma = split(*arg);
85f98a
+      id = dhcp_netid_create((*arg)+4, id);
85f98a
+      *arg = comma;
85f98a
+    };
85f98a
+  if (!*arg)
85f98a
+    {
85f98a
+      dhcp_netid_free(id);
85f98a
+      id = NULL;
85f98a
+    }
85f98a
+  return id;
85f98a
+}
85f98a
+
85f98a
+static void dhcp_netid_list_free(struct dhcp_netid_list *netid)
85f98a
+{
85f98a
+  while (netid)
85f98a
+    {
85f98a
+      struct dhcp_netid_list *tmplist = netid;
85f98a
+      netid = netid->next;
85f98a
+      dhcp_netid_free(tmplist->list);
85f98a
+      free(tmplist);
85f98a
+    }
85f98a
+}
85f98a
+
85f98a
+static void dhcp_config_free(struct dhcp_config *config)
85f98a
+{
85f98a
+  if (config)
85f98a
+    {
85f98a
+      struct hwaddr_config *hwaddr = config->hwaddr;
85f98a
+      while (hwaddr)
85f98a
+        {
85f98a
+	  struct hwaddr_config *tmp = hwaddr;
85f98a
+          hwaddr = hwaddr->next;
85f98a
+	  free(tmp);
85f98a
+        }
85f98a
+      dhcp_netid_list_free(config->netid);
85f98a
+      if (config->flags & CONFIG_CLID)
85f98a
+        free(config->clid);
85f98a
+      free(config);
85f98a
+    }
85f98a
+}
85f98a
+
85f98a
+static void dhcp_context_free(struct dhcp_context *ctx)
85f98a
+{
85f98a
+  if (ctx)
85f98a
+    {
85f98a
+      dhcp_netid_free(ctx->filter);
85f98a
+      free(ctx->netid.net);
85f98a
+#ifdef HAVE_DHCP6
85f98a
+      free(ctx->template_interface);
85f98a
+#endif
85f98a
+      free(ctx);
85f98a
+    }
85f98a
+}
85f98a
+
85f98a
+static void dhcp_opt_free(struct dhcp_opt *opt)
85f98a
+{
85f98a
+  if (opt->flags & DHOPT_VENDOR)
85f98a
+    free(opt->u.vendor_class);
85f98a
+  dhcp_netid_free(opt->netid);
85f98a
+  free(opt->val);
85f98a
+  free(opt);
85f98a
+}
85f98a
+
85f98a
+
85f98a
 /* This is too insanely large to keep in-line in the switch */
85f98a
 static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
 {
85f98a
@@ -955,7 +1053,6 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
   char lenchar = 0, *cp;
85f98a
   int addrs, digs, is_addr, is_addr6, is_hex, is_dec, is_string, dots;
85f98a
   char *comma = NULL;
85f98a
-  struct dhcp_netid *np = NULL;
85f98a
   u16 opt_len = 0;
85f98a
   int is6 = 0;
85f98a
   int option_ok = 0;
85f98a
@@ -1042,14 +1139,9 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
 	}
85f98a
       else
85f98a
 	{
85f98a
-	  new->netid = opt_malloc(sizeof (struct dhcp_netid));
85f98a
 	  /* allow optional "net:" or "tag:" for consistency */
85f98a
-	  if (is_tag_prefix(arg))
85f98a
-	    new->netid->net = opt_string_alloc(arg+4);
85f98a
-	  else
85f98a
-	    new->netid->net = opt_string_alloc(set_prefix(arg));
85f98a
-	  new->netid->next = np;
85f98a
-	  np = new->netid;
85f98a
+	  const char *name = (is_tag_prefix(arg)) ? arg+4 : set_prefix(arg);
85f98a
+	  new->netid = dhcp_netid_create(name, new->netid);
85f98a
 	}
85f98a
       
85f98a
       arg = comma; 
85f98a
@@ -1059,7 +1151,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
   if (is6)
85f98a
     {
85f98a
       if (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))
85f98a
-	ret_err(_("unsupported encapsulation for IPv6 option"));
85f98a
+	goto_err(_("unsupported encapsulation for IPv6 option"));
85f98a
       
85f98a
       if (opt_len == 0 &&
85f98a
 	  !(new->flags & DHOPT_RFC3925))
85f98a
@@ -1073,7 +1165,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
   
85f98a
   /* option may be missing with rfc3925 match */
85f98a
   if (!option_ok)
85f98a
-    ret_err(_("bad dhcp-option"));
85f98a
+    goto_err(_("bad dhcp-option"));
85f98a
   
85f98a
   if (comma)
85f98a
     {
85f98a
@@ -1141,10 +1233,10 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
 	  is_string = is_dec = is_hex = 0;
85f98a
 	  
85f98a
 	  if (!is6 && (!is_addr || dots == 0))
85f98a
-	    ret_err(_("bad IP address"));
85f98a
+	    goto_err(_("bad IP address"));
85f98a
 
85f98a
 	   if (is6 && !is_addr6)
85f98a
-	     ret_err(_("bad IPv6 address"));
85f98a
+	     goto_err(_("bad IPv6 address"));
85f98a
 	}
85f98a
       /* or names */
85f98a
       else if (opt_len & (OT_NAME | OT_RFC1035_NAME | OT_CSTRING))
85f98a
@@ -1237,7 +1329,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
 	      comma = split(cp);
85f98a
 	      slash = split_chr(cp, '/');
85f98a
 	      if (!inet_pton(AF_INET, cp, &in))
85f98a
-		ret_err(_("bad IPv4 address"));
85f98a
+		goto_err(_("bad IPv4 address"));
85f98a
 	      if (!slash)
85f98a
 		{
85f98a
 		  memcpy(op, &in, INADDRSZ);
85f98a
@@ -1282,8 +1374,8 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
 		  op += IN6ADDRSZ;
85f98a
 		  continue;
85f98a
 		}
85f98a
-	  
85f98a
-	      ret_err(_("bad IPv6 address"));
85f98a
+
85f98a
+	      goto_err(_("bad IPv6 address"));
85f98a
 	    } 
85f98a
 	  new->len = op - new->val;
85f98a
 	}
85f98a
@@ -1310,7 +1402,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
 		  if (strcmp (arg, ".") != 0)
85f98a
 		    {
85f98a
 		      if (!(dom = canonicalise_opt(arg)))
85f98a
-			ret_err(_("bad domain in dhcp-option"));
85f98a
+			goto_err(_("bad domain in dhcp-option"));
85f98a
 			
85f98a
 		      domlen = strlen(dom) + 2;
85f98a
 		    }
85f98a
@@ -1404,7 +1496,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
 		{
85f98a
 		  char *dom = canonicalise_opt(arg);
85f98a
 		  if (!dom)
85f98a
-		    ret_err(_("bad domain in dhcp-option"));
85f98a
+		    goto_err(_("bad domain in dhcp-option"));
85f98a
 		    		  
85f98a
 		  newp = opt_malloc(len + strlen(dom) + 2);
85f98a
 		  
85f98a
@@ -1442,14 +1534,14 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
       ((new->len > 255) || 
85f98a
       (new->len > 253 && (new->flags & (DHOPT_VENDOR | DHOPT_ENCAPSULATE))) ||
85f98a
        (new->len > 250 && (new->flags & DHOPT_RFC3925))))
85f98a
-    ret_err(_("dhcp-option too long"));
85f98a
+    goto_err(_("dhcp-option too long"));
85f98a
   
85f98a
   if (flags == DHOPT_MATCH)
85f98a
     {
85f98a
       if ((new->flags & (DHOPT_ENCAPSULATE | DHOPT_VENDOR)) ||
85f98a
 	  !new->netid ||
85f98a
 	  new->netid->next)
85f98a
-	ret_err(_("illegal dhcp-match"));
85f98a
+	goto_err(_("illegal dhcp-match"));
85f98a
        
85f98a
       if (is6)
85f98a
 	{
85f98a
@@ -1474,24 +1566,31 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
85f98a
     }
85f98a
     
85f98a
   return 1;
85f98a
+on_error:
85f98a
+  dhcp_opt_free(new);
85f98a
+  return 0;
85f98a
 }
85f98a
 
85f98a
 #endif
85f98a
 
85f98a
 void set_option_bool(unsigned int opt)
85f98a
 {
85f98a
-  if (opt < 32)
85f98a
-    daemon->options |= 1u << opt;
85f98a
-  else
85f98a
-    daemon->options2 |= 1u << (opt - 32);
85f98a
+  option_var(opt) |= option_val(opt);
85f98a
 }
85f98a
 
85f98a
 void reset_option_bool(unsigned int opt)
85f98a
 {
85f98a
-  if (opt < 32)
85f98a
-    daemon->options &= ~(1u << opt);
85f98a
-  else
85f98a
-    daemon->options2 &= ~(1u << (opt - 32));
85f98a
+  option_var(opt) &= ~(option_val(opt));
85f98a
+}
85f98a
+
85f98a
+static void server_list_free(struct server *list)
85f98a
+{
85f98a
+  while (list)
85f98a
+    {
85f98a
+      struct server *tmp = list;
85f98a
+      list = list->next;
85f98a
+      free(tmp);
85f98a
+    }
85f98a
 }
85f98a
 
85f98a
 static int one_opt(int option, char *arg, char *errstr, char *gen_err, int command_line, int servers_only)
85f98a
@@ -1675,13 +1774,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	      /* has subnet+len */
85f98a
 	      err = parse_mysockaddr(arg, &new->addr);
85f98a
 	      if (err)
85f98a
-		ret_err(err);
85f98a
+		ret_err_free(err, new);
85f98a
 	      if (!atoi_check(end, &new->mask))
85f98a
-		ret_err(gen_err);
85f98a
+		ret_err_free(gen_err, new);
85f98a
 	      new->addr_used = 1;
85f98a
 	    } 
85f98a
 	  else if (!atoi_check(arg, &new->mask))
85f98a
-	    ret_err(gen_err);
85f98a
+	    ret_err_free(gen_err, new);
85f98a
 	    
85f98a
           daemon->add_subnet4 = new;
85f98a
 
85f98a
@@ -1693,15 +1792,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		  /* has subnet+len */
85f98a
                   err = parse_mysockaddr(comma, &new->addr);
85f98a
                   if (err)
85f98a
-                    ret_err(err);
85f98a
+                    ret_err_free(err, new);
85f98a
                   if (!atoi_check(end, &new->mask))
85f98a
-                    ret_err(gen_err);
85f98a
+                    ret_err_free(gen_err, new);
85f98a
                   new->addr_used = 1;
85f98a
                 }
85f98a
               else
85f98a
                 {
85f98a
                   if (!atoi_check(comma, &new->mask))
85f98a
-                    ret_err(gen_err);
85f98a
+                    ret_err_free(gen_err, new);
85f98a
                 }
85f98a
           
85f98a
 	      daemon->add_subnet6 = new;
85f98a
@@ -1908,7 +2007,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		  new->addr.sa.sa_family = AF_INET6;
85f98a
 #endif
85f98a
 		else
85f98a
-		  ret_err(gen_err);
85f98a
+		  {
85f98a
+		    free(new->name);
85f98a
+		    ret_err_free(gen_err, new);
85f98a
+		  }
85f98a
 	      } 
85f98a
 	  }
85f98a
 	new->next = daemon->authinterface;
85f98a
@@ -2080,7 +2182,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 
85f98a
 		      arg = split(netpart);
85f98a
 		      if (!atoi_check(netpart, &msize))
85f98a
-			ret_err(gen_err);
85f98a
+			ret_err_free(gen_err, new);
85f98a
 		      else if (inet_pton(AF_INET, comma, &new->start))
85f98a
 			{
85f98a
 			  int mask = (1 << (32 - msize)) - 1;
85f98a
@@ -2093,18 +2195,18 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 				{
85f98a
 				  if (!(new->prefix = canonicalise_opt(arg)) ||
85f98a
 				      strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
85f98a
-				    ret_err(_("bad prefix"));
85f98a
+				    ret_err_free(_("bad prefix"), new);
85f98a
 				}
85f98a
 			      else if (strcmp(arg, "local") != 0 ||
85f98a
 				       (msize != 8 && msize != 16 && msize != 24))
85f98a
-				ret_err(gen_err);
85f98a
+				ret_err_free(gen_err, new);
85f98a
 			      else
85f98a
 				{
85f98a
 				   /* generate the equivalent of
85f98a
 				      local=/xxx.yyy.zzz.in-addr.arpa/ */
85f98a
 				  struct server *serv = add_rev4(new->start, msize);
85f98a
 				  if (!serv)
85f98a
-				    ret_err(_("bad prefix"));
85f98a
+				    ret_err_free(_("bad prefix"), new);
85f98a
 
85f98a
 				  serv->flags |= SERV_NO_ADDR;
85f98a
 
85f98a
@@ -2134,17 +2236,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 			  setaddr6part(&new->end6, addrpart | mask);
85f98a
 			  
85f98a
 			  if (msize < 64)
85f98a
-			    ret_err(gen_err);
85f98a
+			    ret_err_free(gen_err, new);
85f98a
 			  else if (arg)
85f98a
 			    {
85f98a
 			      if (option != 's')
85f98a
 				{
85f98a
 				  if (!(new->prefix = canonicalise_opt(arg)) ||
85f98a
 				      strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
85f98a
-				    ret_err(_("bad prefix"));
85f98a
+				    ret_err_free(_("bad prefix"), new);
85f98a
 				}	
85f98a
 			      else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
85f98a
-				ret_err(gen_err);
85f98a
+				ret_err_free(gen_err, new);
85f98a
 			      else 
85f98a
 				{
85f98a
 				  /* generate the equivalent of
85f98a
@@ -2164,7 +2266,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 			}
85f98a
 #endif
85f98a
 		      else
85f98a
-			ret_err(gen_err);
85f98a
+			ret_err_free(gen_err, new);
85f98a
 		    }
85f98a
 		  else
85f98a
 		    {
85f98a
@@ -2178,7 +2280,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 			  if (!arg)
85f98a
 			    new->end.s_addr = new->start.s_addr;
85f98a
 			  else if (!inet_pton(AF_INET, arg, &new->end))
85f98a
-			    ret_err(gen_err);
85f98a
+			    ret_err_free(gen_err, new);
85f98a
 			}
85f98a
 #ifdef HAVE_IPV6
85f98a
 		      else if (inet_pton(AF_INET6, comma, &new->start6))
85f98a
@@ -2187,17 +2289,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 			  if (!arg)
85f98a
 			    memcpy(&new->end6, &new->start6, IN6ADDRSZ);
85f98a
 			  else if (!inet_pton(AF_INET6, arg, &new->end6))
85f98a
-			    ret_err(gen_err);
85f98a
+			    ret_err_free(gen_err, new);
85f98a
 			}
85f98a
 #endif
85f98a
 		      else 
85f98a
-			ret_err(gen_err);
85f98a
+			ret_err_free(gen_err, new);
85f98a
 
85f98a
 		      if (option != 's' && prefstr)
85f98a
 			{
85f98a
 			  if (!(new->prefix = canonicalise_opt(prefstr)) ||
85f98a
 			      strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
85f98a
-			    ret_err(_("bad prefix"));
85f98a
+			    ret_err_free(_("bad prefix"), new);
85f98a
 			}
85f98a
 		    }
85f98a
 
85f98a
@@ -2359,7 +2461,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	  }
85f98a
 #endif
85f98a
 	else
85f98a
-	  ret_err(gen_err);
85f98a
+	  ret_err_free(gen_err, new);
85f98a
 
85f98a
 	new->used = 0;
85f98a
 	if (option == 'a')
85f98a
@@ -2430,7 +2532,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	  {
85f98a
 	    newlist->flags |= SERV_LITERAL_ADDRESS;
85f98a
 	    if (!(newlist->flags & SERV_TYPE))
85f98a
-	      ret_err(gen_err);
85f98a
+	      {
85f98a
+	        server_list_free(newlist);
85f98a
+	        ret_err(gen_err);
85f98a
+	      }
85f98a
 	  }
85f98a
 	else if (option == LOPT_NO_REBIND)
85f98a
 	  newlist->flags |= SERV_NO_REBIND;
85f98a
@@ -2451,7 +2556,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	  {
85f98a
 	    char *err = parse_server(arg, &newlist->addr, &newlist->source_addr, newlist->interface, &newlist->flags);
85f98a
 	    if (err)
85f98a
-	      ret_err(err);
85f98a
+	      {
85f98a
+	        server_list_free(newlist);
85f98a
+	        ret_err(err);
85f98a
+	      }
85f98a
 	  }
85f98a
 	
85f98a
 	serv = newlist;
85f98a
@@ -2801,21 +2909,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	      {
85f98a
 		if (is_tag_prefix(arg))
85f98a
 		  {
85f98a
-		    struct dhcp_netid *tt = opt_malloc(sizeof (struct dhcp_netid));
85f98a
-		    tt->net = opt_string_alloc(arg+4);
85f98a
-		    tt->next = new->filter;
85f98a
 		    /* ignore empty tag */
85f98a
-		    if (tt->net)
85f98a
-		      new->filter = tt;
85f98a
+		    if (arg[4])
85f98a
+		      new->filter = dhcp_netid_create(arg+4, new->filter);
85f98a
 		  }
85f98a
 		else
85f98a
 		  {
85f98a
 		    if (new->netid.net)
85f98a
-		      ret_err(_("only one tag allowed"));
85f98a
-		    else if (strstr(arg, "set:") == arg)
85f98a
-		      new->netid.net = opt_string_alloc(arg+4);
85f98a
+		      {
85f98a
+			dhcp_context_free(new);
85f98a
+			ret_err(_("only one tag allowed"));
85f98a
+		      }
85f98a
 		    else
85f98a
-		      new->netid.net = opt_string_alloc(arg);
85f98a
+		      new->netid.net = opt_string_alloc(set_prefix(arg));
85f98a
 		  }
85f98a
 		arg = comma;
85f98a
 	      }
85f98a
@@ -2831,7 +2937,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	    break;
85f98a
 	
85f98a
 	if (k < 2)
85f98a
-	  ret_err(_("bad dhcp-range"));
85f98a
+	  {
85f98a
+	    dhcp_context_free(new);
85f98a
+	    ret_err(_("bad dhcp-range"));
85f98a
+	  }
85f98a
 	
85f98a
 	if (inet_pton(AF_INET, a[0], &new->start))
85f98a
 	  {
85f98a
@@ -2843,7 +2952,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	    else if (strcmp(a[1], "proxy") == 0)
85f98a
 	      new->flags |= CONTEXT_PROXY;
85f98a
 	    else if (!inet_pton(AF_INET, a[1], &new->end))
85f98a
-	      ret_err(_("bad dhcp-range"));
85f98a
+	      {
85f98a
+		dhcp_context_free(new);
85f98a
+		ret_err(_("bad dhcp-range"));
85f98a
+	      }
85f98a
 	    
85f98a
 	    if (ntohl(new->start.s_addr) > ntohl(new->end.s_addr))
85f98a
 	      {
85f98a
@@ -2858,7 +2970,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		new->flags |= CONTEXT_NETMASK;
85f98a
 		leasepos = 3;
85f98a
 		if (!is_same_net(new->start, new->end, new->netmask))
85f98a
-		  ret_err(_("inconsistent DHCP range"));
85f98a
+		  {
85f98a
+		    dhcp_context_free(new);
85f98a
+		    ret_err(_("inconsistent DHCP range"));
85f98a
+		  }
85f98a
 		
85f98a
 	    
85f98a
 		if (k >= 4 && strchr(a[3], '.') &&  
85f98a
@@ -2872,6 +2987,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 #ifdef HAVE_DHCP6
85f98a
 	else if (inet_pton(AF_INET6, a[0], &new->start6))
85f98a
 	  {
85f98a
+	    const char *err = NULL;
85f98a
+
85f98a
 	    new->flags |= CONTEXT_V6; 
85f98a
 	    new->prefix = 64; /* default */
85f98a
 	    new->end6 = new->start6;
85f98a
@@ -2917,19 +3034,24 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		  }
85f98a
 	      }
85f98a
 	    
85f98a
-	    if (new->prefix != 64)
85f98a
+	    if (new->prefix > 64)
85f98a
 	      {
85f98a
 		if (new->flags & CONTEXT_RA)
85f98a
-		  ret_err(_("prefix length must be exactly 64 for RA subnets"));
85f98a
+		  err=(_("prefix length must be exactly 64 for RA subnets"));
85f98a
 		else if (new->flags & CONTEXT_TEMPLATE)
85f98a
-		  ret_err(_("prefix length must be exactly 64 for subnet constructors"));
85f98a
+		  err=(_("prefix length must be exactly 64 for subnet constructors"));
85f98a
 	      }
85f98a
-
85f98a
-	    if (new->prefix < 64)
85f98a
-	      ret_err(_("prefix length must be at least 64"));
85f98a
+	    else if (new->prefix < 64)
85f98a
+	      err=(_("prefix length must be at least 64"));
85f98a
 	    
85f98a
-	    if (!is_same_net6(&new->start6, &new->end6, new->prefix))
85f98a
-	      ret_err(_("inconsistent DHCPv6 range"));
85f98a
+	    if (!err && !is_same_net6(&new->start6, &new->end6, new->prefix))
85f98a
+	      err=(_("inconsistent DHCPv6 range"));
85f98a
+
85f98a
+	    if (err)
85f98a
+	      {
85f98a
+		dhcp_context_free(new);
85f98a
+		ret_err(err);
85f98a
+	      }
85f98a
 
85f98a
 	    /* dhcp-range=:: enables DHCP stateless on any interface */
85f98a
 	    if (IN6_IS_ADDR_UNSPECIFIED(&new->start6) && !(new->flags & CONTEXT_TEMPLATE))
85f98a
@@ -2940,7 +3062,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		struct in6_addr zero;
85f98a
 		memset(&zero, 0, sizeof(zero));
85f98a
 		if (!is_same_net6(&zero, &new->start6, new->prefix))
85f98a
-		  ret_err(_("prefix must be zero with \"constructor:\" argument"));
85f98a
+		  {
85f98a
+		    dhcp_context_free(new);
85f98a
+		    ret_err(_("prefix must be zero with \"constructor:\" argument"));
85f98a
+		  }
85f98a
 	      }
85f98a
 	    
85f98a
 	    if (addr6part(&new->start6) > addr6part(&new->end6))
85f98a
@@ -2952,12 +3077,18 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	  }
85f98a
 #endif
85f98a
 	else
85f98a
-	  ret_err(_("bad dhcp-range"));
85f98a
+	  {
85f98a
+	    dhcp_context_free(new);
85f98a
+	    ret_err(_("bad dhcp-range"));
85f98a
+	  }
85f98a
 	
85f98a
 	if (leasepos < k)
85f98a
 	  {
85f98a
 	    if (leasepos != k-1)
85f98a
-	      ret_err(_("bad dhcp-range"));
85f98a
+	      {
85f98a
+		dhcp_context_free(new);
85f98a
+		ret_err(_("bad dhcp-range"));
85f98a
+	      }
85f98a
 	    
85f98a
 	    if (strcmp(a[leasepos], "infinite") == 0)
85f98a
 	      new->lease_time = 0xffffffff;
85f98a
@@ -2996,7 +3127,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 			break;
85f98a
 
85f98a
 		    if (*cp || (leasepos+1 < k))
85f98a
-		      ret_err(_("bad dhcp-range"));
85f98a
+		      ret_err_free(_("bad dhcp-range"), new);
85f98a
 		    
85f98a
 		    new->lease_time = atoi(a[leasepos]) * fac;
85f98a
 		    /* Leases of a minute or less confuse
85f98a
@@ -3023,6 +3154,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	new->flags = (option == LOPT_BANK) ? CONFIG_BANK : 0;
85f98a
 	new->hwaddr = NULL;
85f98a
 	new->netid = NULL;
85f98a
+	new->clid = NULL;
85f98a
 
85f98a
 	if ((a[0] = arg))
85f98a
 	  for (k = 1; k < 7; k++)
85f98a
@@ -3053,7 +3185,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 			}
85f98a
 
85f98a
 		      if (len == -1)
85f98a
-			ret_err(_("bad hex constant"));
85f98a
+			{
85f98a
+			  dhcp_config_free(new);
85f98a
+			  ret_err(_("bad hex constant"));
85f98a
+			}
85f98a
 		      else if ((new->clid = opt_malloc(len)))
85f98a
 			{
85f98a
 			  new->flags |= CONFIG_CLID;
85f98a
@@ -3065,17 +3200,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	      /* dhcp-host has strange backwards-compat needs. */
85f98a
 	      else if (strstr(arg, "net:") == arg || strstr(arg, "set:") == arg)
85f98a
 		{
85f98a
-		  struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
85f98a
 		  struct dhcp_netid_list *newlist = opt_malloc(sizeof(struct dhcp_netid_list));
85f98a
-		  newtag->net = opt_malloc(strlen(arg + 4) + 1);
85f98a
 		  newlist->next = new->netid;
85f98a
 		  new->netid = newlist;
85f98a
-		  newlist->list = newtag;
85f98a
-		  strcpy(newtag->net, arg+4);
85f98a
-		  unhide_metas(newtag->net);
85f98a
+		  newlist->list = dhcp_netid_create(arg+4, NULL);
85f98a
 		}
85f98a
 	      else if (strstr(arg, "tag:") == arg)
85f98a
-		ret_err(_("cannot match tags in --dhcp-host"));
85f98a
+		{
85f98a
+		  
85f98a
+		  dhcp_config_free(new);
85f98a
+		  ret_err(_("cannot match tags in --dhcp-host"));
85f98a
+		}
85f98a
 #ifdef HAVE_DHCP6
85f98a
 	      else if (arg[0] == '[' && arg[strlen(arg)-1] == ']')
85f98a
 		{
85f98a
@@ -3083,7 +3218,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		  arg++;
85f98a
 		  
85f98a
 		  if (!inet_pton(AF_INET6, arg, &new->addr6))
85f98a
-		    ret_err(_("bad IPv6 address"));
85f98a
+		    {
85f98a
+		      dhcp_config_free(new);
85f98a
+		      ret_err(_("bad IPv6 address"));
85f98a
+		    }
85f98a
 
85f98a
 		  for (i= 0; i < 8; i++)
85f98a
 		    if (new->addr6.s6_addr[i] != 0)
85f98a
@@ -3101,10 +3239,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		  struct hwaddr_config *newhw = opt_malloc(sizeof(struct hwaddr_config));
85f98a
 		  if ((newhw->hwaddr_len = parse_hex(a[j], newhw->hwaddr, DHCP_CHADDR_MAX, 
85f98a
 						     &newhw->wildcard_mask, &newhw->hwaddr_type)) == -1)
85f98a
-		    ret_err(_("bad hex constant"));
85f98a
+		    {
85f98a
+		      free(newhw);
85f98a
+		      dhcp_config_free(new);
85f98a
+		      ret_err(_("bad hex constant"));
85f98a
+		    }
85f98a
 		  else
85f98a
 		    {
85f98a
-		      
85f98a
 		      newhw->next = new->hwaddr;
85f98a
 		      new->hwaddr = newhw;
85f98a
 		    }		    
85f98a
@@ -3181,7 +3322,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		    {
85f98a
 		      if (!(new->hostname = canonicalise_opt(a[j])) ||
85f98a
 			  !legal_hostname(new->hostname))
85f98a
-			ret_err(_("bad DHCP host name"));
85f98a
+			{
85f98a
+			  dhcp_config_free(new);
85f98a
+			  ret_err(_("bad DHCP host name"));
85f98a
+			}
85f98a
 		     
85f98a
 		      new->flags |= CONFIG_NAME;
85f98a
 		      new->domain = strip_hostname(new->hostname);			
85f98a
@@ -3234,10 +3378,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	      }
85f98a
 	    else
85f98a
 	      {
85f98a
-		struct dhcp_netid *newtag = opt_malloc(sizeof(struct dhcp_netid));
85f98a
-		newtag->net = opt_malloc(len - 3);
85f98a
-		strcpy(newtag->net, arg+4);
85f98a
-		unhide_metas(newtag->net);
85f98a
+		struct dhcp_netid *newtag = dhcp_netid_create(arg+4, NULL);
85f98a
 
85f98a
 		if (strstr(arg, "set:") == arg)
85f98a
 		  {
85f98a
@@ -3254,7 +3395,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 		else 
85f98a
 		  {
85f98a
 		    new->set = NULL;
85f98a
-		    free(newtag);
85f98a
+		    dhcp_netid_free(newtag);
85f98a
 		    break;
85f98a
 		  }
85f98a
 	      }
85f98a
@@ -3263,7 +3404,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	  }
85f98a
 
85f98a
 	if (!new->set)
85f98a
-	  ret_err(_("bad tag-if"));
85f98a
+	  {
85f98a
+	    dhcp_netid_free(new->tag);
85f98a
+	    dhcp_netid_list_free(new->set);
85f98a
+	    ret_err_free(_("bad tag-if"), new);
85f98a
+	  }
85f98a
 	  
85f98a
 	break;
85f98a
       }
85f98a
@@ -3280,19 +3425,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
      
85f98a
     case 'M': /* --dhcp-boot */
85f98a
       {
85f98a
-	struct dhcp_netid *id = NULL;
85f98a
-	while (is_tag_prefix(arg))
85f98a
-	  {
85f98a
-	    struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
85f98a
-	    newid->next = id;
85f98a
-	    id = newid;
85f98a
-	    comma = split(arg);
85f98a
-	    newid->net = opt_string_alloc(arg+4);
85f98a
-	    arg = comma;
85f98a
-	  };
85f98a
+	struct dhcp_netid *id = dhcp_tags(&arg;;
85f98a
 	
85f98a
 	if (!arg)
85f98a
-	  ret_err(gen_err);
85f98a
+	  {
85f98a
+	    ret_err(gen_err);
85f98a
+	  }
85f98a
 	else 
85f98a
 	  {
85f98a
 	    char *dhcp_file, *dhcp_sname = NULL, *tftp_sname = NULL;
85f98a
@@ -3338,19 +3476,12 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 
85f98a
     case LOPT_REPLY_DELAY: /* --dhcp-reply-delay */
85f98a
       {
85f98a
-	struct dhcp_netid *id = NULL;
85f98a
-	while (is_tag_prefix(arg))
85f98a
-	  {
85f98a
-	    struct dhcp_netid *newid = opt_malloc(sizeof(struct dhcp_netid));
85f98a
-	    newid->next = id;
85f98a
-	    id = newid;
85f98a
-	    comma = split(arg);
85f98a
-	    newid->net = opt_string_alloc(arg+4);
85f98a
-	    arg = comma;
85f98a
-	  };
85f98a
+	struct dhcp_netid *id = dhcp_tags(&arg;;
85f98a
 	
85f98a
 	if (!arg)
85f98a
-	  ret_err(gen_err);
85f98a
+	  {
85f98a
+	    ret_err(gen_err);
85f98a
+	  }
85f98a
 	else
85f98a
 	  {
85f98a
 	    struct delay_config *new;
85f98a
@@ -3375,19 +3506,13 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	 
85f98a
 	 new->netid = NULL;
85f98a
 	 new->opt = 10; /* PXE_MENU_PROMPT */
85f98a
-
85f98a
-	 while (is_tag_prefix(arg))
85f98a
-	  {
85f98a
-	     struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
85f98a
-	     comma = split(arg);
85f98a
-	     nn->next = new->netid;
85f98a
-	     new->netid = nn;
85f98a
-	     nn->net = opt_string_alloc(arg+4);
85f98a
-	     arg = comma;
85f98a
-	   }
85f98a
+	 new->netid = dhcp_tags(&arg;;
85f98a
 	 
85f98a
 	 if (!arg)
85f98a
-	   ret_err(gen_err);
85f98a
+	   {
85f98a
+	     dhcp_opt_free(new);
85f98a
+	     ret_err(gen_err);
85f98a
+	   }
85f98a
 	 else
85f98a
 	   {
85f98a
 	     comma = split(arg);
85f98a
@@ -3423,17 +3548,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	 new->netid = NULL;
85f98a
 	 new->sname = NULL;
85f98a
 	 new->server.s_addr = 0;
85f98a
+	 new->netid = dhcp_tags(&arg;;
85f98a
 
85f98a
-	 while (is_tag_prefix(arg))
85f98a
-	   {
85f98a
-	     struct dhcp_netid *nn = opt_malloc(sizeof (struct dhcp_netid));
85f98a
-	     comma = split(arg);
85f98a
-	     nn->next = new->netid;
85f98a
-	     new->netid = nn;
85f98a
-	     nn->net = opt_string_alloc(arg+4);
85f98a
-	     arg = comma;
85f98a
-	   }
85f98a
-       
85f98a
 	 if (arg && (comma = split(arg)))
85f98a
 	   {
85f98a
 	     for (i = 0; CSA[i]; i++)
85f98a
@@ -3510,7 +3626,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	    unhide_metas(comma);
85f98a
 	    new->hwaddr_len = parse_hex(comma, new->hwaddr, DHCP_CHADDR_MAX, &new->mask, &new->hwaddr_type);
85f98a
 	    if (new->hwaddr_len == -1)
85f98a
-	      ret_err(gen_err);
85f98a
+	      {
85f98a
+		free(new->netid.net);
85f98a
+		ret_err_free(gen_err, new);
85f98a
+	      }
85f98a
 	    else
85f98a
 	      {
85f98a
 		new->next = daemon->dhcp_macs;
85f98a
@@ -3527,7 +3646,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	
85f98a
 	if (!(comma = split(arg)) ||
85f98a
 	    !atoi_check16(comma, &new->class))
85f98a
-	  ret_err(gen_err);
85f98a
+	  ret_err_free(gen_err, new);
85f98a
 	
85f98a
 	new->tag.net = opt_string_alloc(set_prefix(arg));
85f98a
 	new->next = daemon->prefix_classes;
85f98a
@@ -3549,7 +3668,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	 struct dhcp_vendor *new = opt_malloc(sizeof(struct dhcp_vendor));
85f98a
 	 
85f98a
 	 if (!(comma = split(arg)))
85f98a
-	   ret_err(gen_err);
85f98a
+	   ret_err_free(gen_err, new);
85f98a
 	
85f98a
 	 new->netid.net = opt_string_alloc(set_prefix(arg));
85f98a
 	 /* check for hex string - must digits may include : must not have nothing else, 
85f98a
@@ -3559,7 +3678,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	 if ((comma = split(arg)))
85f98a
 	   {
85f98a
 	     if (option  != 'U' || strstr(arg, "enterprise:") != arg)
85f98a
-	       ret_err(gen_err);
85f98a
+	       {
85f98a
+	         free(new->netid.net);
85f98a
+	         ret_err_free(gen_err, new);
85f98a
+	       }
85f98a
 	     else
85f98a
 	       new->enterprise = atoi(arg+11);
85f98a
 	   }
85f98a
@@ -3661,14 +3783,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	  }
85f98a
 	
85f98a
 	while (arg) {
85f98a
-	  struct dhcp_netid *member = opt_malloc(sizeof(struct dhcp_netid));
85f98a
 	  comma = split(arg);
85f98a
-	  member->next = list;
85f98a
-	  list = member;
85f98a
-	  if (is_tag_prefix(arg))
85f98a
-	    member->net = opt_string_alloc(arg+4);
85f98a
-	  else
85f98a
-	    member->net = opt_string_alloc(arg);
85f98a
+	  list = dhcp_netid_create(is_tag_prefix(arg) ? arg+4 :arg, list);
85f98a
 	  arg = comma;
85f98a
 	}
85f98a
 	
85f98a
@@ -3682,7 +3798,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	struct addr_list *new = opt_malloc(sizeof(struct addr_list));
85f98a
 	comma = split(arg);
85f98a
 	if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
85f98a
-	  ret_err(_("bad dhcp-proxy address"));
85f98a
+	  ret_err_free(_("bad dhcp-proxy address"), new);
85f98a
 	new->next = daemon->override_relays;
85f98a
 	daemon->override_relays = new;
85f98a
 	arg = comma;
85f98a
@@ -3708,7 +3824,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	  }
85f98a
 #endif
85f98a
 	else
85f98a
-	  ret_err(_("Bad dhcp-relay"));
85f98a
+	  {
85f98a
+	    free(new->interface);
85f98a
+	    ret_err_free(_("Bad dhcp-relay"), new);
85f98a
+	  }
85f98a
 	
85f98a
 	break;
85f98a
       }
85f98a
@@ -3748,8 +3867,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
85f98a
 	   arg = split(comma);
85f98a
 	   if (!atoi_check(comma, &new->interval) || 
85f98a
 	      (arg && !atoi_check(arg, &new->lifetime)))
85f98a
+             {
85f98a
 err:
85f98a
-	    ret_err(_("bad RA-params"));
85f98a
+	       free(new->name);
85f98a
+	       ret_err_free(_("bad RA-params"), new);
85f98a
+             }
85f98a
 	  
85f98a
 	  new->next = daemon->ra_interfaces;
85f98a
 	  daemon->ra_interfaces = new;
85f98a
@@ -3800,7 +3922,7 @@ err:
85f98a
 	    (!(inet_pton(AF_INET, dash, &new->end) > 0) ||
85f98a
 	     !is_same_net(new->in, new->end, new->mask) ||
85f98a
 	     ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
85f98a
-	  ret_err(_("invalid alias range"));
85f98a
+	  ret_err_free(_("invalid alias range"), new);
85f98a
 	
85f98a
 	break;
85f98a
       }
85f98a
@@ -3835,7 +3957,7 @@ err:
85f98a
 	      new->family = AF_INET6;
85f98a
 #endif
85f98a
 	    else
85f98a
-	      ret_err(gen_err);
85f98a
+	      ret_err_free(gen_err, new);
85f98a
 	  } 
85f98a
 	new->intr = opt_string_alloc(comma);
85f98a
 	break;
85f98a
@@ -3867,11 +3989,19 @@ err:
85f98a
 	    alias = canonicalise_opt(arg);
85f98a
 
85f98a
 	    if (!alias || !target)
85f98a
-	      ret_err(_("bad CNAME"));
85f98a
+	      {
85f98a
+		free(target);
85f98a
+		free(alias);
85f98a
+		ret_err(_("bad CNAME"));
85f98a
+	      }
85f98a
 	    
85f98a
 	    for (new = daemon->cnames; new; new = new->next)
85f98a
 	      if (hostname_isequal(new->alias, alias))
85f98a
-		ret_err(_("duplicate CNAME"));
85f98a
+		{
85f98a
+		  free(target);
85f98a
+		  free(alias);
85f98a
+		  ret_err(_("duplicate CNAME"));
85f98a
+		}
85f98a
 	    new = opt_malloc(sizeof(struct cname));
85f98a
 	    new->next = daemon->cnames;
85f98a
 	    daemon->cnames = new;
85f98a
@@ -3894,7 +4024,11 @@ err:
85f98a
 	
85f98a
 	if (!(dom = canonicalise_opt(arg)) ||
85f98a
 	    (comma && !(target = canonicalise_opt(comma))))
85f98a
-	  ret_err(_("bad PTR record"));
85f98a
+	  {
85f98a
+	    free(dom);
85f98a
+	    free(target);
85f98a
+	    ret_err(_("bad PTR record"));
85f98a
+	  }
85f98a
 	else
85f98a
 	  {
85f98a
 	    new = opt_malloc(sizeof(struct ptr_record));
85f98a
@@ -3912,7 +4046,7 @@ err:
85f98a
 	int k = 0;
85f98a
 	struct naptr *new;
85f98a
 	int order, pref;
85f98a
-	char *name, *replace = NULL;
85f98a
+	char *name=NULL, *replace = NULL;
85f98a
 
85f98a
 	if ((a[0] = arg))
85f98a
 	  for (k = 1; k < 7; k++)
85f98a
@@ -3925,7 +4059,11 @@ err:
85f98a
 	    !atoi_check16(a[1], &order) || 
85f98a
 	    !atoi_check16(a[2], &pref) ||
85f98a
 	    (k == 7 && !(replace = canonicalise_opt(a[6]))))
85f98a
-	  ret_err(_("bad NAPTR record"));
85f98a
+          {
85f98a
+	    free(name);
85f98a
+	    free(replace);
85f98a
+	    ret_err(_("bad NAPTR record"));
85f98a
+          }
85f98a
 	else
85f98a
 	  {
85f98a
 	    new = opt_malloc(sizeof(struct naptr));
85f98a
@@ -3947,22 +4085,26 @@ err:
85f98a
        	struct txt_record *new;
85f98a
 	size_t len = 0;
85f98a
 	char *data;
85f98a
-	int val;
85f98a
+	int class;
85f98a
 
85f98a
 	comma = split(arg);
85f98a
 	data = split(comma);
85f98a
 		
85f98a
 	new = opt_malloc(sizeof(struct txt_record));
85f98a
-	new->next = daemon->rr;
85f98a
-	daemon->rr = new;
85f98a
+	new->name = NULL;
85f98a
 	
85f98a
-	if (!atoi_check(comma, &val) || 
85f98a
+	if (!atoi_check(comma, &class) || 
85f98a
 	    !(new->name = canonicalise_opt(arg)) ||
85f98a
 	    (data && (len = parse_hex(data, (unsigned char *)data, -1, NULL, NULL)) == -1U))
85f98a
-	  ret_err(_("bad RR record"));
85f98a
-	   	
85f98a
-	new->class = val;
85f98a
+          {
85f98a
+            free(new->name);
85f98a
+	    ret_err_free(_("bad RR record"), new);
85f98a
+          }
85f98a
+
85f98a
 	new->len = 0;
85f98a
+	new->class = class;
85f98a
+	new->next = daemon->rr;
85f98a
+	daemon->rr = new;
85f98a
 	
85f98a
 	if (data)
85f98a
 	  {
85f98a
@@ -3983,14 +4125,14 @@ err:
85f98a
 	comma = split(arg);
85f98a
 		
85f98a
 	new = opt_malloc(sizeof(struct txt_record));
85f98a
-	new->next = daemon->txt;
85f98a
-	daemon->txt = new;
85f98a
 	new->class = C_IN;
85f98a
 	new->stat = 0;
85f98a
 
85f98a
 	if (!(new->name = canonicalise_opt(arg)))
85f98a
-	  ret_err(_("bad TXT record"));
85f98a
+	  ret_err_free(_("bad TXT record"), new);
85f98a
 	
85f98a
+	new->next = daemon->txt;
85f98a
+	daemon->txt = new;
85f98a
 	len = comma ? strlen(comma) : 0;
85f98a
 	len += (len/255) + 1; /* room for extra counts */
85f98a
 	new->txt = p = opt_malloc(len);
85f98a
@@ -4037,24 +4179,32 @@ err:
85f98a
 	    arg = comma;
85f98a
 	    comma = split(arg);
85f98a
 	    if (!(target = canonicalise_opt(arg)))
85f98a
-	      ret_err(_("bad SRV target"));
85f98a
+	      ret_err_free(_("bad SRV target"), name);
85f98a
 		
85f98a
 	    if (comma)
85f98a
 	      {
85f98a
 		arg = comma;
85f98a
 		comma = split(arg);
85f98a
 		if (!atoi_check16(arg, &port))
85f98a
-		  ret_err(_("invalid port number"));
85f98a
+                  {
85f98a
+                    free(name);
85f98a
+		    ret_err_free(_("invalid port number"), target);
85f98a
+                  }
85f98a
 		
85f98a
 		if (comma)
85f98a
 		  {
85f98a
 		    arg = comma;
85f98a
 		    comma = split(arg);
85f98a
 		    if (!atoi_check16(arg, &priority))
85f98a
-		      ret_err(_("invalid priority"));
85f98a
-			
85f98a
+                      {
85f98a
+                        free(name);
85f98a
+		        ret_err_free(_("invalid priority"), target);
85f98a
+		      }
85f98a
 		    if (comma && !atoi_check16(comma, &weight))
85f98a
-		      ret_err(_("invalid weight"));
85f98a
+                      {
85f98a
+                        free(name);
85f98a
+		        ret_err_free(_("invalid weight"), target);
85f98a
+                      }
85f98a
 		  }
85f98a
 	      }
85f98a
 	  }
85f98a
@@ -4073,13 +4223,15 @@ err:
85f98a
       
85f98a
     case LOPT_HOST_REC: /* --host-record */
85f98a
       {
85f98a
-	struct host_record *new = opt_malloc(sizeof(struct host_record));
85f98a
-	memset(new, 0, sizeof(struct host_record));
85f98a
-	new->ttl = -1;
85f98a
+	struct host_record *new;
85f98a
 
85f98a
 	if (!arg || !(comma = split(arg)))
85f98a
 	  ret_err(_("Bad host-record"));
85f98a
 	
85f98a
+	new = opt_malloc(sizeof(struct host_record));
85f98a
+	memset(new, 0, sizeof(struct host_record));
85f98a
+	new->ttl = -1;
85f98a
+
85f98a
 	while (arg)
85f98a
 	  {
85f98a
 	    struct all_addr addr;
85f98a
@@ -4100,10 +4252,19 @@ err:
85f98a
 	      {
85f98a
 		int nomem;
85f98a
 		char *canon = canonicalise(arg, &nomem);
85f98a
-		struct name_list *nl = opt_malloc(sizeof(struct name_list));
85f98a
+		struct name_list *nl;
85f98a
 		if (!canon)
85f98a
-		  ret_err(_("Bad name in host-record"));
85f98a
+                  {
85f98a
+		    struct name_list *tmp = new->names, *next;
85f98a
+		    for (tmp = new->names; tmp; tmp = next)
85f98a
+		      {
85f98a
+			next = tmp->next;
85f98a
+			free(tmp);
85f98a
+		      }
85f98a
+		    ret_err_free(_("Bad name in host-record"), new);
85f98a
+                  }
85f98a
 
85f98a
+		nl = opt_malloc(sizeof(struct name_list));
85f98a
 		nl->name = canon;
85f98a
 		/* keep order, so that PTR record goes to first name */
85f98a
 		nl->next = NULL;
85f98a
@@ -4143,6 +4304,7 @@ err:
85f98a
 	int len;
85f98a
 	
85f98a
 	new->class = C_IN;
85f98a
+	new->name = NULL;
85f98a
 
85f98a
 	if ((comma = split(arg)) && (algo = split(comma)))
85f98a
 	  {
85f98a
@@ -4167,7 +4329,7 @@ err:
85f98a
 	    !atoi_check8(algo, &new->algo) ||
85f98a
 	    !atoi_check8(digest, &new->digest_type) ||
85f98a
 	    !(new->name = canonicalise_opt(arg)))
85f98a
-	  ret_err(_("bad trust anchor"));
85f98a
+	  ret_err_free(_("bad trust anchor"), new);
85f98a
 	    
85f98a
 	/* Upper bound on length */
85f98a
 	len = (2*strlen(keyhex))+1;
85f98a
@@ -4181,7 +4343,10 @@ err:
85f98a
 	  else
85f98a
 	    cp++;
85f98a
 	if ((new->digestlen = parse_hex(keyhex, (unsigned char *)new->digest, len, NULL, NULL)) == -1)
85f98a
-	  ret_err(_("bad HEX in trust anchor"));
85f98a
+	  {
85f98a
+	    free(new->name);
85f98a
+	    ret_err_free(_("bad HEX in trust anchor"), new);
85f98a
+	  }
85f98a
 	
85f98a
 	new->next = daemon->ds;
85f98a
 	daemon->ds = new;
85f98a
@@ -4650,8 +4815,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
85f98a
   size_t argbuf_size = MAXDNAME;
85f98a
   char *argbuf = opt_malloc(argbuf_size);
85f98a
   char *buff = opt_malloc(MAXDNAME);
85f98a
-  int option, conffile_opt = '7', testmode = 0;
85f98a
-  char *arg, *conffile = CONFFILE;
85f98a
+  int option, testmode = 0;
85f98a
+  char *arg, *conffile = NULL;
85f98a
       
85f98a
   opterr = 0;
85f98a
 
85f98a
@@ -4725,8 +4890,7 @@ void read_opts(int argc, char **argv, char *compile_opts)
85f98a
 	      argbuf_size = strlen(optarg) + 1;
85f98a
 	      argbuf = opt_malloc(argbuf_size);
85f98a
 	    }
85f98a
-	  strncpy(argbuf, optarg, argbuf_size);
85f98a
-	  argbuf[argbuf_size-1] = 0;
85f98a
+	  safe_strncpy(argbuf, optarg, argbuf_size);
85f98a
 	  arg = argbuf;
85f98a
 	}
85f98a
       else
85f98a
@@ -4761,7 +4925,8 @@ void read_opts(int argc, char **argv, char *compile_opts)
85f98a
         }
85f98a
       else if (option == 'C')
85f98a
 	{
85f98a
-	  conffile_opt = 0; /* file must exist */
85f98a
+          if (conffile)
85f98a
+            free(conffile);
85f98a
 	  conffile = opt_string_alloc(arg);
85f98a
 	}
85f98a
       else
85f98a
@@ -4779,10 +4944,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
85f98a
 
85f98a
   if (conffile)
85f98a
     {
85f98a
-      one_file(conffile, conffile_opt);
85f98a
-      if (conffile_opt == 0)
85f98a
-	free(conffile);
85f98a
+      one_file(conffile, 0);
85f98a
+      free(conffile);
85f98a
     }
85f98a
+  else
85f98a
+    one_file(CONFFILE, '7');
85f98a
 
85f98a
   /* port might not be known when the address is parsed - fill in here */
85f98a
   if (daemon->servers)
85f98a
diff --git a/src/rfc2131.c b/src/rfc2131.c
85f98a
index c08a8ab..997575a 100644
85f98a
--- a/src/rfc2131.c
85f98a
+++ b/src/rfc2131.c
85f98a
@@ -917,7 +917,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
85f98a
 			mess->siaddr = a_record_from_hosts(boot->tftp_sname, now);
85f98a
 		      
85f98a
 		      if (boot->file)
85f98a
-			strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
85f98a
+			safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
85f98a
 		    }
85f98a
 		  
85f98a
 		  option_put(mess, end, OPTION_MESSAGE_TYPE, 1, 
85f98a
@@ -2296,7 +2296,7 @@ static void do_options(struct dhcp_context *context,
85f98a
 	      in_list(req_options, OPTION_SNAME))
85f98a
 	    option_put_string(mess, end, OPTION_SNAME, boot->sname, 1);
85f98a
 	  else
85f98a
-	    strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname)-1);
85f98a
+	    safe_strncpy((char *)mess->sname, boot->sname, sizeof(mess->sname));
85f98a
 	}
85f98a
       
85f98a
       if (boot->file)
85f98a
@@ -2306,7 +2306,7 @@ static void do_options(struct dhcp_context *context,
85f98a
 	      in_list(req_options, OPTION_FILENAME))
85f98a
 	    option_put_string(mess, end, OPTION_FILENAME, boot->file, 1);
85f98a
 	  else
85f98a
-	    strncpy((char *)mess->file, boot->file, sizeof(mess->file)-1);
85f98a
+	    safe_strncpy((char *)mess->file, boot->file, sizeof(mess->file));
85f98a
 	}
85f98a
       
85f98a
       if (boot->next_server.s_addr) 
85f98a
@@ -2323,14 +2323,14 @@ static void do_options(struct dhcp_context *context,
85f98a
       if ((!req_options || !in_list(req_options, OPTION_FILENAME)) &&
85f98a
 	  (opt = option_find2(OPTION_FILENAME)) && !(opt->flags & DHOPT_FORCE))
85f98a
 	{
85f98a
-	  strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file)-1);
85f98a
+	  safe_strncpy((char *)mess->file, (char *)opt->val, sizeof(mess->file));
85f98a
 	  done_file = 1;
85f98a
 	}
85f98a
       
85f98a
       if ((!req_options || !in_list(req_options, OPTION_SNAME)) &&
85f98a
 	  (opt = option_find2(OPTION_SNAME)) && !(opt->flags & DHOPT_FORCE))
85f98a
 	{
85f98a
-	  strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname)-1);
85f98a
+	  safe_strncpy((char *)mess->sname, (char *)opt->val, sizeof(mess->sname));
85f98a
 	  done_server = 1;
85f98a
 	}
85f98a
       
85f98a
diff --git a/src/tftp.c b/src/tftp.c
85f98a
index bccca69..f2eccbc 100644
85f98a
--- a/src/tftp.c
85f98a
+++ b/src/tftp.c
85f98a
@@ -234,7 +234,7 @@ void tftp_request(struct listener *listen, time_t now)
85f98a
 #endif
85f98a
 	}
85f98a
 
85f98a
-      strncpy(ifr.ifr_name, name, IF_NAMESIZE);
85f98a
+      safe_strncpy(ifr.ifr_name, name, IF_NAMESIZE);
85f98a
       if (ioctl(listen->tftpfd, SIOCGIFMTU, &ifr) != -1)
85f98a
 	{
85f98a
 	  mtu = ifr.ifr_mtu;  
85f98a
diff --git a/src/util.c b/src/util.c
85f98a
index 532bc16..e003e3c 100644
85f98a
--- a/src/util.c
85f98a
+++ b/src/util.c
85f98a
@@ -281,7 +281,17 @@ void *safe_malloc(size_t size)
85f98a
     die(_("could not get memory"), NULL, EC_NOMEM);
85f98a
       
85f98a
   return ret;
85f98a
-}    
85f98a
+}
85f98a
+
85f98a
+/* can be replaced by (void)strlcpy() on some platforms */
85f98a
+void safe_strncpy(char *dest, const char *src, size_t size)
85f98a
+{
85f98a
+  if (size)
85f98a
+    {
85f98a
+      dest[size-1] = '\0';
85f98a
+      strncpy(dest, src, size-1);
85f98a
+    }
85f98a
+}
85f98a
 
85f98a
 void safe_pipe(int *fd, int read_noblock)
85f98a
 {
85f98a
-- 
85f98a
2.20.1
85f98a