From ba61f889f62660ca2e3b9af918c2bdd8c6acca3b Mon Sep 17 00:00:00 2001
From: Howard Johnson <merlin@merlinthp.org>
Date: Sat, 1 Jul 2017 12:25:50 +0100
Subject: [PATCH] Ticket 49307 - Friendlier configuration of ns-slapd listen
 addresses

Bug Description:  The nsslapd-listenhost / securelistenhost attributes
are single-value.  In order to get ns-slapd to listen on two or more
(but not all) interfaces, we have to use a name that getaddrinfo returns
multiple IP addresses for.  That's a little unusual compared to other
software, which tend to take a list or similar.

Fix Description:  Make nsslapd-listenhost and nsslapd-securelistenhost
multi-valued attributes, and use all values to decide what interfaces
to listen on.

https://pagure.io/389-ds-base/issue/49307

Author: Howard Johnson <merlin@merlinthp.org>

Review by: ???
---
 dirsrvtests/tests/tickets/ticket49307_test.py |  99 +++++++++++++++++
 ldap/schema/01core389.ldif                    |   4 +-
 ldap/servers/slapd/daemon.c                   | 149 ++++++++++++++------------
 ldap/servers/slapd/fe.h                       |   2 +-
 ldap/servers/slapd/libglobs.c                 |  57 +++++++---
 ldap/servers/slapd/main.c                     |  18 ++--
 ldap/servers/slapd/proto-slap.h               |   5 +-
 ldap/servers/slapd/slap.h                     |   4 +-
 8 files changed, 242 insertions(+), 96 deletions(-)
 create mode 100644 dirsrvtests/tests/tickets/ticket49307_test.py

