123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- /*
- Copyright (c) 2010-2020 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 2.0
- and Eclipse Distribution License v1.0 which accompany this distribution.
- The Eclipse Public License is available at
- https://www.eclipse.org/legal/epl-2.0/
- and the Eclipse Distribution License is available at
- http://www.eclipse.org/org/documents/edl-v10.php.
- SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
- Contributors:
- Roger Light - initial implementation and documentation.
- */
- #include "config.h"
- #ifndef WIN32
- # include <strings.h>
- #endif
- #include <string.h>
- #ifdef WITH_TLS
- # ifdef WIN32
- # include <winsock2.h>
- # endif
- # include <openssl/engine.h>
- #endif
- #include "mosquitto.h"
- #include "mosquitto_internal.h"
- #include "memory_mosq.h"
- #include "misc_mosq.h"
- #include "mqtt_protocol.h"
- #include "util_mosq.h"
- #include "will_mosq.h"
- int mosquitto_will_set(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain)
- {
- return mosquitto_will_set_v5(mosq, topic, payloadlen, payload, qos, retain, NULL);
- }
- int mosquitto_will_set_v5(struct mosquitto *mosq, const char *topic, int payloadlen, const void *payload, int qos, bool retain, mosquitto_property *properties)
- {
- int rc;
- if(!mosq) return MOSQ_ERR_INVAL;
- if(properties){
- rc = mosquitto_property_check_all(CMD_WILL, properties);
- if(rc) return rc;
- }
- return will__set(mosq, topic, payloadlen, payload, qos, retain, properties);
- }
- int mosquitto_will_clear(struct mosquitto *mosq)
- {
- if(!mosq) return MOSQ_ERR_INVAL;
- return will__clear(mosq);
- }
- int mosquitto_username_pw_set(struct mosquitto *mosq, const char *username, const char *password)
- {
- size_t slen;
- if(!mosq) return MOSQ_ERR_INVAL;
- if(mosq->protocol == mosq_p_mqtt311 || mosq->protocol == mosq_p_mqtt31){
- if(password != NULL && username == NULL){
- return MOSQ_ERR_INVAL;
- }
- }
- mosquitto__free(mosq->username);
- mosq->username = NULL;
- mosquitto__free(mosq->password);
- mosq->password = NULL;
- if(username){
- slen = strlen(username);
- if(slen > UINT16_MAX){
- return MOSQ_ERR_INVAL;
- }
- if(mosquitto_validate_utf8(username, (int)slen)){
- return MOSQ_ERR_MALFORMED_UTF8;
- }
- mosq->username = mosquitto__strdup(username);
- if(!mosq->username) return MOSQ_ERR_NOMEM;
- }
- if(password){
- mosq->password = mosquitto__strdup(password);
- if(!mosq->password){
- mosquitto__free(mosq->username);
- mosq->username = NULL;
- return MOSQ_ERR_NOMEM;
- }
- }
- return MOSQ_ERR_SUCCESS;
- }
- int mosquitto_reconnect_delay_set(struct mosquitto *mosq, unsigned int reconnect_delay, unsigned int reconnect_delay_max, bool reconnect_exponential_backoff)
- {
- if(!mosq) return MOSQ_ERR_INVAL;
- if(reconnect_delay == 0) reconnect_delay = 1;
- mosq->reconnect_delay = reconnect_delay;
- mosq->reconnect_delay_max = reconnect_delay_max;
- mosq->reconnect_exponential_backoff = reconnect_exponential_backoff;
- return MOSQ_ERR_SUCCESS;
- }
- int mosquitto_tls_set(struct mosquitto *mosq, const char *cafile, const char *capath, const char *certfile, const char *keyfile, int (*pw_callback)(char *buf, int size, int rwflag, void *userdata))
- {
- #ifdef WITH_TLS
- FILE *fptr;
- if(!mosq || (!cafile && !capath) || (certfile && !keyfile) || (!certfile && keyfile)) return MOSQ_ERR_INVAL;
- mosquitto__free(mosq->tls_cafile);
- mosq->tls_cafile = NULL;
- if(cafile){
- fptr = mosquitto__fopen(cafile, "rt", false);
- if(fptr){
- fclose(fptr);
- }else{
- return MOSQ_ERR_INVAL;
- }
- mosq->tls_cafile = mosquitto__strdup(cafile);
- if(!mosq->tls_cafile){
- return MOSQ_ERR_NOMEM;
- }
- }
- mosquitto__free(mosq->tls_capath);
- mosq->tls_capath = NULL;
- if(capath){
- mosq->tls_capath = mosquitto__strdup(capath);
- if(!mosq->tls_capath){
- return MOSQ_ERR_NOMEM;
- }
- }
- mosquitto__free(mosq->tls_certfile);
- mosq->tls_certfile = NULL;
- if(certfile){
- fptr = mosquitto__fopen(certfile, "rt", false);
- if(fptr){
- fclose(fptr);
- }else{
- mosquitto__free(mosq->tls_cafile);
- mosq->tls_cafile = NULL;
- mosquitto__free(mosq->tls_capath);
- mosq->tls_capath = NULL;
- return MOSQ_ERR_INVAL;
- }
- mosq->tls_certfile = mosquitto__strdup(certfile);
- if(!mosq->tls_certfile){
- return MOSQ_ERR_NOMEM;
- }
- }
- mosquitto__free(mosq->tls_keyfile);
- mosq->tls_keyfile = NULL;
- if(keyfile){
- fptr = mosquitto__fopen(keyfile, "rt", false);
- if(fptr){
- fclose(fptr);
- }else{
- mosquitto__free(mosq->tls_cafile);
- mosq->tls_cafile = NULL;
- mosquitto__free(mosq->tls_capath);
- mosq->tls_capath = NULL;
- mosquitto__free(mosq->tls_certfile);
- mosq->tls_certfile = NULL;
- return MOSQ_ERR_INVAL;
- }
- mosq->tls_keyfile = mosquitto__strdup(keyfile);
- if(!mosq->tls_keyfile){
- return MOSQ_ERR_NOMEM;
- }
- }
- mosq->tls_pw_callback = pw_callback;
- return MOSQ_ERR_SUCCESS;
- #else
- UNUSED(mosq);
- UNUSED(cafile);
- UNUSED(capath);
- UNUSED(certfile);
- UNUSED(keyfile);
- UNUSED(pw_callback);
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- }
- int mosquitto_tls_opts_set(struct mosquitto *mosq, int cert_reqs, const char *tls_version, const char *ciphers)
- {
- #ifdef WITH_TLS
- if(!mosq) return MOSQ_ERR_INVAL;
- mosq->tls_cert_reqs = cert_reqs;
- if(tls_version){
- if(!strcasecmp(tls_version, "tlsv1.3")
- || !strcasecmp(tls_version, "tlsv1.2")
- || !strcasecmp(tls_version, "tlsv1.1")){
- mosq->tls_version = mosquitto__strdup(tls_version);
- if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
- }else{
- return MOSQ_ERR_INVAL;
- }
- }else{
- mosq->tls_version = mosquitto__strdup("tlsv1.2");
- if(!mosq->tls_version) return MOSQ_ERR_NOMEM;
- }
- if(ciphers){
- mosq->tls_ciphers = mosquitto__strdup(ciphers);
- if(!mosq->tls_ciphers) return MOSQ_ERR_NOMEM;
- }else{
- mosq->tls_ciphers = NULL;
- }
- return MOSQ_ERR_SUCCESS;
- #else
- UNUSED(mosq);
- UNUSED(cert_reqs);
- UNUSED(tls_version);
- UNUSED(ciphers);
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- }
- int mosquitto_tls_insecure_set(struct mosquitto *mosq, bool value)
- {
- #ifdef WITH_TLS
- if(!mosq) return MOSQ_ERR_INVAL;
- mosq->tls_insecure = value;
- return MOSQ_ERR_SUCCESS;
- #else
- UNUSED(mosq);
- UNUSED(value);
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- }
- int mosquitto_string_option(struct mosquitto *mosq, enum mosq_opt_t option, const char *value)
- {
- #ifdef WITH_TLS
- ENGINE *eng;
- char *str;
- #endif
- if(!mosq) return MOSQ_ERR_INVAL;
- switch(option){
- case MOSQ_OPT_TLS_ENGINE:
- #if defined(WITH_TLS) && !defined(OPENSSL_NO_ENGINE)
- eng = ENGINE_by_id(value);
- if(!eng){
- return MOSQ_ERR_INVAL;
- }
- ENGINE_free(eng); /* release the structural reference from ENGINE_by_id() */
- mosq->tls_engine = mosquitto__strdup(value);
- if(!mosq->tls_engine){
- return MOSQ_ERR_NOMEM;
- }
- return MOSQ_ERR_SUCCESS;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- break;
- case MOSQ_OPT_TLS_KEYFORM:
- #ifdef WITH_TLS
- if(!value) return MOSQ_ERR_INVAL;
- if(!strcasecmp(value, "pem")){
- mosq->tls_keyform = mosq_k_pem;
- }else if (!strcasecmp(value, "engine")){
- mosq->tls_keyform = mosq_k_engine;
- }else{
- return MOSQ_ERR_INVAL;
- }
- return MOSQ_ERR_SUCCESS;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- break;
- case MOSQ_OPT_TLS_ENGINE_KPASS_SHA1:
- #ifdef WITH_TLS
- if(mosquitto__hex2bin_sha1(value, (unsigned char**)&str) != MOSQ_ERR_SUCCESS){
- return MOSQ_ERR_INVAL;
- }
- mosq->tls_engine_kpass_sha1 = str;
- return MOSQ_ERR_SUCCESS;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- break;
- case MOSQ_OPT_TLS_ALPN:
- #ifdef WITH_TLS
- mosq->tls_alpn = mosquitto__strdup(value);
- if(!mosq->tls_alpn){
- return MOSQ_ERR_NOMEM;
- }
- return MOSQ_ERR_SUCCESS;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- break;
- case MOSQ_OPT_BIND_ADDRESS:
- mosquitto__free(mosq->bind_address);
- if(value){
- mosq->bind_address = mosquitto__strdup(value);
- if(mosq->bind_address){
- return MOSQ_ERR_SUCCESS;
- }else{
- return MOSQ_ERR_NOMEM;
- }
- }else{
- return MOSQ_ERR_SUCCESS;
- }
- default:
- return MOSQ_ERR_INVAL;
- }
- }
- int mosquitto_tls_psk_set(struct mosquitto *mosq, const char *psk, const char *identity, const char *ciphers)
- {
- #ifdef FINAL_WITH_TLS_PSK
- if(!mosq || !psk || !identity) return MOSQ_ERR_INVAL;
- /* Check for hex only digits */
- if(strspn(psk, "0123456789abcdefABCDEF") < strlen(psk)){
- return MOSQ_ERR_INVAL;
- }
- mosq->tls_psk = mosquitto__strdup(psk);
- if(!mosq->tls_psk) return MOSQ_ERR_NOMEM;
- mosq->tls_psk_identity = mosquitto__strdup(identity);
- if(!mosq->tls_psk_identity){
- mosquitto__free(mosq->tls_psk);
- return MOSQ_ERR_NOMEM;
- }
- if(ciphers){
- mosq->tls_ciphers = mosquitto__strdup(ciphers);
- if(!mosq->tls_ciphers) return MOSQ_ERR_NOMEM;
- }else{
- mosq->tls_ciphers = NULL;
- }
- return MOSQ_ERR_SUCCESS;
- #else
- UNUSED(mosq);
- UNUSED(psk);
- UNUSED(identity);
- UNUSED(ciphers);
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- }
- int mosquitto_opts_set(struct mosquitto *mosq, enum mosq_opt_t option, void *value)
- {
- int ival;
- if(!mosq) return MOSQ_ERR_INVAL;
- switch(option){
- case MOSQ_OPT_PROTOCOL_VERSION:
- if(value == NULL){
- return MOSQ_ERR_INVAL;
- }
- ival = *((int *)value);
- return mosquitto_int_option(mosq, option, ival);
- case MOSQ_OPT_SSL_CTX:
- return mosquitto_void_option(mosq, option, value);
- default:
- return MOSQ_ERR_INVAL;
- }
- return MOSQ_ERR_SUCCESS;
- }
- int mosquitto_int_option(struct mosquitto *mosq, enum mosq_opt_t option, int value)
- {
- if(!mosq) return MOSQ_ERR_INVAL;
- switch(option){
- case MOSQ_OPT_PROTOCOL_VERSION:
- if(value == MQTT_PROTOCOL_V31){
- mosq->protocol = mosq_p_mqtt31;
- }else if(value == MQTT_PROTOCOL_V311){
- mosq->protocol = mosq_p_mqtt311;
- }else if(value == MQTT_PROTOCOL_V5){
- mosq->protocol = mosq_p_mqtt5;
- }else{
- return MOSQ_ERR_INVAL;
- }
- break;
- case MOSQ_OPT_RECEIVE_MAXIMUM:
- if(value < 0 || value > UINT16_MAX){
- return MOSQ_ERR_INVAL;
- }
- if(value == 0){
- mosq->msgs_in.inflight_maximum = UINT16_MAX;
- }else{
- mosq->msgs_in.inflight_maximum = (uint16_t)value;
- }
- break;
- case MOSQ_OPT_SEND_MAXIMUM:
- if(value < 0 || value > UINT16_MAX){
- return MOSQ_ERR_INVAL;
- }
- if(value == 0){
- mosq->msgs_out.inflight_maximum = UINT16_MAX;
- }else{
- mosq->msgs_out.inflight_maximum = (uint16_t)value;
- }
- break;
- case MOSQ_OPT_SSL_CTX_WITH_DEFAULTS:
- #if defined(WITH_TLS) && OPENSSL_VERSION_NUMBER >= 0x10100000L
- if(value){
- mosq->ssl_ctx_defaults = true;
- }else{
- mosq->ssl_ctx_defaults = false;
- }
- break;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- case MOSQ_OPT_TLS_USE_OS_CERTS:
- #ifdef WITH_TLS
- if(value){
- mosq->tls_use_os_certs = true;
- }else{
- mosq->tls_use_os_certs = false;
- }
- break;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- case MOSQ_OPT_TLS_OCSP_REQUIRED:
- #ifdef WITH_TLS
- mosq->tls_ocsp_required = (bool)value;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- break;
- case MOSQ_OPT_TCP_NODELAY:
- mosq->tcp_nodelay = (bool)value;
- break;
- default:
- return MOSQ_ERR_INVAL;
- }
- return MOSQ_ERR_SUCCESS;
- }
- int mosquitto_void_option(struct mosquitto *mosq, enum mosq_opt_t option, void *value)
- {
- if(!mosq) return MOSQ_ERR_INVAL;
- switch(option){
- case MOSQ_OPT_SSL_CTX:
- #ifdef WITH_TLS
- mosq->user_ssl_ctx = (SSL_CTX *)value;
- if(mosq->user_ssl_ctx){
- #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- SSL_CTX_up_ref(mosq->user_ssl_ctx);
- #else
- CRYPTO_add(&(mosq->user_ssl_ctx)->references, 1, CRYPTO_LOCK_SSL_CTX);
- #endif
- }
- break;
- #else
- return MOSQ_ERR_NOT_SUPPORTED;
- #endif
- default:
- return MOSQ_ERR_INVAL;
- }
- return MOSQ_ERR_SUCCESS;
- }
- void mosquitto_user_data_set(struct mosquitto *mosq, void *userdata)
- {
- if(mosq){
- mosq->userdata = userdata;
- }
- }
- void *mosquitto_userdata(struct mosquitto *mosq)
- {
- return mosq->userdata;
- }
|