diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2015-01-05 14:59:18 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2015-01-05 14:59:18 +0000 |
commit | 31099b506d62d7cc49c57c2c36e5eba7411ec513 (patch) | |
tree | 30705480abca4f4e30ced6b496cc411d8f48cac8 /contrib/unbound | |
parent | 74342541e2fe7402ea8179718e98b4ba79f6cdd5 (diff) | |
parent | 3ff5baf8cb6770d63f234c261e9af15848bb939c (diff) | |
download | src-test2-31099b506d62d7cc49c57c2c36e5eba7411ec513.tar.gz src-test2-31099b506d62d7cc49c57c2c36e5eba7411ec513.zip |
Notes
Diffstat (limited to 'contrib/unbound')
-rw-r--r-- | contrib/unbound/config.h | 6 | ||||
-rw-r--r-- | contrib/unbound/config.h.in | 6 | ||||
-rw-r--r-- | contrib/unbound/configure.ac | 2 | ||||
-rw-r--r-- | contrib/unbound/daemon/remote.c | 118 | ||||
-rw-r--r-- | contrib/unbound/daemon/remote.h | 2 | ||||
-rw-r--r-- | contrib/unbound/daemon/unbound.c | 39 | ||||
-rw-r--r-- | contrib/unbound/doc/unbound.conf.5 | 33 | ||||
-rw-r--r-- | contrib/unbound/doc/unbound.conf.5.in | 33 | ||||
-rw-r--r-- | contrib/unbound/services/listen_dnsport.c | 54 | ||||
-rw-r--r-- | contrib/unbound/services/listen_dnsport.h | 9 | ||||
-rw-r--r-- | contrib/unbound/smallapp/unbound-checkconf.c | 2 | ||||
-rw-r--r-- | contrib/unbound/smallapp/unbound-control.c | 81 | ||||
-rw-r--r-- | contrib/unbound/util/config_file.c | 16 | ||||
-rw-r--r-- | contrib/unbound/util/config_file.h | 4 | ||||
-rw-r--r-- | contrib/unbound/util/configlexer.lex | 1 | ||||
-rw-r--r-- | contrib/unbound/util/configparser.y | 13 | ||||
-rw-r--r-- | contrib/unbound/util/net_help.c | 4 |
17 files changed, 321 insertions, 102 deletions
diff --git a/contrib/unbound/config.h b/contrib/unbound/config.h index 10cf2992267a..17828ee85657 100644 --- a/contrib/unbound/config.h +++ b/contrib/unbound/config.h @@ -381,6 +381,9 @@ /* Define to 1 if you have the <sys/uio.h> header file. */ #define HAVE_SYS_UIO_H 1 +/* Define to 1 if you have the <sys/un.h> header file. */ +#define HAVE_SYS_UN_H 1 + /* Define to 1 if you have the <sys/wait.h> header file. */ #define HAVE_SYS_WAIT_H 1 @@ -429,7 +432,8 @@ /* if lex has yylex_destroy */ #define LEX_HAS_YYLEX_DESTROY 1 -/* Define to the sub-directory where libtool stores uninstalled libraries. */ +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ #define LT_OBJDIR ".libs/" /* Define to the maximum message length to pass to syslog. */ diff --git a/contrib/unbound/config.h.in b/contrib/unbound/config.h.in index 9f5359847565..7a8a5dd58e9c 100644 --- a/contrib/unbound/config.h.in +++ b/contrib/unbound/config.h.in @@ -380,6 +380,9 @@ /* Define to 1 if you have the <sys/uio.h> header file. */ #undef HAVE_SYS_UIO_H +/* Define to 1 if you have the <sys/un.h> header file. */ +#undef HAVE_SYS_UN_H + /* Define to 1 if you have the <sys/wait.h> header file. */ #undef HAVE_SYS_WAIT_H @@ -428,7 +431,8 @@ /* if lex has yylex_destroy */ #undef LEX_HAS_YYLEX_DESTROY -/* Define to the sub-directory where libtool stores uninstalled libraries. */ +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ #undef LT_OBJDIR /* Define to the maximum message length to pass to syslog. */ diff --git a/contrib/unbound/configure.ac b/contrib/unbound/configure.ac index 7e5da1a9f046..37e1bf6f4bca 100644 --- a/contrib/unbound/configure.ac +++ b/contrib/unbound/configure.ac @@ -266,7 +266,7 @@ AC_CHECK_TOOL(STRIP, strip) 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. diff --git a/contrib/unbound/daemon/remote.c b/contrib/unbound/daemon/remote.c index ff3d769d4e54..a1d2628a904a 100644 --- a/contrib/unbound/daemon/remote.c +++ b/contrib/unbound/daemon/remote.c @@ -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 @@ timeval_divide(struct timeval* avg, const struct timeval* sum, size_t d) #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_create(struct config_file* cfg) 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 @@ void daemon_remote_delete(struct daemon_remote* rc) * @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 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err) 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) { -#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(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 */ + } #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 @@ struct listen_port* daemon_remote_open_ports(struct config_file* cfg) 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 @@ struct listen_port* daemon_remote_open_ports(struct config_file* cfg) } 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 @@ int remote_control_callback(struct comm_point* c, void* arg, int err, 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 " diff --git a/contrib/unbound/daemon/remote.h b/contrib/unbound/daemon/remote.h index cc670b70128f..b25bfb1af611 100644 --- a/contrib/unbound/daemon/remote.h +++ b/contrib/unbound/daemon/remote.h @@ -89,6 +89,8 @@ struct daemon_remote { 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 */ diff --git a/contrib/unbound/daemon/unbound.c b/contrib/unbound/daemon/unbound.c index 5ded5a964cc3..e48a6b5ea951 100644 --- a/contrib/unbound/daemon/unbound.c +++ b/contrib/unbound/daemon/unbound.c @@ -441,20 +441,14 @@ static void 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 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, #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 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, /* 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,27 +588,27 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode, #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 */ 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)); diff --git a/contrib/unbound/doc/unbound.conf.5 b/contrib/unbound/doc/unbound.conf.5 index ab5cc9da5ccd..c9541da7fea1 100644 --- a/contrib/unbound/doc/unbound.conf.5 +++ b/contrib/unbound/doc/unbound.conf.5 @@ -958,36 +958,47 @@ to setup SSLv3 / TLSv1 security for the connection. The 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. diff --git a/contrib/unbound/doc/unbound.conf.5.in b/contrib/unbound/doc/unbound.conf.5.in index f08a01b31844..9b23fd64da1b 100644 --- a/contrib/unbound/doc/unbound.conf.5.in +++ b/contrib/unbound/doc/unbound.conf.5.in @@ -958,36 +958,47 @@ to setup SSLv3 / TLSv1 security for the connection. The 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. diff --git a/contrib/unbound/services/listen_dnsport.c b/contrib/unbound/services/listen_dnsport.c index b7ffb6d3fad3..69c68b2807ff 100644 --- a/contrib/unbound/services/listen_dnsport.c +++ b/contrib/unbound/services/listen_dnsport.c @@ -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 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, 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 */ diff --git a/contrib/unbound/services/listen_dnsport.h b/contrib/unbound/services/listen_dnsport.h index 075f6d281d5d..0513b5d6c01b 100644 --- a/contrib/unbound/services/listen_dnsport.h +++ b/contrib/unbound/services/listen_dnsport.h @@ -207,4 +207,13 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr, 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 */ diff --git a/contrib/unbound/smallapp/unbound-checkconf.c b/contrib/unbound/smallapp/unbound-checkconf.c index e83867f26844..7723c3357695 100644 --- a/contrib/unbound/smallapp/unbound-checkconf.c +++ b/contrib/unbound/smallapp/unbound-checkconf.c @@ -416,7 +416,7 @@ morechecks(struct config_file* cfg, const char* fname) 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, diff --git a/contrib/unbound/smallapp/unbound-control.c b/contrib/unbound/smallapp/unbound-control.c index ff86184a8162..37e840bad799 100644 --- a/contrib/unbound/smallapp/unbound-control.c +++ b/contrib/unbound/smallapp/unbound-control.c @@ -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 @@ setup_ctx(struct config_file* cfg) 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 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd) { 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 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd) 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 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd) /** 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 @@ setup_ssl(SSL_CTX* ctx, int fd) /* 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 @@ go(const char* cfgfile, char* svr, int quiet, int argc, char* argv[]) 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); diff --git a/contrib/unbound/util/config_file.c b/contrib/unbound/util/config_file.c index a11d217ecc12..922901041bd7 100644 --- a/contrib/unbound/util/config_file.c +++ b/contrib/unbound/util/config_file.c @@ -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 @@ config_create(void) 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 @@ config_read(struct config_file* cfg, const char* filename, const char* chroot) 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; } diff --git a/contrib/unbound/util/config_file.h b/contrib/unbound/util/config_file.h index 49ffbdde4a56..fd35d7863ae1 100644 --- a/contrib/unbound/util/config_file.h +++ b/contrib/unbound/util/config_file.h @@ -192,6 +192,8 @@ struct config_file { 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_file { 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 */ diff --git a/contrib/unbound/util/configlexer.lex b/contrib/unbound/util/configlexer.lex index 5840560f6d04..e13bad07536d 100644 --- a/contrib/unbound/util/configlexer.lex +++ b/contrib/unbound/util/configlexer.lex @@ -317,6 +317,7 @@ remote-control{COLON} { YDVAR(0, VAR_REMOTE_CONTROL) } 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) } diff --git a/contrib/unbound/util/configparser.y b/contrib/unbound/util/configparser.y index 7a92d9ee7899..cbb5e16bd813 100644 --- a/contrib/unbound/util/configparser.y +++ b/contrib/unbound/util/configparser.y @@ -95,6 +95,7 @@ extern struct config_parser_state* cfg_parser; %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 @@ contents_rc: contents_rc content_rc | ; 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 @@ rc_control_interface: VAR_CONTROL_INTERFACE STRING_ARG 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)); diff --git a/contrib/unbound/util/net_help.c b/contrib/unbound/util/net_help.c index 8c2bac7372fc..335ee7499e7d 100644 --- a/contrib/unbound/util/net_help.c +++ b/contrib/unbound/util/net_help.c @@ -156,7 +156,7 @@ log_addr(enum verbosity_value v, const char* str, 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 @@ void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone, 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) { |