(sounds like an oxymoron, but by "local socket" I mean AF_LOCAL, which
is the correct name for AF_UNIX.)

I just committed a heavily modified version of Ilya Bakulin's patch
(contrib/unbound_unixsock.diff) to FreeBSD 11.  I have attached a
version of the patch relative to Unbound 1.5.1.  It also applies cleanly
to trunk@3302, but I have not tested the result.

Here is a summary:

  Add support for using a local socket for the remote control connection
  by specifying its path instead of (or in addition to) an IP address as
  an argument to the control-interface configuration variable.

  Add support for unencrypted and unauthenticated control connections
  through a new configuration variable, control-use-cert.  To avoid the
  complexity of supporting both SSL socket and plain socket descriptors
  in the same code, we just use an unencrypted SSL context and forego
  authentication.  The downside is that we still have to perform DH kex
  when establishing the connection.

  This patch was derived (with significant modifications) from the
  contrib/unbound_unixsock.diff patch originally submitted by Ilya
  Bakulin of Genua mbH.

Note that my patch does not update generated files, so remember to run
autoreconf and regenerate the configuration parser and lexer.

Genua have already released Ilya's part of the patch under the BSD
license.  I release my version under the same license.

DES
-- 
Dag-Erling Smørgrav - [email protected]

Index: configure.ac
===================================================================
--- configure.ac	(revision 276697)
+++ configure.ac	(revision 276698)
@@ -266,7 +266,7 @@
 ACX_LIBTOOL_C_ONLY
 
 # Checks for header files.
-AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h],,, [AC_INCLUDES_DEFAULT])
+AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h sys/param.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h],,, [AC_INCLUDES_DEFAULT])
 
 # check for types.  
 # Using own tests for int64* because autoconf builtin only give 32bit.
Index: smallapp/unbound-control.c
===================================================================
--- smallapp/unbound-control.c	(revision 276697)
+++ smallapp/unbound-control.c	(revision 276698)
@@ -59,6 +59,10 @@
 #include "util/locks.h"
 #include "util/net_help.h"
 
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
 /** Give unbound-control usage, and exit (1). */
 static void
 usage()
@@ -139,29 +143,37 @@
 	char* s_cert, *c_key, *c_cert;
 	SSL_CTX* ctx;
 
-	s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
-	c_key = fname_after_chroot(cfg->control_key_file, cfg, 1);
-	c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1);
-	if(!s_cert || !c_key || !c_cert)
-		fatal_exit("out of memory");
+	if(cfg->remote_control_use_cert) {
+		s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
+		c_key = fname_after_chroot(cfg->control_key_file, cfg, 1);
+		c_cert = fname_after_chroot(cfg->control_cert_file, cfg, 1);
+		if(!s_cert || !c_key || !c_cert)
+			fatal_exit("out of memory");
+	}
         ctx = SSL_CTX_new(SSLv23_client_method());
 	if(!ctx)
 		ssl_err("could not allocate SSL_CTX pointer");
         if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2))
 		ssl_err("could not set SSL_OP_NO_SSLv2");
-        if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3))
-		ssl_err("could not set SSL_OP_NO_SSLv3");
-	if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) ||
-		!SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
-		|| !SSL_CTX_check_private_key(ctx))
-		ssl_err("Error setting up SSL_CTX client key and cert");
-	if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
-		ssl_err("Error setting up SSL_CTX verify, server cert");
-	SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+        if(cfg->remote_control_use_cert) {
+		if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3))
+			ssl_err("could not set SSL_OP_NO_SSLv3");
+		if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) ||
+		    !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM)
+		    || !SSL_CTX_check_private_key(ctx))
+			ssl_err("Error setting up SSL_CTX client key and cert");
+		if (SSL_CTX_load_verify_locations(ctx, s_cert, NULL) != 1)
+			ssl_err("Error setting up SSL_CTX verify, server cert");
+		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
 
