mfv (r276698): support for remote control over local sockets.

This commit is contained in:
Dag-Erling Smørgrav 2015-01-05 14:59:18 +00:00
commit 31099b506d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=276699
17 changed files with 321 additions and 102 deletions

View File

@ -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. */

View File

@ -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. */

View File

@ -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.

View File

@ -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 "

View File

@ -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 */

View File

@ -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));

View File

@ -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.

View File

@ -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.

View File

@ -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
*/

View File

@ -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 */

View File

@ -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,

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -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) }

View File

@ -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));

View File

@ -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) {