/*
|
Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
|
|
All rights reserved. This program and the accompanying materials
|
are made available under the terms of the Eclipse Public License v1.0
|
and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
The Eclipse Public License is available at
|
http://www.eclipse.org/legal/epl-v10.html
|
and the Eclipse Distribution License is available at
|
http://www.eclipse.org/org/documents/edl-v10.php.
|
|
Contributors:
|
Roger Light - initial implementation and documentation.
|
*/
|
|
#include "config.h"
|
|
#ifndef WIN32
|
#include <netdb.h>
|
#include <unistd.h>
|
#include <arpa/inet.h>
|
#include <sys/socket.h>
|
#include <netinet/tcp.h>
|
#include <net/if.h>
|
#else
|
#include <winsock2.h>
|
#include <ws2tcpip.h>
|
#endif
|
|
#include <assert.h>
|
#include <errno.h>
|
#include <fcntl.h>
|
#include <stdio.h>
|
#include <string.h>
|
#ifdef WITH_WRAP
|
#include <tcpd.h>
|
#endif
|
|
#ifdef HAVE_NETINET_IN_H
|
# include <netinet/in.h>
|
#endif
|
|
#ifdef __QNX__
|
#include <net/netbyte.h>
|
#endif
|
|
#include "mosquitto_broker_internal.h"
|
#include "mqtt_protocol.h"
|
#include "memory_mosq.h"
|
#include "net_mosq.h"
|
#include "util_mosq.h"
|
|
#ifdef WITH_TLS
|
#include "tls_mosq.h"
|
#include <openssl/err.h>
|
static int tls_ex_index_context = -1;
|
static int tls_ex_index_listener = -1;
|
#endif
|
|
#include "sys_tree.h"
|
|
/* For EMFILE handling */
|
static mosq_sock_t spare_sock = INVALID_SOCKET;
|
|
void net__broker_init(void)
|
{
|
spare_sock = socket(AF_INET, SOCK_STREAM, 0);
|
net__init();
|
}
|
|
|
void net__broker_cleanup(void)
|
{
|
if(spare_sock != INVALID_SOCKET){
|
COMPAT_CLOSE(spare_sock);
|
spare_sock = INVALID_SOCKET;
|
}
|
net__cleanup();
|
}
|
|
|
static void net__print_error(int log, const char *format_str)
|
{
|
char *buf;
|
|
#ifdef WIN32
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
NULL, WSAGetLastError(), LANG_NEUTRAL, &buf, 0, NULL);
|
|
log__printf(NULL, log, format_str, buf);
|
LocalFree(buf);
|
#else
|
buf = strerror(errno);
|
log__printf(NULL, log, format_str, buf);
|
#endif
|
}
|
|
|
int net__socket_accept(struct mosquitto_db *db, mosq_sock_t listensock)
|
{
|
int i;
|
int j;
|
mosq_sock_t new_sock = INVALID_SOCKET;
|
struct mosquitto *new_context;
|
#ifdef WITH_TLS
|
BIO *bio;
|
int rc;
|
char ebuf[256];
|
unsigned long e;
|
#endif
|
#ifdef WITH_WRAP
|
struct request_info wrap_req;
|
char address[1024];
|
#endif
|
|
new_sock = accept(listensock, NULL, 0);
|
if(new_sock == INVALID_SOCKET){
|
#ifdef WIN32
|
errno = WSAGetLastError();
|
if(errno == WSAEMFILE){
|
#else
|
if(errno == EMFILE || errno == ENFILE){
|
#endif
|
/* Close the spare socket, which means we should be able to accept
|
* this connection. Accept it, then close it immediately and create
|
* a new spare_sock. This prevents the situation of ever properly
|
* running out of sockets.
|
* It would be nice to send a "server not available" connack here,
|
* but there are lots of reasons why this would be tricky (TLS
|
* being the big one). */
|
COMPAT_CLOSE(spare_sock);
|
new_sock = accept(listensock, NULL, 0);
|
if(new_sock != INVALID_SOCKET){
|
COMPAT_CLOSE(new_sock);
|
}
|
spare_sock = socket(AF_INET, SOCK_STREAM, 0);
|
log__printf(NULL, MOSQ_LOG_WARNING,
|
"Unable to accept new connection, system socket count has been exceeded. Try increasing \"ulimit -n\" or equivalent.");
|
}
|
return -1;
|
}
|
|
G_SOCKET_CONNECTIONS_INC();
|
|
if(net__socket_nonblock(&new_sock)){
|
return INVALID_SOCKET;
|
}
|
|
#ifdef WITH_WRAP
|
/* Use tcpd / libwrap to determine whether a connection is allowed. */
|
request_init(&wrap_req, RQ_FILE, new_sock, RQ_DAEMON, "mosquitto", 0);
|
fromhost(&wrap_req);
|
if(!hosts_access(&wrap_req)){
|
/* Access is denied */
|
if(db->config->connection_messages == true){
|
if(!net__socket_get_address(new_sock, address, 1024)){
|
log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied access by tcpd.", address);
|
}
|
}
|
COMPAT_CLOSE(new_sock);
|
return -1;
|
}
|
#endif
|
|
if(db->config->set_tcp_nodelay){
|
int flag = 1;
|
if(setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)) != 0){
|
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: Unable to set TCP_NODELAY.");
|
}
|
}
|
|
new_context = context__init(db, new_sock);
|
if(!new_context){
|
COMPAT_CLOSE(new_sock);
|
return -1;
|
}
|
for(i=0; i<db->config->listener_count; i++){
|
for(j=0; j<db->config->listeners[i].sock_count; j++){
|
if(db->config->listeners[i].socks[j] == listensock){
|
new_context->listener = &db->config->listeners[i];
|
new_context->listener->client_count++;
|
break;
|
}
|
}
|
}
|
if(!new_context->listener){
|
context__cleanup(db, new_context, true);
|
return -1;
|
}
|
|
if(new_context->listener->max_connections > 0 && new_context->listener->client_count > new_context->listener->max_connections){
|
if(db->config->connection_messages == true){
|
log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address);
|
}
|
context__cleanup(db, new_context, true);
|
return -1;
|
}
|
|
#ifdef WITH_TLS
|
/* TLS init */
|
for(i=0; i<db->config->listener_count; i++){
|
for(j=0; j<db->config->listeners[i].sock_count; j++){
|
if(db->config->listeners[i].socks[j] == listensock){
|
if(db->config->listeners[i].ssl_ctx){
|
new_context->ssl = SSL_new(db->config->listeners[i].ssl_ctx);
|
if(!new_context->ssl){
|
context__cleanup(db, new_context, true);
|
return -1;
|
}
|
SSL_set_ex_data(new_context->ssl, tls_ex_index_context, new_context);
|
SSL_set_ex_data(new_context->ssl, tls_ex_index_listener, &db->config->listeners[i]);
|
new_context->want_write = true;
|
bio = BIO_new_socket(new_sock, BIO_NOCLOSE);
|
SSL_set_bio(new_context->ssl, bio, bio);
|
ERR_clear_error();
|
rc = SSL_accept(new_context->ssl);
|
if(rc != 1){
|
rc = SSL_get_error(new_context->ssl, rc);
|
if(rc == SSL_ERROR_WANT_READ){
|
/* We always want to read. */
|
}else if(rc == SSL_ERROR_WANT_WRITE){
|
new_context->want_write = true;
|
}else{
|
if(db->config->connection_messages == true){
|
e = ERR_get_error();
|
while(e){
|
log__printf(NULL, MOSQ_LOG_NOTICE,
|
"Client connection from %s failed: %s.",
|
new_context->address, ERR_error_string(e, ebuf));
|
e = ERR_get_error();
|
}
|
}
|
context__cleanup(db, new_context, true);
|
return -1;
|
}
|
}
|
}
|
}
|
}
|
}
|
#endif
|
|
if(db->config->connection_messages == true){
|
log__printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s on port %d.", new_context->address, new_context->listener->port);
|
}
|
|
return new_sock;
|
}
|
|
#ifdef WITH_TLS
|
static int client_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
{
|
UNUSED(ctx);
|
|
/* Preverify should check expiry, revocation. */
|
return preverify_ok;
|
}
|
#endif
|
|
#ifdef FINAL_WITH_TLS_PSK
|
static unsigned int psk_server_callback(SSL *ssl, const char *identity, unsigned char *psk, unsigned int max_psk_len)
|
{
|
struct mosquitto_db *db;
|
struct mosquitto *context;
|
struct mosquitto__listener *listener;
|
char *psk_key = NULL;
|
int len;
|
const char *psk_hint;
|
|
if(!identity) return 0;
|
|
db = mosquitto__get_db();
|
|
context = SSL_get_ex_data(ssl, tls_ex_index_context);
|
if(!context) return 0;
|
|
listener = SSL_get_ex_data(ssl, tls_ex_index_listener);
|
if(!listener) return 0;
|
|
psk_hint = listener->psk_hint;
|
|
/* The hex to BN conversion results in the length halving, so we can pass
|
* max_psk_len*2 as the max hex key here. */
|
psk_key = mosquitto__calloc(1, max_psk_len*2 + 1);
|
if(!psk_key) return 0;
|
|
if(mosquitto_psk_key_get(db, context, psk_hint, identity, psk_key, max_psk_len*2) != MOSQ_ERR_SUCCESS){
|
mosquitto__free(psk_key);
|
return 0;
|
}
|
|
len = mosquitto__hex2bin(psk_key, psk, max_psk_len);
|
if (len < 0){
|
mosquitto__free(psk_key);
|
return 0;
|
}
|
|
if(listener->use_identity_as_username){
|
context->username = mosquitto__strdup(identity);
|
if(!context->username){
|
mosquitto__free(psk_key);
|
return 0;
|
}
|
}
|
|
mosquitto__free(psk_key);
|
return len;
|
}
|
#endif
|
|
#ifdef WITH_TLS
|
static int mosquitto__tls_server_ctx(struct mosquitto__listener *listener)
|
{
|
char buf[256];
|
int rc;
|
FILE *dhparamfile;
|
DH *dhparam = NULL;
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
listener->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
#else
|
listener->ssl_ctx = SSL_CTX_new(TLS_server_method());
|
#endif
|
|
if(!listener->ssl_ctx){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
|
return 1;
|
}
|
|
if(listener->tls_version == NULL){
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1);
|
#ifdef SSL_OP_NO_TLSv1_3
|
}else if(!strcmp(listener->tls_version, "tlsv1.3")){
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
|
}else if(!strcmp(listener->tls_version, "tlsv1.2")){
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_3);
|
}else if(!strcmp(listener->tls_version, "tlsv1.1")){
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3);
|
#else
|
}else if(!strcmp(listener->tls_version, "tlsv1.2")){
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
|
}else if(!strcmp(listener->tls_version, "tlsv1.1")){
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_2);
|
#endif
|
}else{
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unsupported tls_version \"%s\".", listener->tls_version);
|
return 1;
|
}
|
|
#ifdef SSL_OP_NO_COMPRESSION
|
/* Disable compression */
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_COMPRESSION);
|
#endif
|
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
|
/* Server chooses cipher */
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
#endif
|
|
#ifdef SSL_MODE_RELEASE_BUFFERS
|
/* Use even less memory per SSL connection. */
|
SSL_CTX_set_mode(listener->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
#endif
|
|
#ifdef WITH_EC
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L && OPENSSL_VERSION_NUMBER < 0x10100000L
|
SSL_CTX_set_ecdh_auto(listener->ssl_ctx, 1);
|
#endif
|
#endif
|
|
#ifdef SSL_OP_NO_RENEGOTIATION
|
SSL_CTX_set_options(listener->ssl_ctx, SSL_OP_NO_RENEGOTIATION);
|
#endif
|
|
snprintf(buf, 256, "mosquitto-%d", listener->port);
|
SSL_CTX_set_session_id_context(listener->ssl_ctx, (unsigned char *)buf, strlen(buf));
|
|
if(listener->ciphers){
|
rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, listener->ciphers);
|
if(rc == 0){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
|
return 1;
|
}
|
}else{
|
rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, "DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH");
|
if(rc == 0){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
|
return 1;
|
}
|
}
|
if(listener->dhparamfile){
|
dhparamfile = fopen(listener->dhparamfile, "r");
|
if(!dhparamfile){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error loading dhparamfile \"%s\".", listener->dhparamfile);
|
return 1;
|
}
|
dhparam = PEM_read_DHparams(dhparamfile, NULL, NULL, NULL);
|
fclose(dhparamfile);
|
|
if(dhparam == NULL || SSL_CTX_set_tmp_dh(listener->ssl_ctx, dhparam) != 1){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error loading dhparamfile \"%s\".", listener->dhparamfile);
|
return 1;
|
}
|
}
|
return MOSQ_ERR_SUCCESS;
|
}
|
#endif
|
|
/* Creates a socket and listens on port 'port'.
|
* Returns 1 on failure
|
* Returns 0 on success.
|
*/
|
int net__socket_listen(struct mosquitto__listener *listener)
|
{
|
mosq_sock_t sock = INVALID_SOCKET;
|
struct addrinfo hints;
|
struct addrinfo *ainfo, *rp;
|
char service[10];
|
int rc;
|
#ifndef WIN32
|
int ss_opt = 1;
|
#else
|
char ss_opt = 1;
|
#endif
|
#ifdef WITH_TLS
|
X509_STORE *store;
|
X509_LOOKUP *lookup;
|
ENGINE *engine = NULL;
|
#endif
|
#ifdef SO_BINDTODEVICE
|
struct ifreq ifr;
|
#endif
|
|
if(!listener) return MOSQ_ERR_INVAL;
|
|
snprintf(service, 10, "%d", listener->port);
|
memset(&hints, 0, sizeof(struct addrinfo));
|
if(listener->socket_domain){
|
hints.ai_family = listener->socket_domain;
|
}else{
|
hints.ai_family = AF_UNSPEC;
|
}
|
hints.ai_flags = AI_PASSIVE;
|
hints.ai_socktype = SOCK_STREAM;
|
|
rc = getaddrinfo(listener->host, service, &hints, &ainfo);
|
if (rc){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error creating listener: %s.", gai_strerror(rc));
|
return INVALID_SOCKET;
|
}
|
|
listener->sock_count = 0;
|
listener->socks = NULL;
|
|
for(rp = ainfo; rp; rp = rp->ai_next){
|
if(rp->ai_family == AF_INET){
|
log__printf(NULL, MOSQ_LOG_INFO, "Opening ipv4 listen socket on port %d.", ntohs(((struct sockaddr_in *)rp->ai_addr)->sin_port));
|
}else if(rp->ai_family == AF_INET6){
|
log__printf(NULL, MOSQ_LOG_INFO, "Opening ipv6 listen socket on port %d.", ntohs(((struct sockaddr_in6 *)rp->ai_addr)->sin6_port));
|
}else{
|
continue;
|
}
|
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
if(sock == INVALID_SOCKET){
|
net__print_error(MOSQ_LOG_WARNING, "Warning: %s");
|
continue;
|
}
|
listener->sock_count++;
|
listener->socks = mosquitto__realloc(listener->socks, sizeof(mosq_sock_t)*listener->sock_count);
|
if(!listener->socks){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
return MOSQ_ERR_NOMEM;
|
}
|
listener->socks[listener->sock_count-1] = sock;
|
|
#ifndef WIN32
|
ss_opt = 1;
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &ss_opt, sizeof(ss_opt));
|
#endif
|
#ifdef IPV6_V6ONLY
|
ss_opt = 1;
|
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ss_opt, sizeof(ss_opt));
|
#endif
|
|
if(net__socket_nonblock(&sock)){
|
return 1;
|
}
|
|
#ifdef SO_BINDTODEVICE
|
if(listener->bind_interface){
|
memset(&ifr, 0, sizeof(ifr));
|
strncpy(ifr.ifr_name, listener->bind_interface, sizeof(ifr.ifr_name)-1);
|
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
|
log__printf(NULL, MOSQ_LOG_INFO, "Binding listener to interface \"%s\".", ifr.ifr_name);
|
if(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
return 1;
|
}
|
}
|
#endif
|
|
if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
return 1;
|
}
|
|
if(listen(sock, 100) == -1){
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
return 1;
|
}
|
}
|
freeaddrinfo(ainfo);
|
|
/* We need to have at least one working socket. */
|
if(listener->sock_count > 0){
|
#ifdef WITH_TLS
|
if((listener->cafile || listener->capath) && listener->certfile && listener->keyfile){
|
if(mosquitto__tls_server_ctx(listener)){
|
COMPAT_CLOSE(sock);
|
return 1;
|
}
|
|
rc = SSL_CTX_load_verify_locations(listener->ssl_ctx, listener->cafile, listener->capath);
|
if(rc == 0){
|
if(listener->cafile && listener->capath){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\" and capath \"%s\".", listener->cafile, listener->capath);
|
}else if(listener->cafile){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\".", listener->cafile);
|
}else{
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check capath \"%s\".", listener->capath);
|
}
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
return 1;
|
}
|
if(listener->tls_engine){
|
#if !defined(OPENSSL_NO_ENGINE)
|
engine = ENGINE_by_id(listener->tls_engine);
|
if(!engine){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error loading %s engine\n", listener->tls_engine);
|
COMPAT_CLOSE(sock);
|
return 1;
|
}
|
if(!ENGINE_init(engine)){
|
log__printf(NULL, MOSQ_LOG_ERR, "Failed engine initialisation\n");
|
ENGINE_free(engine);
|
COMPAT_CLOSE(sock);
|
return 1;
|
}
|
ENGINE_set_default(engine, ENGINE_METHOD_ALL);
|
ENGINE_free(engine); /* release the structural reference from ENGINE_by_id() */
|
#endif
|
}
|
/* FIXME user data? */
|
if(listener->require_certificate){
|
SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, client_certificate_verify);
|
}else{
|
SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_NONE, client_certificate_verify);
|
}
|
rc = SSL_CTX_use_certificate_chain_file(listener->ssl_ctx, listener->certfile);
|
if(rc != 1){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server certificate \"%s\". Check certfile.", listener->certfile);
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
#if !defined(OPENSSL_NO_ENGINE)
|
ENGINE_FINISH(engine);
|
#endif
|
return 1;
|
}
|
if(listener->tls_keyform == mosq_k_engine){
|
#if !defined(OPENSSL_NO_ENGINE)
|
UI_METHOD *ui_method = net__get_ui_method();
|
if(listener->tls_engine_kpass_sha1){
|
if(!ENGINE_ctrl_cmd(engine, ENGINE_SECRET_MODE, ENGINE_SECRET_MODE_SHA, NULL, NULL, 0)){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set engine secret mode sha");
|
COMPAT_CLOSE(sock);
|
ENGINE_FINISH(engine);
|
return 1;
|
}
|
if(!ENGINE_ctrl_cmd(engine, ENGINE_PIN, 0, listener->tls_engine_kpass_sha1, NULL, 0)){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set engine pin");
|
COMPAT_CLOSE(sock);
|
ENGINE_FINISH(engine);
|
return 1;
|
}
|
ui_method = NULL;
|
}
|
EVP_PKEY *pkey = ENGINE_load_private_key(engine, listener->keyfile, ui_method, NULL);
|
if(!pkey){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load engine private key file \"%s\".", listener->keyfile);
|
COMPAT_CLOSE(sock);
|
ENGINE_FINISH(engine);
|
return 1;
|
}
|
if(SSL_CTX_use_PrivateKey(listener->ssl_ctx, pkey) <= 0){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to use engine private key file \"%s\".", listener->keyfile);
|
COMPAT_CLOSE(sock);
|
ENGINE_FINISH(engine);
|
return 1;
|
}
|
#endif
|
}else{
|
rc = SSL_CTX_use_PrivateKey_file(listener->ssl_ctx, listener->keyfile, SSL_FILETYPE_PEM);
|
if(rc != 1){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server key file \"%s\". Check keyfile.", listener->keyfile);
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
#if !defined(OPENSSL_NO_ENGINE)
|
ENGINE_FINISH(engine);
|
#endif
|
return 1;
|
}
|
}
|
rc = SSL_CTX_check_private_key(listener->ssl_ctx);
|
if(rc != 1){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Server certificate/key are inconsistent.");
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
#if !defined(OPENSSL_NO_ENGINE)
|
ENGINE_FINISH(engine);
|
#endif
|
return 1;
|
}
|
/* Load CRLs if they exist. */
|
if(listener->crlfile){
|
store = SSL_CTX_get_cert_store(listener->ssl_ctx);
|
if(!store){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to obtain TLS store.");
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
#if !defined(OPENSSL_NO_ENGINE)
|
ENGINE_FINISH(engine);
|
#endif
|
return 1;
|
}
|
lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
|
rc = X509_load_crl_file(lookup, listener->crlfile, X509_FILETYPE_PEM);
|
if(rc != 1){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load certificate revocation file \"%s\". Check crlfile.", listener->crlfile);
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
#if !defined(OPENSSL_NO_ENGINE)
|
ENGINE_FINISH(engine);
|
#endif
|
return 1;
|
}
|
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
|
}
|
|
# ifdef FINAL_WITH_TLS_PSK
|
}else if(listener->psk_hint){
|
if(tls_ex_index_context == -1){
|
tls_ex_index_context = SSL_get_ex_new_index(0, "client context", NULL, NULL, NULL);
|
}
|
if(tls_ex_index_listener == -1){
|
tls_ex_index_listener = SSL_get_ex_new_index(0, "listener", NULL, NULL, NULL);
|
}
|
|
if(mosquitto__tls_server_ctx(listener)){
|
COMPAT_CLOSE(sock);
|
#if !defined(OPENSSL_NO_ENGINE)
|
ENGINE_FINISH(engine);
|
#endif
|
return 1;
|
}
|
SSL_CTX_set_psk_server_callback(listener->ssl_ctx, psk_server_callback);
|
if(listener->psk_hint){
|
rc = SSL_CTX_use_psk_identity_hint(listener->ssl_ctx, listener->psk_hint);
|
if(rc == 0){
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS PSK hint.");
|
net__print_error(MOSQ_LOG_ERR, "Error: %s");
|
COMPAT_CLOSE(sock);
|
#if !defined(OPENSSL_NO_ENGINE)
|
ENGINE_FINISH(engine);
|
#endif
|
return 1;
|
}
|
}
|
# endif /* FINAL_WITH_TLS_PSK */
|
}
|
#endif /* WITH_TLS */
|
return 0;
|
}else{
|
return 1;
|
}
|
}
|
|
int net__socket_get_address(mosq_sock_t sock, char *buf, int len)
|
{
|
struct sockaddr_storage addr;
|
socklen_t addrlen;
|
|
memset(&addr, 0, sizeof(struct sockaddr_storage));
|
addrlen = sizeof(addr);
|
if(!getpeername(sock, (struct sockaddr *)&addr, &addrlen)){
|
if(addr.ss_family == AF_INET){
|
if(inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr.s_addr, buf, len)){
|
return 0;
|
}
|
}else if(addr.ss_family == AF_INET6){
|
if(inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr.s6_addr, buf, len)){
|
return 0;
|
}
|
}
|
}
|
return 1;
|
}
|