-	free(s_cert);
-	free(c_key);
-	free(c_cert);
+		free(s_cert);
+		free(c_key);
+		free(c_cert);
+	} else {
+		/* Use ciphers that don't require authentication  */
+		if(!SSL_CTX_set_cipher_list(ctx, "aNULL"))
+			ssl_err("Error setting NULL cipher!");
+	}
 	return ctx;
 }
 
@@ -171,6 +183,7 @@
 {
 	struct sockaddr_storage addr;
 	socklen_t addrlen;
+	int addrfamily = 0;
 	int fd;
 	/* use svr or the first config entry */
 	if(!svr) {
@@ -189,12 +202,23 @@
 	if(strchr(svr, '@')) {
 		if(!extstrtoaddr(svr, &addr, &addrlen))
 			fatal_exit("could not parse IP@port: %s", svr);
+#ifdef HAVE_SYS_UN_H
+	} else if(svr[0] == '/') {
+		struct sockaddr_un* sun = (struct sockaddr_un *) &addr;
+		sun->sun_family = AF_LOCAL;
+		sun->sun_len = sizeof(sun);
+		strlcpy(sun->sun_path, svr, 104);
+		addrlen = sizeof(struct sockaddr_un);
+		addrfamily = AF_LOCAL;
+#endif
 	} else {
 		if(!ipstrtoaddr(svr, cfg->control_port, &addr, &addrlen))
 			fatal_exit("could not parse IP: %s", svr);
 	}
-	fd = socket(addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET, 
-		SOCK_STREAM, 0);
+
+	if(addrfamily == 0)
+		addrfamily = addr_is_ip6(&addr, addrlen)?AF_INET6:AF_INET;
+	fd = socket(addrfamily, SOCK_STREAM, 0);
 	if(fd == -1) {
 #ifndef USE_WINSOCK
 		fatal_exit("socket: %s", strerror(errno));
@@ -223,7 +247,7 @@
 
 /** setup SSL on the connection */
 static SSL*
-setup_ssl(SSL_CTX* ctx, int fd)
+setup_ssl(SSL_CTX* ctx, int fd, struct config_file* cfg)
 {
 	SSL* ssl;
 	X509* x;
@@ -249,10 +273,13 @@
 	/* check authenticity of server */
 	if(SSL_get_verify_result(ssl) != X509_V_OK)
 		ssl_err("SSL verification failed");
-	x = SSL_get_peer_certificate(ssl);
-	if(!x)
-		ssl_err("Server presented no peer certificate");
-	X509_free(x);
+	if(cfg->remote_control_use_cert) {
+		x = SSL_get_peer_certificate(ssl);
+		if(!x)
+			ssl_err("Server presented no peer certificate");
+		X509_free(x);
+	}
+
 	return ssl;
 }
 
@@ -330,11 +357,11 @@
 	if(!cfg->remote_control_enable)
 		log_warn("control-enable is 'no' in the config file.");
 	ctx = setup_ctx(cfg);
-	
+
 	/* contact server */
 	fd = contact_server(svr, cfg, argc>0&&strcmp(argv[0],"status")==0);
-	ssl = setup_ssl(ctx, fd);
-	
+	ssl = setup_ssl(ctx, fd, cfg);
+
 	/* send command */
 	ret = go_cmd(ssl, quiet, argc, argv);
 
Index: smallapp/unbound-checkconf.c
===================================================================
--- smallapp/unbound-checkconf.c	(revision 276697)
+++ smallapp/unbound-checkconf.c	(revision 276698)
@@ -416,7 +416,7 @@
 		endpwent();
 	}
 #endif
-	if(cfg->remote_control_enable) {
+	if(cfg->remote_control_enable && cfg->remote_control_use_cert) {
 		check_chroot_string("server-key-file", &cfg->server_key_file,
 			cfg->chrootdir, cfg);
 		check_chroot_string("server-cert-file", &cfg->server_cert_file,
Index: daemon/unbound.c
===================================================================
--- daemon/unbound.c	(revision 276697)
+++ daemon/unbound.c	(revision 276698)
@@ -441,20 +441,14 @@
 perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
 	const char** cfgfile)
 {
+	log_assert(cfg);
+
 #ifdef HAVE_GETPWNAM
 	struct passwd *pwd = NULL;
-	uid_t uid;
-	gid_t gid;
-	/* initialize, but not to 0 (root) */
-	memset(&uid, 112, sizeof(uid));
-	memset(&gid, 112, sizeof(gid));
-	log_assert(cfg);
 
 	if(cfg->username && cfg->username[0]) {
 		if((pwd = getpwnam(cfg->username)) == NULL)
 			fatal_exit("user '%s' does not exist.", cfg->username);
-		uid = pwd->pw_uid;
-		gid = pwd->pw_gid;
 		/* endpwent below, in case we need pwd for setusercontext */
 	}
 #endif
@@ -511,18 +505,11 @@
 #ifdef HAVE_KILL
 	if(cfg->pidfile && cfg->pidfile[0]) {
 		writepid(daemon->pidfile, getpid());
-		if(!(cfg->chrootdir && cfg->chrootdir[0]) || 
-			(cfg->chrootdir && cfg->chrootdir[0] && 
-			strncmp(daemon->pidfile, cfg->chrootdir, 
-			strlen(cfg->chrootdir))==0)) {
-			/* delete of pidfile could potentially work,
-			 * chown to get permissions */
-			if(cfg->username && cfg->username[0]) {
-			  if(chown(daemon->pidfile, uid, gid) == -1) {
+		if(cfg->username && cfg->username[0]) {
+			if(chown(daemon->pidfile, cfg->uid, cfg->gid) == -1) {
 				log_err("cannot chown %u.%u %s: %s",
-					(unsigned)uid, (unsigned)gid,
+					(unsigned)cfg->uid, (unsigned)cfg->gid,
 					daemon->pidfile, strerror(errno));
-			  }
 			}
 		}
 	}
@@ -537,7 +524,7 @@
 		/* setusercontext does initgroups, setuid, setgid, and
 		 * also resource limits from login config, but we
 		 * still call setresuid, setresgid to be sure to set all uid*/
-		if(setusercontext(NULL, pwd, uid, (unsigned)
+		if(setusercontext(NULL, pwd, cfg->uid, (unsigned)
 			LOGIN_SETALL & ~LOGIN_SETUSER & ~LOGIN_SETGROUP) != 0)
 			log_warn("unable to setusercontext %s: %s",
 				cfg->username, strerror(errno));
@@ -601,7 +588,7 @@
 #ifdef HAVE_GETPWNAM
 	if(cfg->username && cfg->username[0]) {
 #  ifdef HAVE_INITGROUPS
-		if(initgroups(cfg->username, gid) != 0)
+		if(initgroups(cfg->username, cfg->gid) != 0)
 			log_warn("unable to initgroups %s: %s",
 				cfg->username, strerror(errno));
 #  endif /* HAVE_INITGROUPS */
@@ -608,20 +595,20 @@
 		endpwent();
 
 #ifdef HAVE_SETRESGID
-		if(setresgid(gid,gid,gid) != 0)
+		if(setresgid(cfg->gid,cfg->gid,cfg->gid) != 0)
 #elif defined(HAVE_SETREGID) && !defined(DARWIN_BROKEN_SETREUID)
-		if(setregid(gid,gid) != 0)
+		if(setregid(cfg->gid,cfg->gid) != 0)
 #else /* use setgid */
-		if(setgid(gid) != 0)
+		if(setgid(cfg->gid) != 0)
 #endif /* HAVE_SETRESGID */
 			fatal_exit("unable to set group id of %s: %s", 
 				cfg->username, strerror(errno));
 #ifdef HAVE_SETRESUID
-		if(setresuid(uid,uid,uid) != 0)
+		if(setresuid(cfg->uid,cfg->uid,cfg->uid) != 0)
 #elif defined(HAVE_SETREUID) && !defined(DARWIN_BROKEN_SETREUID)
-		if(setreuid(uid,uid) != 0)
+		if(setreuid(cfg->uid,cfg->uid) != 0)
 #else /* use setuid */
-		if(setuid(uid) != 0)
+		if(setuid(cfg->uid) != 0)
 #endif /* HAVE_SETRESUID */
 			fatal_exit("unable to set user id of %s: %s", 
 				cfg->username, strerror(errno));
Index: daemon/remote.c
===================================================================
--- daemon/remote.c	(revision 276697)
+++ daemon/remote.c	(revision 276698)
@@ -46,6 +46,10 @@
 #ifdef HAVE_OPENSSL_ERR_H
 #include <openssl/err.h>
 #endif
+#ifndef HEADER_DH_H
+#include <openssl/dh.h>
+#endif
+
 #include <ctype.h>
 #include "daemon/remote.h"
 #include "daemon/worker.h"
@@ -82,6 +86,9 @@
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
@@ -131,6 +138,39 @@
 #endif
 }
 
+/*
+ * The following function was generated using the openssl utility, using
+ * the command : "openssl dhparam -dsaparam -C 512"
+ */
+DH *get_dh512()
+{
+	static unsigned char dh512_p[]={
+		0xC9,0xD7,0x05,0xDA,0x5F,0xAB,0x14,0xE8,0x11,0x56,0x77,0x85,
+		0xB1,0x24,0x2C,0x95,0x60,0xEA,0xE2,0x10,0x6F,0x0F,0x84,0xEC,
+		0xF4,0x45,0xE8,0x90,0x7A,0xA7,0x03,0xFF,0x5B,0x88,0x53,0xDE,
+		0xC4,0xDE,0xBC,0x42,0x78,0x71,0x23,0x7E,0x24,0xA5,0x5E,0x4E,
+		0xEF,0x6F,0xFF,0x5F,0xAF,0xBE,0x8A,0x77,0x62,0xB4,0x65,0x82,
+		0x7E,0xC9,0xED,0x2F,
+	};
+	static unsigned char dh512_g[]={
+		0x8D,0x3A,0x52,0xBC,0x8A,0x71,0x94,0x33,0x2F,0xE1,0xE8,0x4C,
+		0x73,0x47,0x03,0x4E,0x7D,0x40,0xE5,0x84,0xA0,0xB5,0x6D,0x10,
+		0x6F,0x90,0x43,0x05,0x1A,0xF9,0x0B,0x6A,0xD1,0x2A,0x9C,0x25,
+		0x0A,0xB9,0xD1,0x14,0xDC,0x35,0x1C,0x48,0x7C,0xC6,0x0C,0x6D,
+		0x32,0x1D,0xD3,0xC8,0x10,0xA8,0x82,0x14,0xA2,0x1C,0xF4,0x53,
+		0x23,0x3B,0x1C,0xB9,
+	};
+	DH *dh;
+
+	if ((dh=DH_new()) == NULL) return(NULL);
+	dh->p=BN_bin2bn(dh512_p,sizeof(dh512_p),NULL);
+	dh->g=BN_bin2bn(dh512_g,sizeof(dh512_g),NULL);
+	if ((dh->p == NULL) || (dh->g == NULL))
+	{ DH_free(dh); return(NULL); }
+	dh->length = 160;
+	return(dh);
+}
+
 struct daemon_remote*
 daemon_remote_create(struct config_file* cfg)
 {
@@ -165,6 +205,24 @@
 		daemon_remote_delete(rc);
 		return NULL;
 	}
+
+	if (cfg->remote_control_use_cert == 0) {
+		/* No certificates are requested */
+		if(!SSL_CTX_set_cipher_list(rc->ctx, "aNULL")) {
+			log_crypto_err("Failed to set aNULL cipher list");
+			return NULL;
+		}
+
+		/* Since we have no certificates and hence no source of
+		 * DH params, let's generate and set them
+		 */
+		if(!SSL_CTX_set_tmp_dh(rc->ctx,get_dh512())) {
+			log_crypto_err("Wanted to set DH param, but failed");
+			return NULL;
+		}
+		return rc;
+	}
+	rc->use_cert = 1;
 	s_cert = fname_after_chroot(cfg->server_cert_file, cfg, 1);
 	s_key = fname_after_chroot(cfg->server_key_file, cfg, 1);
 	if(!s_cert || !s_key) {
@@ -244,7 +302,8 @@
  * @return false on failure.
  */
 static int
-add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err)
+add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
+	struct config_file* cfg)
 {
 	struct addrinfo hints;
 	struct addrinfo* res;
@@ -255,29 +314,46 @@
 	snprintf(port, sizeof(port), "%d", nr);
 	port[sizeof(port)-1]=0;
 	memset(&hints, 0, sizeof(hints));
-	hints.ai_socktype = SOCK_STREAM;
-	hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
-	if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) {
+
+	if(ip[0] == '/') {
+		/* This looks like a local socket */
+		fd = create_local_accept_sock(ip, &noproto);
+		/*
+		 * Change socket ownership and permissions so users other
+		 * than root can access it provided they are in the same
+		 * group as the user we run as.
+		 */
+		if(fd != -1) {
+			if (cfg->username && cfg->username[0])
+				chown(ip, cfg->uid, cfg->gid);
+			chmod(ip, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+		}
+	} else {
+		hints.ai_socktype = SOCK_STREAM;
+		hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+		if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) {
 #ifdef USE_WINSOCK
-		if(!noproto_is_err && r == EAI_NONAME) {
-			/* tried to lookup the address as name */
-			return 1; /* return success, but do nothing */
-		}
+			if(!noproto_is_err && r == EAI_NONAME) {
+				/* tried to lookup the address as name */
+				return 1; /* return success, but do nothing */
+			}
 #endif /* USE_WINSOCK */
-                log_err("control interface %s:%s getaddrinfo: %s %s",
-			ip?ip:"default", port, gai_strerror(r),
+			log_err("control interface %s:%s getaddrinfo: %s %s",
+				ip?ip:"default", port, gai_strerror(r),
 #ifdef EAI_SYSTEM
-			r==EAI_SYSTEM?(char*)strerror(errno):""
+				r==EAI_SYSTEM?(char*)strerror(errno):""
 #else
-			""
+				""
 #endif
 			);
-		return 0;
+			return 0;
+		}
+
+		/* open fd */
+		fd = create_tcp_accept_sock(res, 1, &noproto, 0);
+		freeaddrinfo(res);
 	}
 
-	/* open fd */
-	fd = create_tcp_accept_sock(res, 1, &noproto, 0);
-	freeaddrinfo(res);
 	if(fd == -1 && noproto) {
 		if(!noproto_is_err)
 			return 1; /* return success, but do nothing */
@@ -314,7 +390,7 @@
 	if(cfg->control_ifs) {
 		struct config_strlist* p;
 		for(p = cfg->control_ifs; p; p = p->next) {
-			if(!add_open(p->str, cfg->control_port, &l, 1)) {
+			if(!add_open(p->str, cfg->control_port, &l, 1, cfg)) {
 				listening_ports_free(l);
 				return NULL;
 			}
@@ -322,12 +398,12 @@
 	} else {
 		/* defaults */
 		if(cfg->do_ip6 &&
-			!add_open("::1", cfg->control_port, &l, 0)) {
+			!add_open("::1", cfg->control_port, &l, 0, cfg)) {
 			listening_ports_free(l);
 			return NULL;
 		}
 		if(cfg->do_ip4 &&
-			!add_open("127.0.0.1", cfg->control_port, &l, 1)) {
+			!add_open("127.0.0.1", cfg->control_port, &l, 1, cfg)) {
 			listening_ports_free(l);
 			return NULL;
 		}
@@ -2434,7 +2510,9 @@
 	s->shake_state = rc_none;
 
 	/* once handshake has completed, check authentication */
-	if(SSL_get_verify_result(s->ssl) == X509_V_OK) {
+	if (!rc->use_cert) {
+		verbose(VERB_ALGO, "unauthenticated remote control connection");
+	} else if(SSL_get_verify_result(s->ssl) == X509_V_OK) {
 		X509* x = SSL_get_peer_certificate(s->ssl);
 		if(!x) {
 			verbose(VERB_DETAIL, "remote control connection "
Index: daemon/remote.h
===================================================================
--- daemon/remote.h	(revision 276697)
+++ daemon/remote.h	(revision 276698)
@@ -89,6 +89,8 @@
 	struct worker* worker;
 	/** commpoints for accepting remote control connections */
 	struct listen_list* accept_list;
+	/* if certificates are used */
+	int use_cert;
 	/** number of active commpoints that are handling remote control */
 	int active;
 	/** max active commpoints */
Index: doc/unbound.conf.5.in
===================================================================
--- doc/unbound.conf.5.in	(revision 276697)
+++ doc/unbound.conf.5.in	(revision 276698)
@@ -958,36 +958,47 @@
 section for options.  To setup the correct self\-signed certificates use the
 \fIunbound\-control\-setup\fR(8) utility.
 .TP 5
-.B control\-enable:     \fI<yes or no>
+.B control\-enable: \fI<yes or no>
 The option is used to enable remote control, default is "no".
 If turned off, the server does not listen for control commands.
 .TP 5
-.B control\-interface: <ip address>
-Give IPv4 or IPv6 addresses to listen on for control commands.
+.B control\-interface: \fI<ip address or path>
+Give IPv4 or IPv6 addresses or local socket path to listen on for
+control commands.
 By default localhost (127.0.0.1 and ::1) is listened to.
 Use 0.0.0.0 and ::0 to listen to all interfaces.
+If you change this and permissions have been dropped, you must restart
+the server for the change to take effect.
 .TP 5
-.B control\-port: <port number>
-The port number to listen on for control commands, default is 8953.
-If you change this port number, and permissions have been dropped,
-a reload is not sufficient to open the port again, you must then restart.
+.B control\-port: \fI<port number>
+The port number to listen on for IPv4 or IPv6 control interfaces,
+default is 8953.
+If you change this and permissions have been dropped, you must restart
+the server for the change to take effect.
 .TP 5
-.B server\-key\-file: "<private key file>"
+.B control-use-cert: \fI<yes or no>
+Whether to require certificate authentication of control connections.
+The default is "yes".
+This should not be changed unless there are other mechanisms in place
+to prevent untrusted users from accessing the remote control
+interface.
+.TP 5
+.B server\-key\-file: \fI<private key file>
 Path to the server private key, by default unbound_server.key.
 This file is generated by the \fIunbound\-control\-setup\fR utility.
 This file is used by the unbound server, but not by \fIunbound\-control\fR.
 .TP 5
-.B server\-cert\-file: "<certificate file.pem>"
+.B server\-cert\-file: \fI<certificate file.pem>
 Path to the server self signed certificate, by default unbound_server.pem.
 This file is generated by the \fIunbound\-control\-setup\fR utility.
 This file is used by the unbound server, and also by \fIunbound\-control\fR.
 .TP 5
-.B control\-key\-file: "<private key file>"
+.B control\-key\-file: \fI<private key file>
 Path to the control client private key, by default unbound_control.key.
 This file is generated by the \fIunbound\-control\-setup\fR utility.
 This file is used by \fIunbound\-control\fR.
 .TP 5
-.B control\-cert\-file: "<certificate file.pem>"
+.B control\-cert\-file: \fI<certificate file.pem>
 Path to the control client certificate, by default unbound_control.pem.
 This certificate has to be signed with the server certificate.
 This file is generated by the \fIunbound\-control\-setup\fR utility.
Index: util/config_file.c
===================================================================
--- util/config_file.c	(revision 276697)
+++ util/config_file.c	(revision 276698)
@@ -60,6 +60,9 @@
 #ifdef HAVE_GLOB_H
 # include <glob.h>
 #endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
 
 /** global config during parsing */
 struct config_parser_state* cfg_parser = 0;
@@ -131,6 +134,8 @@
 		goto error_exit;
 	init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
 	if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
+	cfg->uid = (uid_t)-1;
+	cfg->gid = (gid_t)-1;
 #ifdef HAVE_CHROOT
 	if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
 #endif
@@ -799,6 +804,17 @@
 		errno=EINVAL;
 		return 0;
 	}
+
+#ifdef HAVE_GETPWNAM
+	/* translate username into uid and gid */
+	if(cfg->username && cfg->username[0]) {
+		struct passwd *pwd;
+		if((pwd = getpwnam(cfg->username)) == NULL)
+			log_err("user '%s' does not exist.", cfg->username);
+		cfg->uid = pwd->pw_uid;
+		cfg->gid = pwd->pw_gid;
+	}
+#endif
 	return 1;
 }
 
Index: util/configparser.y
===================================================================
--- util/configparser.y	(revision 276697)
+++ util/configparser.y	(revision 276698)
@@ -95,6 +95,7 @@
 %token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
 %token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE
 %token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE
+%token VAR_CONTROL_USE_CERT
 %token VAR_EXTENDED_STATISTICS VAR_LOCAL_DATA_PTR VAR_JOSTLE_TIMEOUT
 %token VAR_STUB_PRIME VAR_UNWANTED_REPLY_THRESHOLD VAR_LOG_TIME_ASCII
 %token VAR_DOMAIN_INSECURE VAR_PYTHON VAR_PYTHON_SCRIPT VAR_VAL_SIG_SKEW_MIN
@@ -1270,7 +1271,7 @@
 	| ;
 content_rc: rc_control_enable | rc_control_interface | rc_control_port |
 	rc_server_key_file | rc_server_cert_file | rc_control_key_file |
-	rc_control_cert_file
+	rc_control_cert_file | rc_control_use_cert
 	;
 rc_control_enable: VAR_CONTROL_ENABLE STRING_ARG
 	{
@@ -1298,6 +1299,16 @@
 			yyerror("out of memory");
 	}
 	;
+rc_control_use_cert: VAR_CONTROL_USE_CERT STRING_ARG
+	{
+		OUTYY(("P(control_use_cert:%s)\n", $2));
+		if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+			yyerror("expected yes or no.");
+		else cfg_parser->cfg->remote_control_use_cert =
+			(strcmp($2, "yes")==0);
+		free($2);
+	}
+	;
 rc_server_key_file: VAR_SERVER_KEY_FILE STRING_ARG
 	{
 		OUTYY(("P(rc_server_key_file:%s)\n", $2));
Index: util/config_file.h
===================================================================
--- util/config_file.h	(revision 276697)
+++ util/config_file.h	(revision 276698)
@@ -192,6 +192,8 @@
 	char* chrootdir;
 	/** username to change to, if not "". */
 	char* username;
+	uid_t uid;
+	gid_t gid;
 	/** working directory */
 	char* directory;
 	/** filename to log to. */
@@ -282,6 +284,8 @@
 	struct config_strlist* control_ifs;
 	/** port number for the control port */
 	int control_port;
+	/** use certificates for remote control */
+	int remote_control_use_cert;
 	/** private key file for server */
 	char* server_key_file;
 	/** certificate file for server */
Index: util/net_help.c
===================================================================
--- util/net_help.c	(revision 276697)
+++ util/net_help.c	(revision 276698)
@@ -156,7 +156,7 @@
 		case AF_INET6: family="ip6";
 			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
 			break;
-		case AF_UNIX: family="unix"; break;
+		case AF_LOCAL: family="local"; break;
 		default: break;
 	}
 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
@@ -313,7 +313,7 @@
 		case AF_INET6: family="";
 			sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
 			break;
-		case AF_UNIX: family="unix_family "; break;
+		case AF_LOCAL: family="local "; break;
 		default: break;
 	}
 	if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
Index: util/configlexer.lex
===================================================================
--- util/configlexer.lex	(revision 276697)
+++ util/configlexer.lex	(revision 276698)
@@ -315,6 +315,7 @@
 control-enable{COLON}		{ YDVAR(1, VAR_CONTROL_ENABLE) }
 control-interface{COLON}	{ YDVAR(1, VAR_CONTROL_INTERFACE) }
 control-port{COLON}		{ YDVAR(1, VAR_CONTROL_PORT) }
+control-use-cert{COLON}		{ YDVAR(1, VAR_CONTROL_USE_CERT) }
 server-key-file{COLON}		{ YDVAR(1, VAR_SERVER_KEY_FILE) }
 server-cert-file{COLON}		{ YDVAR(1, VAR_SERVER_CERT_FILE) }
 control-key-file{COLON}		{ YDVAR(1, VAR_CONTROL_KEY_FILE) }
Index: services/listen_dnsport.c
===================================================================
--- services/listen_dnsport.c	(revision 276697)
+++ services/listen_dnsport.c	(revision 276698)
@@ -56,6 +56,10 @@
 #endif
 #include <fcntl.h>
 
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
 /** number of queued TCP connections for listen() */
 #define TCP_BACKLOG 256 
 
@@ -571,6 +575,56 @@
 	return s;
 }
 
+int
+create_local_accept_sock(char *path, int* noproto)
+{
+#ifdef HAVE_SYS_UN_H
+	int s;
+	struct sockaddr_un sun;
+
+	sun.sun_len = sizeof(sun);
+	sun.sun_family = AF_LOCAL;
+	strlcpy(sun.sun_path, path, 104);
+
+	if ((s = socket(PF_LOCAL, SOCK_STREAM, 0)) == -1) {
+		log_err("Cannot create local socket %s (%s)",
+			path, strerror(errno));
+		return -1;
+	}
+
+	if (unlink(path) && errno != ENOENT) {
+		/* The socket already exists and cannot be removed */
+		log_err("Cannot remove old local socket %s (%s)",
+			path, strerror(errno));
+		return -1;
+	}
+
+	if (bind(s, (struct sockaddr *)&sun,
+		sizeof(struct sockaddr_un)) == -1) {
+		log_err("Cannot bind local socket %s (%s)",
+			path, strerror(errno));
+		return -1;
+	}
+
+	if (!fd_set_nonblock(s)) {
+		log_err("Cannot set non-blocking mode");
+		return -1;
+	}
+
+	if (listen(s, TCP_BACKLOG) == -1) {
+		log_err("can't listen: %s", strerror(errno));
+		return -1;
+	}
+
+	return s;
+#else
+	log_err("Local sockets are not supported");
+	*noproto = 1;
+	return -1;
+#endif
+}
+
+
 /**
  * Create socket from getaddrinfo results
  */
Index: services/listen_dnsport.h
===================================================================
--- services/listen_dnsport.h	(revision 276697)
+++ services/listen_dnsport.h	(revision 276698)
@@ -207,4 +207,13 @@
 int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
 	int* reuseport);
 
+/**
+ * Create and bind local listening socket
+ * @param path: path to the socket.
+ * @param noproto: on error, this is set true if cause is that local sockets
+ *	are not supported.
+ * @return: the socket. -1 on error.
+ */
+int create_local_accept_sock(char* path, int* noproto);
+
 #endif /* LISTEN_DNSPORT_H */
_______________________________________________
Unbound-users mailing list
[email protected]
http://unbound.nlnetlabs.nl/mailman/listinfo/unbound-users

Reply via email to