2014-05-07 22:27:00 +00:00
|
|
|
/*
|
2015-04-19 21:10:59 +00:00
|
|
|
Copyright (c) 2009-2015 Roger Light <roger@atchoo.org>
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2015-04-29 20:37:47 +00:00
|
|
|
#include "config.h"
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <sys/socket.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 __FreeBSD__
|
|
|
|
# include <netinet/in.h>
|
|
|
|
# include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __QNX__
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <net/netbyte.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
|
2015-04-29 20:37:47 +00:00
|
|
|
#include "mosquitto_broker.h"
|
|
|
|
#include "mqtt3_protocol.h"
|
|
|
|
#include "memory_mosq.h"
|
|
|
|
#include "net_mosq.h"
|
|
|
|
#include "util_mosq.h"
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
#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
|
|
|
|
|
2015-05-16 11:25:35 +00:00
|
|
|
#include "sys_tree.h"
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-05-16 17:43:06 +00:00
|
|
|
int net__socket_accept(struct mosquitto_db *db, int listensock)
|
2014-05-07 22:27:00 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int j;
|
|
|
|
int new_sock = -1;
|
|
|
|
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) return -1;
|
|
|
|
|
2015-05-16 11:25:35 +00:00
|
|
|
G_SOCKET_CONNECTIONS_INC();
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2015-04-19 21:10:59 +00:00
|
|
|
if(mosquitto__socket_nonblock(new_sock)){
|
2014-05-07 22:27:00 +00:00
|
|
|
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 */
|
2015-04-19 21:10:59 +00:00
|
|
|
if(!mosquitto__socket_get_address(new_sock, address, 1024)){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied access by tcpd.", address);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
COMPAT_CLOSE(new_sock);
|
|
|
|
return -1;
|
2014-06-23 08:43:32 +00:00
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
#endif
|
2015-05-16 14:24:24 +00:00
|
|
|
new_context = context__init(db, new_sock);
|
2014-06-23 08:43:32 +00:00
|
|
|
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;
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-23 08:43:32 +00:00
|
|
|
}
|
|
|
|
if(!new_context->listener){
|
2015-05-16 14:24:24 +00:00
|
|
|
context__cleanup(db, new_context, true);
|
2014-06-23 08:43:32 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
2014-06-23 08:43:32 +00:00
|
|
|
if(new_context->listener->max_connections > 0 && new_context->listener->client_count > new_context->listener->max_connections){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", new_context->address);
|
2015-05-16 14:24:24 +00:00
|
|
|
context__cleanup(db, new_context, true);
|
2014-06-23 08:43:32 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
#ifdef WITH_TLS
|
2014-06-23 08:43:32 +00:00
|
|
|
/* 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){
|
2015-05-16 14:24:24 +00:00
|
|
|
context__cleanup(db, new_context, true);
|
2014-06-23 08:43:32 +00:00
|
|
|
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);
|
|
|
|
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{
|
|
|
|
e = ERR_get_error();
|
|
|
|
while(e){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_NOTICE,
|
2014-06-23 08:43:32 +00:00
|
|
|
"Client connection from %s failed: %s.",
|
|
|
|
new_context->address, ERR_error_string(e, ebuf));
|
2014-05-07 22:27:00 +00:00
|
|
|
e = ERR_get_error();
|
|
|
|
}
|
2015-05-16 14:24:24 +00:00
|
|
|
context__cleanup(db, new_context, true);
|
2014-06-23 08:43:32 +00:00
|
|
|
return -1;
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-06-23 08:43:32 +00:00
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
#endif
|
|
|
|
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s on port %d.", new_context->address, new_context->listener->port);
|
2014-06-23 08:43:32 +00:00
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
return new_sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WITH_TLS
|
|
|
|
static int client_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx)
|
|
|
|
{
|
|
|
|
/* Preverify should check expiry, revocation. */
|
|
|
|
return preverify_ok;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef REAL_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;
|
2015-05-16 18:03:12 +00:00
|
|
|
struct mosquitto__listener *listener;
|
2014-05-07 22:27:00 +00:00
|
|
|
char *psk_key = NULL;
|
|
|
|
int len;
|
|
|
|
const char *psk_hint;
|
|
|
|
|
|
|
|
if(!identity) return 0;
|
|
|
|
|
2015-04-19 21:10:59 +00:00
|
|
|
db = mosquitto__get_db();
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
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. */
|
2015-04-19 21:10:59 +00:00
|
|
|
psk_key = mosquitto__calloc(1, max_psk_len*2 + 1);
|
2014-05-07 22:27:00 +00:00
|
|
|
if(!psk_key) return 0;
|
|
|
|
|
|
|
|
if(mosquitto_psk_key_get(db, psk_hint, identity, psk_key, max_psk_len*2) != MOSQ_ERR_SUCCESS){
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(psk_key);
|
2014-05-07 22:27:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-04-19 21:10:59 +00:00
|
|
|
len = mosquitto__hex2bin(psk_key, psk, max_psk_len);
|
2014-06-28 00:38:58 +00:00
|
|
|
if (len < 0){
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(psk_key);
|
2014-06-28 00:38:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
|
|
|
|
if(listener->use_identity_as_username){
|
2015-04-19 21:10:59 +00:00
|
|
|
context->username = mosquitto__strdup(identity);
|
2014-06-28 00:38:58 +00:00
|
|
|
if(!context->username){
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(psk_key);
|
2014-06-28 00:38:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
|
2015-04-19 21:10:59 +00:00
|
|
|
mosquitto__free(psk_key);
|
2014-05-07 22:27:00 +00:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-03 18:33:36 +00:00
|
|
|
#ifdef WITH_TLS
|
2015-05-16 18:03:12 +00:00
|
|
|
static int mosquitto__tls_server_ctx(struct mosquitto__listener *listener)
|
2014-07-03 18:33:36 +00:00
|
|
|
{
|
|
|
|
int ssl_options = 0;
|
|
|
|
char buf[256];
|
|
|
|
int rc;
|
2014-07-03 20:21:40 +00:00
|
|
|
#ifdef WITH_EC
|
2014-07-03 18:35:37 +00:00
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
|
|
|
|
EC_KEY *ecdh = NULL;
|
|
|
|
#endif
|
2014-07-03 20:21:40 +00:00
|
|
|
#endif
|
2014-07-03 18:33:36 +00:00
|
|
|
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
|
|
|
|
if(listener->tls_version == NULL){
|
|
|
|
listener->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
|
|
|
}else if(!strcmp(listener->tls_version, "tlsv1.2")){
|
|
|
|
listener->ssl_ctx = SSL_CTX_new(TLSv1_2_server_method());
|
|
|
|
}else if(!strcmp(listener->tls_version, "tlsv1.1")){
|
|
|
|
listener->ssl_ctx = SSL_CTX_new(TLSv1_1_server_method());
|
|
|
|
}else if(!strcmp(listener->tls_version, "tlsv1")){
|
|
|
|
listener->ssl_ctx = SSL_CTX_new(TLSv1_server_method());
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
listener->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
|
|
|
#endif
|
|
|
|
if(!listener->ssl_ctx){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS context.");
|
2014-07-03 18:33:36 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't accept SSLv2 or SSLv3 */
|
|
|
|
ssl_options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
|
|
|
|
#ifdef SSL_OP_NO_COMPRESSION
|
|
|
|
/* Disable compression */
|
|
|
|
ssl_options |= SSL_OP_NO_COMPRESSION;
|
|
|
|
#endif
|
|
|
|
#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
|
|
|
|
/* Server chooses cipher */
|
|
|
|
ssl_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
|
|
|
|
#endif
|
|
|
|
SSL_CTX_set_options(listener->ssl_ctx, ssl_options);
|
|
|
|
|
|
|
|
#ifdef SSL_MODE_RELEASE_BUFFERS
|
|
|
|
/* Use even less memory per SSL connection. */
|
|
|
|
SSL_CTX_set_mode(listener->ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
|
|
|
#endif
|
2014-07-03 18:35:37 +00:00
|
|
|
|
2014-07-03 20:21:40 +00:00
|
|
|
#ifdef WITH_EC
|
2014-07-03 18:35:37 +00:00
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
|
SSL_CTX_set_ecdh_auto(listener->ssl_ctx, 1);
|
|
|
|
#elif OPENSSL_VERSION_NUMBER >= 0x10000000L && OPENSSL_VERSION_NUMBER < 0x10002000L
|
|
|
|
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
|
|
|
if(!ecdh){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to create TLS ECDH curve.");
|
2014-07-03 18:35:37 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
SSL_CTX_set_tmp_ecdh(listener->ssl_ctx, ecdh);
|
|
|
|
EC_KEY_free(ecdh);
|
2014-07-03 20:21:40 +00:00
|
|
|
#endif
|
2014-07-03 18:35:37 +00:00
|
|
|
#endif
|
|
|
|
|
2014-07-03 18:33:36 +00:00
|
|
|
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){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
|
2014-07-03 18:33:36 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
rc = SSL_CTX_set_cipher_list(listener->ssl_ctx, "DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:@STRENGTH");
|
|
|
|
if(rc == 0){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS ciphers. Check cipher list \"%s\".", listener->ciphers);
|
2014-07-03 18:33:36 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return MOSQ_ERR_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-05-07 22:27:00 +00:00
|
|
|
/* Creates a socket and listens on port 'port'.
|
|
|
|
* Returns 1 on failure
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
2015-05-16 18:03:12 +00:00
|
|
|
int net__socket_listen(struct mosquitto__listener *listener)
|
2014-05-07 22:27:00 +00:00
|
|
|
{
|
|
|
|
int sock = -1;
|
|
|
|
struct addrinfo hints;
|
|
|
|
struct addrinfo *ainfo, *rp;
|
|
|
|
char service[10];
|
|
|
|
#ifndef WIN32
|
|
|
|
int ss_opt = 1;
|
|
|
|
#else
|
|
|
|
char ss_opt = 1;
|
|
|
|
#endif
|
|
|
|
#ifdef WITH_TLS
|
|
|
|
int rc;
|
|
|
|
X509_STORE *store;
|
|
|
|
X509_LOOKUP *lookup;
|
|
|
|
#endif
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
if(!listener) return MOSQ_ERR_INVAL;
|
|
|
|
|
|
|
|
snprintf(service, 10, "%d", listener->port);
|
|
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
|
|
hints.ai_family = PF_UNSPEC;
|
|
|
|
hints.ai_flags = AI_PASSIVE;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
|
|
|
if(getaddrinfo(listener->host, service, &hints, &ainfo)) return INVALID_SOCKET;
|
|
|
|
|
|
|
|
listener->sock_count = 0;
|
|
|
|
listener->socks = NULL;
|
|
|
|
|
|
|
|
for(rp = ainfo; rp; rp = rp->ai_next){
|
|
|
|
if(rp->ai_family == AF_INET){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_INFO, "Opening ipv4 listen socket on port %d.", ntohs(((struct sockaddr_in *)rp->ai_addr)->sin_port));
|
2014-05-07 22:27:00 +00:00
|
|
|
}else if(rp->ai_family == AF_INET6){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_INFO, "Opening ipv6 listen socket on port %d.", ntohs(((struct sockaddr_in6 *)rp->ai_addr)->sin6_port));
|
2014-05-07 22:27:00 +00:00
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
|
|
|
if(sock == -1){
|
|
|
|
strerror_r(errno, buf, 256);
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: %s", buf);
|
2014-05-07 22:27:00 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
listener->sock_count++;
|
2015-04-19 21:10:59 +00:00
|
|
|
listener->socks = mosquitto__realloc(listener->socks, sizeof(int)*listener->sock_count);
|
2014-05-07 22:27:00 +00:00
|
|
|
if(!listener->socks){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Out of memory.");
|
2014-05-07 22:27:00 +00:00
|
|
|
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
|
|
|
|
ss_opt = 1;
|
|
|
|
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &ss_opt, sizeof(ss_opt));
|
|
|
|
|
2015-04-19 21:10:59 +00:00
|
|
|
if(mosquitto__socket_nonblock(sock)){
|
2014-05-07 22:27:00 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){
|
2015-01-28 20:56:51 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
errno = WSAGetLastError();
|
|
|
|
#endif
|
2014-05-07 22:27:00 +00:00
|
|
|
strerror_r(errno, buf, 256);
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s", buf);
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(listen(sock, 100) == -1){
|
2015-01-28 20:56:51 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
errno = WSAGetLastError();
|
|
|
|
#endif
|
2014-05-07 22:27:00 +00:00
|
|
|
strerror_r(errno, buf, 256);
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: %s", buf);
|
2014-05-07 22:27:00 +00:00
|
|
|
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){
|
2015-04-19 21:10:59 +00:00
|
|
|
if(mosquitto__tls_server_ctx(listener)){
|
2014-05-07 22:27:00 +00:00
|
|
|
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){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\" and capath \"%s\".", listener->cafile, listener->capath);
|
2014-05-07 22:27:00 +00:00
|
|
|
}else if(listener->cafile){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check cafile \"%s\".", listener->cafile);
|
2014-05-07 22:27:00 +00:00
|
|
|
}else{
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load CA certificates. Check capath \"%s\".", listener->capath);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/* 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{
|
2014-10-07 22:20:46 +00:00
|
|
|
SSL_CTX_set_verify(listener->ssl_ctx, SSL_VERIFY_NONE, client_certificate_verify);
|
2014-05-07 22:27:00 +00:00
|
|
|
}
|
|
|
|
rc = SSL_CTX_use_certificate_chain_file(listener->ssl_ctx, listener->certfile);
|
|
|
|
if(rc != 1){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server certificate \"%s\". Check certfile.", listener->certfile);
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
rc = SSL_CTX_use_PrivateKey_file(listener->ssl_ctx, listener->keyfile, SSL_FILETYPE_PEM);
|
|
|
|
if(rc != 1){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load server key file \"%s\". Check keyfile.", listener->keyfile);
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
rc = SSL_CTX_check_private_key(listener->ssl_ctx);
|
|
|
|
if(rc != 1){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Server certificate/key are inconsistent.");
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
/* Load CRLs if they exist. */
|
|
|
|
if(listener->crlfile){
|
|
|
|
store = SSL_CTX_get_cert_store(listener->ssl_ctx);
|
|
|
|
if(!store){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to obtain TLS store.");
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
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){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to load certificate revocation file \"%s\". Check crlfile.", listener->crlfile);
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK);
|
|
|
|
}
|
|
|
|
|
|
|
|
# ifdef REAL_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);
|
|
|
|
}
|
|
|
|
|
2015-04-19 21:10:59 +00:00
|
|
|
if(mosquitto__tls_server_ctx(listener)){
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
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){
|
2015-05-18 07:53:21 +00:00
|
|
|
log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to set TLS PSK hint.");
|
2014-05-07 22:27:00 +00:00
|
|
|
COMPAT_CLOSE(sock);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# endif /* REAL_WITH_TLS_PSK */
|
|
|
|
}
|
|
|
|
#endif /* WITH_TLS */
|
|
|
|
return 0;
|
|
|
|
}else{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-16 17:43:06 +00:00
|
|
|
int net__socket_get_address(int sock, char *buf, int len)
|
2014-05-07 22:27:00 +00:00
|
|
|
{
|
|
|
|
struct sockaddr_storage addr;
|
|
|
|
socklen_t addrlen;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|