diff options
author | George Hazan <ghazan@miranda.im> | 2019-12-23 13:53:27 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-12-23 13:53:27 +0300 |
commit | a29c9194cf2d9f11839ea833872beab754e19527 (patch) | |
tree | 2a1ff6475dd77d41a1e6bf6acfb5be479c5543eb /libs/libmosquitto/src/util_mosq.c | |
parent | c1358991022919836c77d630ee9a3719fff86ed0 (diff) |
libmosquitto - a helper for MQTT clients
Diffstat (limited to 'libs/libmosquitto/src/util_mosq.c')
-rw-r--r-- | libs/libmosquitto/src/util_mosq.c | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/libs/libmosquitto/src/util_mosq.c b/libs/libmosquitto/src/util_mosq.c new file mode 100644 index 0000000000..5e1065e7c4 --- /dev/null +++ b/libs/libmosquitto/src/util_mosq.c @@ -0,0 +1,354 @@ +/* +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" + +#include <assert.h> +#include <string.h> + +#ifdef WIN32 +# include <winsock2.h> +# include <aclapi.h> +# include <io.h> +# include <lmcons.h> +#else +# include <sys/stat.h> +#endif + +#if !defined(WITH_TLS) && defined(__linux__) && defined(__GLIBC__) +# if __GLIBC_PREREQ(2, 25) +# include <sys/random.h> +# define HAVE_GETRANDOM 1 +# endif +#endif + +#ifdef WITH_TLS +# include <openssl/bn.h> +# include <openssl/rand.h> +#endif + +#ifdef WITH_BROKER +#include "mosquitto_broker_internal.h" +#endif + +#include "mosquitto.h" +#include "memory_mosq.h" +#include "net_mosq.h" +#include "send_mosq.h" +#include "time_mosq.h" +#include "tls_mosq.h" +#include "util_mosq.h" + +#ifdef WITH_WEBSOCKETS +#include <libwebsockets.h> +#endif + +#ifdef WITH_BROKER +int mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq) +#else +int mosquitto__check_keepalive(struct mosquitto *mosq) +#endif +{ + time_t next_msg_out; + time_t last_msg_in; + time_t now = mosquitto_time(); +#ifndef WITH_BROKER + int rc; +#endif + + assert(mosq); +#if defined(WITH_BROKER) && defined(WITH_BRIDGE) + /* Check if a lazy bridge should be timed out due to idle. */ + if(mosq->bridge && mosq->bridge->start_type == bst_lazy + && mosq->sock != INVALID_SOCKET + && now - mosq->next_msg_out - mosq->keepalive >= mosq->bridge->idle_timeout){ + + log__printf(NULL, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id); + net__socket_close(db, mosq); + return MOSQ_ERR_SUCCESS; + } +#endif + pthread_mutex_lock(&mosq->msgtime_mutex); + next_msg_out = mosq->next_msg_out; + last_msg_in = mosq->last_msg_in; + pthread_mutex_unlock(&mosq->msgtime_mutex); + if(mosq->keepalive && mosq->sock != INVALID_SOCKET && + (now >= next_msg_out || now - last_msg_in >= mosq->keepalive)){ + + if(mosq->state == mosq_cs_connected && mosq->ping_t == 0){ + send__pingreq(mosq); + /* Reset last msg times to give the server time to send a pingresp */ + pthread_mutex_lock(&mosq->msgtime_mutex); + mosq->last_msg_in = now; + mosq->next_msg_out = now + mosq->keepalive; + pthread_mutex_unlock(&mosq->msgtime_mutex); + }else{ +#ifdef WITH_BROKER + net__socket_close(db, mosq); +#else + net__socket_close(mosq); + pthread_mutex_lock(&mosq->state_mutex); + if(mosq->state == mosq_cs_disconnecting){ + rc = MOSQ_ERR_SUCCESS; + }else{ + rc = MOSQ_ERR_KEEPALIVE; + } + pthread_mutex_unlock(&mosq->state_mutex); + pthread_mutex_lock(&mosq->callback_mutex); + if(mosq->on_disconnect){ + mosq->in_callback = true; + mosq->on_disconnect(mosq, mosq->userdata, rc); + mosq->in_callback = false; + } + if(mosq->on_disconnect_v5){ + mosq->in_callback = true; + mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL); + mosq->in_callback = false; + } + pthread_mutex_unlock(&mosq->callback_mutex); + + return rc; +#endif + } + } + return MOSQ_ERR_SUCCESS; +} + +uint16_t mosquitto__mid_generate(struct mosquitto *mosq) +{ + /* FIXME - this would be better with atomic increment, but this is safer + * for now for a bug fix release. + * + * If this is changed to use atomic increment, callers of this function + * will have to be aware that they may receive a 0 result, which may not be + * used as a mid. + */ + uint16_t mid; + assert(mosq); + + pthread_mutex_lock(&mosq->mid_mutex); + mosq->last_mid++; + if(mosq->last_mid == 0) mosq->last_mid++; + mid = mosq->last_mid; + pthread_mutex_unlock(&mosq->mid_mutex); + + return mid; +} + + +#ifdef WITH_TLS +int mosquitto__hex2bin_sha1(const char *hex, unsigned char **bin) +{ + unsigned char *sha, tmp[SHA_DIGEST_LENGTH]; + + if(mosquitto__hex2bin(hex, tmp, SHA_DIGEST_LENGTH) != SHA_DIGEST_LENGTH){ + return MOSQ_ERR_INVAL; + } + + sha = mosquitto__malloc(SHA_DIGEST_LENGTH); + memcpy(sha, tmp, SHA_DIGEST_LENGTH); + *bin = sha; + return MOSQ_ERR_SUCCESS; +} + +int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len) +{ + BIGNUM *bn = NULL; + int len; + int leading_zero = 0; + int start = 0; + size_t i = 0; + + /* Count the number of leading zero */ + for(i=0; i<strlen(hex); i=i+2) { + if(strncmp(hex + i, "00", 2) == 0) { + leading_zero++; + /* output leading zero to bin */ + bin[start++] = 0; + }else{ + break; + } + } + + if(BN_hex2bn(&bn, hex) == 0){ + if(bn) BN_free(bn); + return 0; + } + if(BN_num_bytes(bn) + leading_zero > bin_max_len){ + BN_free(bn); + return 0; + } + + len = BN_bn2bin(bn, bin + leading_zero); + BN_free(bn); + return len + leading_zero; +} +#endif + +FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read) +{ +#ifdef WIN32 + char buf[4096]; + int rc; + rc = ExpandEnvironmentStrings(path, buf, 4096); + if(rc == 0 || rc > 4096){ + return NULL; + }else{ + if (restrict_read) { + HANDLE hfile; + SECURITY_ATTRIBUTES sec; + EXPLICIT_ACCESS ea; + PACL pacl = NULL; + char username[UNLEN + 1]; + int ulen = UNLEN; + SECURITY_DESCRIPTOR sd; + DWORD dwCreationDisposition; + + switch(mode[0]){ + case 'a': + dwCreationDisposition = OPEN_ALWAYS; + break; + case 'r': + dwCreationDisposition = OPEN_EXISTING; + break; + case 'w': + dwCreationDisposition = CREATE_ALWAYS; + break; + default: + return NULL; + } + + GetUserName(username, &ulen); + if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) { + return NULL; + } + BuildExplicitAccessWithName(&ea, username, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE); + if (SetEntriesInAcl(1, &ea, NULL, &pacl) != ERROR_SUCCESS) { + return NULL; + } + if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) { + LocalFree(pacl); + return NULL; + } + + sec.nLength = sizeof(SECURITY_ATTRIBUTES); + sec.bInheritHandle = FALSE; + sec.lpSecurityDescriptor = &sd; + + hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0, + &sec, + dwCreationDisposition, + FILE_ATTRIBUTE_NORMAL, + NULL); + + LocalFree(pacl); + + int fd = _open_osfhandle((intptr_t)hfile, 0); + if (fd < 0) { + return NULL; + } + + FILE *fptr = _fdopen(fd, mode); + if (!fptr) { + _close(fd); + return NULL; + } + return fptr; + + }else { + return fopen(buf, mode); + } + } +#else + if (restrict_read) { + FILE *fptr; + mode_t old_mask; + + old_mask = umask(0077); + fptr = fopen(path, mode); + umask(old_mask); + + return fptr; + }else{ + return fopen(path, mode); + } +#endif +} + +void util__increment_receive_quota(struct mosquitto *mosq) +{ + if(mosq->msgs_in.inflight_quota < mosq->msgs_in.inflight_maximum){ + mosq->msgs_in.inflight_quota++; + } +} + +void util__increment_send_quota(struct mosquitto *mosq) +{ + if(mosq->msgs_out.inflight_quota < mosq->msgs_out.inflight_maximum){ + mosq->msgs_out.inflight_quota++; + } +} + + +void util__decrement_receive_quota(struct mosquitto *mosq) +{ + if(mosq->msgs_in.inflight_quota > 0){ + mosq->msgs_in.inflight_quota--; + } +} + +void util__decrement_send_quota(struct mosquitto *mosq) +{ + if(mosq->msgs_out.inflight_quota > 0){ + mosq->msgs_out.inflight_quota--; + } +} + + +int util__random_bytes(void *bytes, int count) +{ + int rc = MOSQ_ERR_UNKNOWN; + +#ifdef WITH_TLS + if(RAND_bytes(bytes, count) == 1){ + rc = MOSQ_ERR_SUCCESS; + } +#elif defined(HAVE_GETRANDOM) + if(getrandom(bytes, count, 0) == count){ + rc = MOSQ_ERR_SUCCESS; + } +#elif defined(WIN32) + HCRYPTPROV provider; + + if(!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){ + return MOSQ_ERR_UNKNOWN; + } + + if(CryptGenRandom(provider, count, bytes)){ + rc = MOSQ_ERR_SUCCESS; + } + + CryptReleaseContext(provider, 0); +#else + int i; + + for(i=0; i<count; i++){ + ((uint8_t *)bytes)[i] = (uint8_t )(random()&0xFF); + } + rc = MOSQ_ERR_SUCCESS; +#endif + return rc; +} |