diff options
author | Gealber Morales <mbasalo@nauta.cu> | 2021-06-04 09:25:38 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2021-06-12 23:50:13 +0200 |
commit | 791937b881177c07c6ab8f151723342b3b9167ce (patch) | |
tree | 91b5f5e2cdfbe5cb3f50f93f9801d5eff21458e8 /lib/mqtt.c | |
parent | 53c26dedf48802131fc3aa072c8982c3c4020046 (diff) | |
download | curl-791937b881177c07c6ab8f151723342b3b9167ce.tar.gz |
mqtt: add support for username and password
Minor-edits-by: Daniel Stenberg
Added test 2200 to 2205
Closes #7243
Diffstat (limited to 'lib/mqtt.c')
-rw-r--r-- | lib/mqtt.c | 210 |
1 files changed, 180 insertions, 30 deletions
diff --git a/lib/mqtt.c b/lib/mqtt.c index d49a5f1cc..9a3ca222f 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -143,32 +143,197 @@ static int mqtt_getsock(struct Curl_easy *data, return GETSOCK_READSOCK(FIRSTSOCKET); } +static int mqtt_encode_len(char *buf, size_t len) +{ + unsigned char encoded; + int i; + + for(i = 0; (len > 0) && (i<4); i++) { + encoded = len % 0x80; + len /= 0x80; + if(len) + encoded |= 0x80; + buf[i] = encoded; + } + + return i; +} + +/* add the passwd to the CONNECT packet */ +static int add_passwd(const char *passwd, const size_t plen, + char *pkt, const size_t start, int remain_pos) +{ + /* magic number that need to be set properly */ + const size_t conn_flags_pos = remain_pos + 8; + if(plen > 0xffff) + return 1; + + /* set password flag */ + pkt[conn_flags_pos] |= 0x40; + + /* length of password provided */ + pkt[start] = (char)((plen >> 8) & 0xFF); + pkt[start + 1] = (char)(plen & 0xFF); + memcpy(&pkt[start + 2], passwd, plen); + return 0; +} + +/* add user to the CONN packet */ +static int add_user(const char *username, const size_t ulen, + unsigned char *pkt, const size_t start, int remain_pos) +{ + /* magic number that need to be set properly */ + const size_t conn_flags_pos = remain_pos + 8; + if(ulen > 0xffff) + return 1; + + /* set username flag */ + pkt[conn_flags_pos] |= 0x80; + /* length of username provided */ + pkt[start] = (unsigned char)((ulen >> 8) & 0xFF); + pkt[start + 1] = (unsigned char)(ulen & 0xFF); + memcpy(&pkt[start + 2], username, ulen); + return 0; +} + +/* add client ID to the CONN packet */ +static int add_client_id(const char *client_id, const size_t client_id_len, + char *pkt, const size_t start) +{ + if(client_id_len != MQTT_CLIENTID_LEN) + return 1; + pkt[start] = 0x00; + pkt[start + 1] = MQTT_CLIENTID_LEN; + memcpy(&pkt[start + 2], client_id, MQTT_CLIENTID_LEN); + return 0; +} + +/* Set initial values of CONN packet */ +static int init_connpack(char *packet, char *remain, int remain_pos) +{ + /* Fixed header starts */ + /* packet type */ + packet[0] = MQTT_MSG_CONNECT; + /* remaining length field */ + memcpy(&packet[1], remain, remain_pos); + /* Fixed header ends */ + + /* Variable header starts */ + /* protocol length */ + packet[remain_pos + 1] = 0x00; + packet[remain_pos + 2] = 0x04; + /* protocol name */ + packet[remain_pos + 3] = 'M'; + packet[remain_pos + 4] = 'Q'; + packet[remain_pos + 5] = 'T'; + packet[remain_pos + 6] = 'T'; + /* protocol level */ + packet[remain_pos + 7] = 0x04; + /* CONNECT flag: CleanSession */ + packet[remain_pos + 8] = 0x02; + /* keep-alive 0 = disabled */ + packet[remain_pos + 9] = 0x00; + packet[remain_pos + 10] = 0x3c; + /*end of variable header*/ + return remain_pos + 10; +} + static CURLcode mqtt_connect(struct Curl_easy *data) { CURLcode result = CURLE_OK; - const size_t client_id_offset = 14; - const size_t packetlen = client_id_offset + MQTT_CLIENTID_LEN; + int pos = 0; + int rc = 0; + /*remain length*/ + int remain_pos = 0; + char remain[4] = {0}; + size_t packetlen = 0; + size_t payloadlen = 0; + size_t start_user = 0; + size_t start_pwd = 0; char client_id[MQTT_CLIENTID_LEN + 1] = "curl"; const size_t clen = strlen("curl"); - char packet[32] = { - MQTT_MSG_CONNECT, /* packet type */ - 0x00, /* remaining length */ - 0x00, 0x04, /* protocol length */ - 'M','Q','T','T', /* protocol name */ - 0x04, /* protocol level */ - 0x02, /* CONNECT flag: CleanSession */ - 0x00, 0x3c, /* keep-alive 0 = disabled */ - 0x00, 0x00 /* payload1 length */ - }; - packet[1] = (packetlen - 2) & 0x7f; - packet[client_id_offset - 1] = MQTT_CLIENTID_LEN; + char *packet = NULL; + + /* extracting username from request */ + const char *username = data->state.aptr.user ? + data->state.aptr.user : ""; + const size_t ulen = strlen(username); + /* extracting password from request */ + const char *passwd = data->state.aptr.passwd ? + data->state.aptr.passwd : ""; + const size_t plen = strlen(passwd); + + payloadlen = ulen + plen + MQTT_CLIENTID_LEN + 2; + /* The plus 2 are for the MSB and LSB describing the length of the string to + * be added on the payload. Refer to spec 1.5.2 and 1.5.4 */ + if(ulen) + payloadlen += 2; + if(plen) + payloadlen += 2; + + /* getting how much occupy the remain length */ + remain_pos = mqtt_encode_len(remain, payloadlen + 10); + + /* 10 length of variable header and 1 the first byte of the fixed header */ + packetlen = payloadlen + 10 + remain_pos + 1; + + /* allocating packet */ + if(packetlen > 268435455) + return CURLE_WEIRD_SERVER_REPLY; + packet = malloc(packetlen); + if(!packet) + return CURLE_OUT_OF_MEMORY; + memset(packet, 0, packetlen); + + /* set initial values for CONN pack */ + pos = init_connpack(packet, remain, remain_pos); result = Curl_rand_hex(data, (unsigned char *)&client_id[clen], MQTT_CLIENTID_LEN - clen + 1); - memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN); + /* add client id */ + rc = add_client_id(client_id, strlen(client_id), packet, pos + 1); + if(rc) { + failf(data, "Client ID length mismatched: [%lu]", strlen(client_id)); + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } infof(data, "Using client id '%s'\n", client_id); + + /* position where starts the user payload */ + start_user = pos + 3 + MQTT_CLIENTID_LEN; + /* position where starts the password payload */ + start_pwd = start_user + ulen; + /* if user name was provided, add it to the packet */ + if(ulen) { + start_pwd += 2; + + rc = add_user(username, ulen, + (unsigned char *)packet, start_user, remain_pos); + if(rc) { + failf(data, "Username is too large: [%lu]", ulen); + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + } + + /* if passwd was provided, add it to the packet */ + if(plen) { + rc = add_passwd(passwd, plen, packet, start_pwd, remain_pos); + if(rc) { + failf(data, "Password is too large: [%lu]", plen); + result = CURLE_WEIRD_SERVER_REPLY; + goto end; + } + } + if(!result) result = mqtt_send(data, packet, packetlen); + +end: + if(packet) + free(packet); + Curl_safefree(data->state.aptr.user); + Curl_safefree(data->state.aptr.passwd); return result; } @@ -228,21 +393,6 @@ static CURLcode mqtt_get_topic(struct Curl_easy *data, } -static int mqtt_encode_len(char *buf, size_t len) -{ - unsigned char encoded; - int i; - - for(i = 0; (len > 0) && (i<4); i++) { - encoded = len % 0x80; - len /= 0x80; - if(len) - encoded |= 0x80; - buf[i] = encoded; - } - - return i; -} static CURLcode mqtt_subscribe(struct Curl_easy *data) { |