diff --git a/dirsrvtests/tests/tickets/ticket49307_test.py b/dirsrvtests/tests/tickets/ticket49307_test.py
new file mode 100644
index 0000000..6ec9a0b
--- /dev/null
+++ b/dirsrvtests/tests/tickets/ticket49307_test.py
@@ -0,0 +1,99 @@
+import time
+import logging
+import os
+import subprocess
+import ldap
+import pytest
+from lib389.topologies import topology_st as topo
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+    logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+    logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+lo = '127.0.0.1'
+lo1 = '127.0.0.201'
+lo2 = '127.0.0.202'
+lo3 = '127.0.0.203'
+
+
+@pytest.fixture(scope="module")
+def ip_setup(request):
+    def lo_ip(ip, add=True):
+        cmd = [
+            '/sbin/ip',
+            'addr',
+            'add' if add else 'del',
+            '%s/32' % ip,
+            'dev',
+            'lo'
+        ]
+
+        subprocess.check_call(cmd)
+
+    # Add some extra loopback IPs to bind to
+    lo_ip(lo1)
+    lo_ip(lo2)
+    lo_ip(lo3)
+
+    def fin():
+        # Tidy the IPs up again
+        lo_ip(lo1, False)
+        lo_ip(lo2, False)
+        lo_ip(lo3, False)
+
+    request.addfinalizer(fin)
+
+
+def check_connect(ip):
+    l = ldap.initialize('ldap://%s:%d' % (ip, 38901))
+    try:
+        l.simple_bind_s()
+        return True
+    except:
+        return False
+
+
+def test_ticket49307(topo, ip_setup):
+    """
+    Test setting nsslapd-listenhost to various values.
+    """
+
+    log.info("Ticket 49307 - Multi-attribute nsslapd-listenhost")
+
+    server = topo.standalone
+
+    # slapd is listening on all interfaces by default, check we can connect
+    for ip in (lo, lo1, lo2, lo3):
+        assert check_connect(ip) is True
+
+    # Rebind to localhost only
+    server.config.set("nsslapd-listenhost", "localhost")
+    server.restart()
+    assert check_connect(lo) is True
+    assert check_connect(lo1) is False
+
+    # Rebind to test IPs
+    server.config.set("nsslapd-listenhost", [lo, lo1, lo2])
+    server.restart()
+    for ip in (lo, lo1, lo2):
+        assert check_connect(ip) is True
+    assert check_connect(lo3) is False
+
+    # Rebind to a mixture of named host and IP
+    server.config.set("nsslapd-listenhost", ["localhost", lo1])
+    server.restart()
+    for ip in (lo, lo1):
+        assert check_connect(ip) is True
+    assert check_connect(lo2) is False
+
+    log.info("Ticket 49307 - PASSED")
+
+
+if __name__ == '__main__':
+    # Run isolated
+    # -s for DEBUG mode
+    CURRENT_FILE = os.path.realpath(__file__)
+    pytest.main("-s %s" % CURRENT_FILE)
\ No newline at end of file
diff --git a/ldap/schema/01core389.ldif b/ldap/schema/01core389.ldif
index 5e5f69f..b199227 100644
--- a/ldap/schema/01core389.ldif
+++ b/ldap/schema/01core389.ldif
@@ -195,7 +195,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2222 NAME 'nsslapd-localuser' DESC 'Nets
 attributeTypes: ( 2.16.840.1.113730.3.1.2223 NAME 'nsslapd-localhost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2224 NAME 'nsslapd-port' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2225 NAME 'nsslapd-workingdir' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
-attributeTypes: ( 2.16.840.1.113730.3.1.2226 NAME 'nsslapd-listenhost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2226 NAME 'nsslapd-listenhost' DESC 'Listen for connections on the specified hostname or IP address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2227 NAME 'nsslapd-snmp-index' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2228 NAME 'nsslapd-ldapifilepath' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2229 NAME 'nsslapd-ldapilisten' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
@@ -212,7 +212,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2239 NAME 'nsslapd-SSL3ciphers' DESC 'Ne
 attributeTypes: ( 2.16.840.1.113730.3.1.2240 NAME 'nsslapd-accesslog' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2241 NAME 'nsslapd-errorlog' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2242 NAME 'nsslapd-securePort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
-attributeTypes: ( 2.16.840.1.113730.3.1.2243 NAME 'nsslapd-securelistenhost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2243 NAME 'nsslapd-securelistenhost' DESC 'Listen for secure connections on the specified hostname or IP address' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2244 NAME 'nnslapd-threadnumber' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2245 NAME 'nsslapd-maxthreadsperconn' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
 attributeTypes: ( 2.16.840.1.113730.3.1.2246 NAME 'nsslapd-maxdescriptors' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index d0a4c6e..125302c 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -2910,12 +2910,13 @@ suppressed:
  * Returns: 0 if successful and -1 if not (after logging an error message).
  */
 int
-slapd_listenhost2addr(const char *listenhost, PRNetAddr ***addr)
+slapd_listenhost2addr(const char **listenhost, PRNetAddr ***addr)
 {
 	char		*logname = "slapd_listenhost2addr";
 	PRErrorCode	prerr = 0;
 	int			rval = 0;
 	PRNetAddr	*netaddr = (PRNetAddr *)slapi_ch_calloc(1, sizeof(PRNetAddr));
+	int 		i = 0;
 
 	PR_ASSERT( addr != NULL );
 	*addr = NULL;
@@ -2932,81 +2933,93 @@ slapd_listenhost2addr(const char *listenhost, PRNetAddr ***addr)
 		}
 		*addr = (PRNetAddr **)slapi_ch_calloc(2, sizeof (PRNetAddr *));
 		(*addr)[0] = netaddr;
-	} else if (PR_SUCCESS == PR_StringToNetAddr(listenhost, netaddr)) {
-		/* PR_StringNetAddr newer than NSPR v4.6.2 supports both IPv4&v6 */; 
-		*addr = (PRNetAddr **)slapi_ch_calloc(2, sizeof (PRNetAddr *));
-		(*addr)[0] = netaddr;
 	} else {
-		PRAddrInfo *infop = PR_GetAddrInfoByName( listenhost,
-						PR_AF_UNSPEC, (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME) );
-		if ( NULL != infop ) {
-			void *iter = NULL;
-			int addrcnt = 0;
-			int i = 0;
-			/* need to count the address, first */
-			while ( (iter = PR_EnumerateAddrInfo( iter, infop, 0, netaddr ))
-							!= NULL ) {
-				addrcnt++;
-			}
-			if ( 0 == addrcnt ) {
-				slapi_log_err(SLAPI_LOG_ERR, logname,
-					"PR_EnumerateAddrInfo for %s failed - %s error %d (%s)\n",
-					listenhost, SLAPI_COMPONENT_NAME_NSPR, prerr,
-					slapd_pr_strerror(prerr));
-				rval = -1;
+		char **strnetaddrs = NULL;
+		int j = 0;
+		*addr = (PRNetAddr **)slapi_ch_calloc(2, sizeof (PRNetAddr *));
+		for (i=0; listenhost[i]!=NULL; i++) {
+			if (PR_SUCCESS == PR_StringToNetAddr(listenhost[i], netaddr)) {
+				/* PR_StringNetAddr newer than NSPR v4.6.2 supports both IPv4&v6 */
+				(*addr)[j++] = netaddr;
+				netaddr = (PRNetAddr *)slapi_ch_calloc(1, sizeof (PRNetAddr));
+				*addr = (PRNetAddr **)slapi_ch_realloc((char *)*addr,
+					(j + 2) * sizeof (PRNetAddr *));
+				(*addr)[j] = NULL;
 			} else {
-				char **strnetaddrs = NULL;
-				*addr = (PRNetAddr **)slapi_ch_calloc(addrcnt + 1, sizeof (PRNetAddr *));
-				iter = NULL; /* from the beginning */
-				memset( netaddr, 0, sizeof( PRNetAddr ));
-				for  ( i = 0; i < addrcnt; i++ ) {
-					char abuf[256];
-					char *abp = abuf;
-					iter = PR_EnumerateAddrInfo( iter, infop, 0, netaddr );
-					if ( NULL == iter ) {
-						break;
-					}
-					/* 
-					 * Check if the netaddr is duplicated or not.
-					 * IPv4 mapped IPv6 could be the identical to IPv4 addr.
-					 */
-					netaddr2string(netaddr, abuf, sizeof(abuf));
-					if (PR_IsNetAddrType(netaddr, PR_IpAddrV4Mapped)) {
-						/* IPv4 mapped IPv6; redundant to IPv4;
-						 * cut the "::ffff:" part. */
-						abp = strrchr(abuf, ':');
-						if (abp) {
-							abp++;
-						} else {
-							abp = abuf;
-						}
+				PRAddrInfo *infop = PR_GetAddrInfoByName( listenhost[i],
+								PR_AF_UNSPEC, (PR_AI_ADDRCONFIG|PR_AI_NOCANONNAME) );
+				if ( NULL != infop ) {
+					void *iter = NULL;
+					int addrcnt = 0;
+					int k = 0;
+					/* need to count the address, first */
+					while ( (iter = PR_EnumerateAddrInfo( iter, infop, 0, netaddr ))
+									!= NULL ) {
+						addrcnt++;
 					}
-					if (charray_inlist(strnetaddrs, abp)) {
-						slapi_log_err(SLAPI_LOG_ERR,
-						               "slapd_listenhost2addr",
-						               "detected duplicated address %s "
-						               "[%s]\n", abuf, abp);
+					if ( 0 == addrcnt ) {
+						slapi_log_err(SLAPI_LOG_ERR, logname,
+							"PR_EnumerateAddrInfo for %s failed - %s error %d (%s)\n",
+							listenhost[i], SLAPI_COMPONENT_NAME_NSPR, prerr,
+							slapd_pr_strerror(prerr));
+						rval = -1;
 					} else {
-						slapi_log_err(SLAPI_LOG_TRACE,
-						              "slapd_listenhost2addr",
-						              "registering address %s\n", abp);
-						slapi_ch_array_add(&strnetaddrs, slapi_ch_strdup(abp));
-						(*addr)[i] = netaddr;
-						netaddr = 
-						    (PRNetAddr *)slapi_ch_calloc(1, sizeof(PRNetAddr));
+						iter = NULL; /* from the beginning */
+						memset( netaddr, 0, sizeof( PRNetAddr ));
+						for  ( k = 0; k < addrcnt; k++ ) {
+							char abuf[256];
+							char *abp = abuf;
+							iter = PR_EnumerateAddrInfo( iter, infop, 0, netaddr );
+							if ( NULL == iter ) {
+								break;
+							}
+							/*
+							 * Check if the netaddr is duplicated or not.
+							 * IPv4 mapped IPv6 could be the identical to IPv4 addr.
+							 */
+							netaddr2string(netaddr, abuf, sizeof(abuf));
+							if (PR_IsNetAddrType(netaddr, PR_IpAddrV4Mapped)) {
+								/* IPv4 mapped IPv6; redundant to IPv4;
+								* cut the "::ffff:" part. */
+								abp = strrchr(abuf, ':');
+								if (abp) {
+									abp++;
+								} else {
+									abp = abuf;
+								}
+							}
+							if (charray_inlist(strnetaddrs, abp)) {
+								slapi_log_err(SLAPI_LOG_ERR,
+											"slapd_listenhost2addr",
+											"detected duplicated address %s "
+											"[%s]\n", abuf, abp);
+							} else {
+								slapi_log_err(SLAPI_LOG_TRACE,
+											"slapd_listenhost2addr",
+											"registering address %s\n", abp);
+								slapi_ch_array_add(&strnetaddrs, slapi_ch_strdup(abp));
+								(*addr)[j++] = netaddr;
+								netaddr =
+									(PRNetAddr *)slapi_ch_calloc(1, sizeof(PRNetAddr));
+								*addr = (PRNetAddr **)slapi_ch_realloc((char *)*addr,
+									(j + 2) * sizeof (PRNetAddr *));
+								(*addr)[j] = NULL;
+							}
+						}
 					}
+					PR_FreeAddrInfo( infop );
+				} else {
+					slapi_log_err(SLAPI_LOG_ERR, logname,
+							"PR_GetAddrInfoByName(%s) failed - %s error %d (%s)\n",
+							listenhost[i], SLAPI_COMPONENT_NAME_NSPR, prerr,
+							slapd_pr_strerror(prerr));
+					rval = -1;
 				}
-				slapi_ch_free((void **)&netaddr); /* not used */
-				slapi_ch_array_free(strnetaddrs);
 			}
-			PR_FreeAddrInfo( infop );
-		} else {
-			slapi_log_err(SLAPI_LOG_ERR, logname,
-					"PR_GetAddrInfoByName(%s) failed - %s error %d (%s)\n",
-					listenhost, SLAPI_COMPONENT_NAME_NSPR, prerr,
-					slapd_pr_strerror(prerr));
-			rval = -1;
 		}
+		slapi_ch_free((void **)&netaddr); /* allocated ready for a next loop
+										   * iteration that didn't happen */
+		slapi_ch_array_free(strnetaddrs);
 	}
 
 	return rval;
diff --git a/ldap/servers/slapd/fe.h b/ldap/servers/slapd/fe.h
index 9667997..2230b02 100644
--- a/ldap/servers/slapd/fe.h
+++ b/ldap/servers/slapd/fe.h
@@ -118,7 +118,7 @@ int signal_listner(void);
 int daemon_pre_setuid_init(daemon_ports_t *ports);
 void slapd_daemon( daemon_ports_t *ports, ns_thrpool_t *tp );
 void daemon_register_connection(void);
-int slapd_listenhost2addr( const char *listenhost, PRNetAddr ***addr );
+int slapd_listenhost2addr( const char **listenhost, PRNetAddr ***addr );
 int daemon_register_reslimits( void );
 PRFileDesc * get_ssl_listener_fd(void);
 int configure_pr_socket( PRFileDesc **pr_socket, int secure, int local );
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 6f9bcdc..7ff5fe9 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -726,7 +726,7 @@ static struct config_get_and_set {
 	{CONFIG_LISTENHOST_ATTRIBUTE, config_set_listenhost,
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.listenhost,
-		CONFIG_STRING, NULL, "" /* Empty value is allowed */},
+		CONFIG_CHARRAY, NULL, NULL},
 	{CONFIG_SNMP_INDEX_ATTRIBUTE, config_set_snmp_index,
 		NULL, 0,
 		(void**) &global_slapdFrontendConfig.snmp_index,
@@ -789,7 +789,7 @@ static struct config_get_and_set {
 	{CONFIG_SECURELISTENHOST_ATTRIBUTE, config_set_securelistenhost,
 		NULL, 0,
 		(void**)&global_slapdFrontendConfig.securelistenhost,
-		CONFIG_STRING, NULL, "" /* Empty value is allowed */},
+		CONFIG_CHARRAY, NULL, NULL},
 	{CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE, NULL,
 		log_set_mindiskspace, SLAPD_AUDIT_LOG,
 		(void**)&global_slapdFrontendConfig.auditlog_minfreespace,
@@ -2138,8 +2138,8 @@ config_set_listenhost( const char *attrname __attribute__((unused)), char *value
   if ( apply) {
 	CFG_LOCK_WRITE(slapdFrontendConfig);
 	
-	slapi_ch_free ( (void **) &(slapdFrontendConfig->listenhost) );
-	slapdFrontendConfig->listenhost = slapi_ch_strdup ( value );
+	slapi_ch_array_free ( slapdFrontendConfig->listenhost );
+	slapdFrontendConfig->listenhost = slapi_ch_array_dup ( (char **) value );
 
 	CFG_UNLOCK_WRITE(slapdFrontendConfig);
   }
@@ -2383,8 +2383,8 @@ config_set_securelistenhost( const char *attrname __attribute__((unused)), char
   if ( apply ) {
 	CFG_LOCK_WRITE(slapdFrontendConfig);
 	
-	slapi_ch_free (  (void **) &(slapdFrontendConfig->securelistenhost) );
-	slapdFrontendConfig->securelistenhost = slapi_ch_strdup ( value );
+	slapi_ch_array_free ( slapdFrontendConfig->securelistenhost );
+	slapdFrontendConfig->securelistenhost = slapi_ch_array_dup ( (char **) value );
 	CFG_UNLOCK_WRITE(slapdFrontendConfig);
   }
   return retVal;
@@ -4524,6 +4524,7 @@ config_set_versionstring( const char *attrname __attribute__((unused)), char *ve
 
 
 #define config_copy_strval( s ) s ? slapi_ch_strdup (s) : NULL;
+#define config_copy_charray( s ) s ? slapi_ch_array_dup (s) : NULL;
 
 int
 config_get_port(){
@@ -4817,25 +4818,25 @@ config_get_localhost(void) {
 
 } 
 
-char *
+char **
 config_get_listenhost(void) {
   slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
-  char *retVal;
+  char **retVal;
  
   CFG_LOCK_READ(slapdFrontendConfig);
-  retVal = config_copy_strval ( slapdFrontendConfig->listenhost );
+  retVal = config_copy_charray ( slapdFrontendConfig->listenhost );
   CFG_UNLOCK_READ(slapdFrontendConfig);
   
   return retVal;
 }
 
-char *
+char **
 config_get_securelistenhost(void) {
   slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
-  char *retVal;
+  char **retVal;
 
   CFG_LOCK_READ(slapdFrontendConfig);
-  retVal = config_copy_strval( slapdFrontendConfig->securelistenhost );
+  retVal = config_copy_charray( slapdFrontendConfig->securelistenhost );
   CFG_UNLOCK_READ(slapdFrontendConfig);
   
   return retVal;
@@ -7464,6 +7465,38 @@ config_set(const char *attr, struct berval **values, char *errorbuf, int apply)
 		}
 		break;
 
+  case CONFIG_CHARRAY:
+    if (values == NULL && cgas->initvalue != NULL) {
+      if (cgas->setfunc) {
+        retval = (cgas->setfunc)(cgas->attr_name, cgas->initvalue,
+              errorbuf, apply);
+      } else if (cgas->logsetfunc) {
+        retval = (cgas->logsetfunc)(cgas->attr_name, cgas->initvalue,
+              cgas->whichlog, errorbuf, apply);
+      } else {
+        slapi_log_err(SLAPI_LOG_ERR, "config_set",
+          "The attribute %s is read only; ignoring setting NULL value\n", attr);
+      }
+    } else if (values != NULL) {
+      char **valarray = NULL;
+      for (ii = 0; !retval && values && values[ii]; ++ii) {
+        charray_add(&valarray, values[ii]->bv_val);
+      }
+      if (cgas->setfunc) {
+        retval = (cgas->setfunc)(cgas->attr_name,
+              (char *) valarray, errorbuf, apply);
+      } else if (cgas->logsetfunc) {
+        retval = (cgas->logsetfunc)(cgas->attr_name,
+              (char *) valarray, cgas->whichlog, errorbuf, apply);
+      } else {
+        slapi_log_err(SLAPI_LOG_ERR, "config_set",
+          "The attribute %s is read only; ignoring new value\n", attr);
+      }
+    } else {
+      retval = LDAP_UNWILLING_TO_PERFORM;
+    }
+    break;
+
 	default:
 		if (values == NULL && cgas->initvalue != NULL) {
             /* We are deleting all our values and reset to defaults */
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
index bc65775..4e12357 100644
--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -845,26 +845,26 @@ main( int argc, char **argv)
 
 	if ((slapd_exemode == SLAPD_EXEMODE_SLAPD) ||
 		(slapd_exemode == SLAPD_EXEMODE_REFERRAL)) {
-		char *listenhost = config_get_listenhost();
-		char *securelistenhost = config_get_securelistenhost();
+		char **listenhost = config_get_listenhost();
+		char **securelistenhost = config_get_securelistenhost();
 		ports_info.n_port = (unsigned short)n_port;
-		if ( slapd_listenhost2addr( listenhost,
+		if ( slapd_listenhost2addr( (const char **) listenhost,
 				&ports_info.n_listenaddr ) != 0 || 
 		     ports_info.n_listenaddr == NULL ) {
-			slapi_ch_free_string(&listenhost);
-			slapi_ch_free_string(&securelistenhost);
+			slapi_ch_array_free(listenhost);
+			slapi_ch_array_free(securelistenhost);
 			return(1);
 		}
-		slapi_ch_free_string(&listenhost);
+		slapi_ch_array_free(listenhost);
 
 		ports_info.s_port = (unsigned short)s_port;
-		if ( slapd_listenhost2addr( securelistenhost,
+		if ( slapd_listenhost2addr( (const char **) securelistenhost,
 				&ports_info.s_listenaddr ) != 0 ||
 			ports_info.s_listenaddr == NULL ) {
-			slapi_ch_free_string(&securelistenhost);
+			slapi_ch_array_free(securelistenhost);
 			return(1);
 		}
-		slapi_ch_free_string(&securelistenhost);
+		slapi_ch_array_free(securelistenhost);
 
 #if defined(ENABLE_LDAPI)
 		if(	config_get_ldapi_switch() &&
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 8e054d1..82840c0 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -243,6 +243,7 @@ int config_set_SSLclientAuth( const char *attrname, char *value, char *errorbuf,
 int config_set_ssl_check_hostname( const char *attrname, char *value, char *errorbuf, int apply );
 int config_set_SSL3ciphers( const char *attrname, char *value, char *errorbuf, int apply );
 int config_set_localhost( const char *attrname, char *value, char *errorbuf, int apply );
+/* The two listenhost functions are actually passed char ** cast to char * */
 int config_set_listenhost( const char *attrname, char *value, char *errorbuf, int apply );
 int config_set_securelistenhost( const char *attrname, char *value, char *errorbuf, int apply );
 int config_set_ldapi_filename( const char *attrname, char *value, char *errorbuf, int apply );
@@ -405,8 +406,8 @@ int config_get_SSLclientAuth(void);
 int config_get_ssl_check_hostname(void);
 char *config_get_SSL3ciphers(void);
 char *config_get_localhost(void);
-char *config_get_listenhost(void);
-char *config_get_securelistenhost(void);
+char **config_get_listenhost(void);
+char **config_get_securelistenhost(void);
 char *config_get_ldapi_filename(void);
 int config_get_ldapi_switch(void);
 int config_get_ldapi_bind_switch(void);
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 0dddb70..5a0d417 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -2243,13 +2243,13 @@ typedef struct _slapdFrontendConfig {
   struct berval **defaultreferral;
   char *encryptionalias;
   char *errorlog;
-  char *listenhost;
+  char **listenhost;
   int snmp_index;
   char *localuser;
   char *localhost;
   char *rootdn;
   char *rootpw;
-  char *securelistenhost;
+  char **securelistenhost;
   char *srvtab;
   char *SSL3ciphers;
   char *userat;
-- 
2.9.4

