From ccdb748c81abc9bb30b8989e27d22bbbb219f9a0 Mon Sep 17 00:00:00 2001 From: defanor Date: Fri, 29 Sep 2023 20:24:16 +0300 Subject: Add more checks, tests, and documentation --- README | 3 +- src/Makefile.am | 4 +-- src/rexmpp.c | 35 ++++++++++++---------- src/rexmpp.h | 2 -- src/rexmpp_base64.h | 25 ++++++++++++++-- src/rexmpp_console.c | 17 ++++++----- src/rexmpp_digest.c | 1 - src/rexmpp_digest.h | 41 +++++++++++++++++++++++++ src/rexmpp_dns.c | 73 +++++++++++++++++++++++++++++++++++++++++---- src/rexmpp_http_upload.c | 28 +++++++++++++---- src/rexmpp_jid.c | 6 ++-- src/rexmpp_jingle.c | 22 +++++++------- src/rexmpp_openpgp.c | 5 ++++ src/rexmpp_random.c | 9 ++++++ src/rexmpp_random.h | 7 +++++ src/rexmpp_tls.c | 24 ++++++++++++--- src/rexmpp_xml.c | 8 +++-- src/rexmpp_xml.h | 5 ++-- src/rexmpp_xml_parser.c | 16 +++++----- tests/Makefile.am | 25 +++++++++------- tests/base64.c | 18 +++++++++++ tests/send_to_self.c | 8 ++--- tests/xml_parse_and_print.c | 27 +++++++++++++++++ tests/xml_print_and_parse.c | 64 +++++++++++++++++++++++++++++++++++++++ 24 files changed, 385 insertions(+), 88 deletions(-) create mode 100644 tests/base64.c create mode 100644 tests/xml_parse_and_print.c create mode 100644 tests/xml_print_and_parse.c diff --git a/README b/README index eb28c13..abeeef0 100644 --- a/README +++ b/README @@ -98,8 +98,7 @@ A rough roadmap: [+] XEP-0176 v1.1: Jingle ICE-UDP Transport Method (uses libnice, discovers TURN/STUN servers with XEP-0215: External Service Discovery) -[+] XEP-0320 v1.0: Use of DTLS-SRTP in Jingle Sessions (uses gnutls - and libsrtp2) +[+] XEP-0320 v1.0: Use of DTLS-SRTP in Jingle Sessions [ ] XEP-0260: Jingle SOCKS5 Bytestreams Transport Method? [ ] XEP-0391: Jingle Encrypted Transports? [ ] XEP-0184: Message Delivery Receipts? diff --git a/src/Makefile.am b/src/Makefile.am index d027b1b..2dfc581 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -29,12 +29,12 @@ librexmpp_la_CFLAGS = $(AM_CFLAGS) $(LIBXML2_CFLAGS) $(EXPAT_CFLAGS) \ $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \ $(ICU_I18N_CFLAGS) $(LIBGCRYPT_CFLAGS) $(CURL_CFLAGS) \ $(NICE_CFLAGS) $(GLIB_CFLAGS) $(SRTP_CFLAGS) \ - $(PORTAUDIO_CFLAGS) $(OPUS_CFLAGS) + $(PORTAUDIO_CFLAGS) $(OPUS_CFLAGS) $(NETTLE_CFLAGS) librexmpp_la_LIBADD = $(LIBXML2_LIBS) $(EXPAT_LIBS) \ $(GNUTLS_LIBS) $(LIBDANE_LIBS) $(OPENSSL_LIBS) \ $(GSASL_LIBS) $(UNBOUND_LIBS) $(CARES_LIBS) $(GPGME_LIBS) $(ICU_I18N_LIBS) \ $(LIBGCRYPT_LIBS) $(CURL_LIBS) $(NICE_LIBS) $(GLIB_LIBS) $(SRTP_LIBS) \ - $(PORTAUDIO_LIBS) $(OPUS_LIBS) + $(PORTAUDIO_LIBS) $(OPUS_LIBS) $(NETTLE_LIBS) librexmpp_la_LDFLAGS = [] if USE_RUST diff --git a/src/rexmpp.c b/src/rexmpp.c index e19386d..e9d20c0 100644 --- a/src/rexmpp.c +++ b/src/rexmpp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "config.h" @@ -401,6 +402,9 @@ rexmpp_disco_find_feature (rexmpp_t *s, { struct rexmpp_feature_search *search = malloc(sizeof(struct rexmpp_feature_search)); + if (search == NULL) { + return REXMPP_E_MALLOC; + } search->max_requests = max_requests - 1; search->found = 0; search->pending = 1; @@ -700,6 +704,7 @@ void rexmpp_cleanup (rexmpp_t *s) { if (s->tcp_state == REXMPP_TCP_CONNECTING) { int sock = rexmpp_tcp_conn_finish(&s->server_connection); if (sock != -1) { + rexmpp_log(s, LOG_DEBUG, "TCP disconnected"); close(sock); } s->tcp_state = REXMPP_TCP_NONE; @@ -855,15 +860,6 @@ const char *jid_bare_to_host (const char *jid_bare) { return NULL; } -char *rexmpp_gen_id (rexmpp_t *s) { - (void)s; - char buf_raw[18], *buf_base64 = NULL; - size_t buf_base64_len = 0; - rexmpp_random_buf(buf_raw, 18); - rexmpp_base64_to(buf_raw, 18, &buf_base64, &buf_base64_len); - return buf_base64; -} - rexmpp_xml_t *rexmpp_xml_set_delay (rexmpp_t *s, rexmpp_xml_t *node) { if (rexmpp_xml_find_child (node, NULL, "delay")) { return node; @@ -1095,6 +1091,8 @@ rexmpp_err_t rexmpp_iq_new (rexmpp_t *s, last = last->next; } if (i >= s->iq_queue_size && s->iq_queue_size > 0) { + assert(prev != NULL); + assert(last != NULL); rexmpp_log(s, LOG_WARNING, "The IQ queue limit is reached, giving up on the oldest IQ."); prev->next = NULL; @@ -1103,7 +1101,7 @@ rexmpp_err_t rexmpp_iq_new (rexmpp_t *s, rexmpp_xml_t *iq_stanza = rexmpp_xml_new_elem("iq", "jabber:client"); - rexmpp_xml_add_id(s, iq_stanza); + rexmpp_xml_add_id(iq_stanza); rexmpp_xml_add_attr(iq_stanza, "type", type); if (to != NULL) { rexmpp_xml_add_attr(iq_stanza, "to", to); @@ -1113,6 +1111,9 @@ rexmpp_err_t rexmpp_iq_new (rexmpp_t *s, } rexmpp_xml_add_child(iq_stanza, payload); rexmpp_iq_t *iq = malloc(sizeof(rexmpp_iq_t)); + if (iq == NULL) { + return REXMPP_E_MALLOC; + } iq->request = rexmpp_xml_clone(iq_stanza); iq->cb = cb; iq->cb_data = cb_data; @@ -1263,9 +1264,9 @@ rexmpp_err_t rexmpp_recv (rexmpp_t *s) { } else if (chunk_raw_len == 0) { if (tls_was_active) { s->tls_state = REXMPP_TLS_CLOSED; - rexmpp_log(s, LOG_INFO, "TLS disconnected"); + rexmpp_log(s, LOG_DEBUG, "TLS disconnected"); } - rexmpp_log(s, LOG_INFO, "TCP disconnected"); + rexmpp_log(s, LOG_DEBUG, "TCP disconnected"); rexmpp_cleanup(s); if (s->stream_state == REXMPP_STREAM_READY || s->stream_state == REXMPP_STREAM_ERROR_RECONNECT) { @@ -1619,7 +1620,7 @@ void rexmpp_stream_is_ready(rexmpp_t *s) { } rexmpp_xml_t *presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); char *caps_hash = rexmpp_capabilities_hash(s, rexmpp_disco_info(s)); if (caps_hash != NULL) { @@ -2042,7 +2043,7 @@ rexmpp_err_t rexmpp_process_element (rexmpp_t *s, rexmpp_xml_t *elem) { strcmp(autojoin, "1") == 0) { rexmpp_xml_t *presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); rexmpp_xml_add_attr(presence, "from", s->assigned_jid.full); rexmpp_xml_t *nick = @@ -2253,6 +2254,7 @@ void rexmpp_sax_start_elem_ns (rexmpp_t *s, strcmp(namespace, "http://etherx.jabber.org/streams") == 0) { rexmpp_log(s, LOG_DEBUG, "stream start"); s->stream_state = REXMPP_STREAM_NEGOTIATION; + rexmpp_xml_attribute_free_list(attributes); return; } @@ -2326,7 +2328,7 @@ rexmpp_err_t rexmpp_stop (rexmpp_t *s) { if (s->stream_state == REXMPP_STREAM_READY) { rexmpp_xml_t *presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); rexmpp_xml_add_attr(presence, "type", "unavailable"); rexmpp_send(s, presence); } @@ -2549,10 +2551,11 @@ rexmpp_err_t rexmpp_run (rexmpp_t *s, fd_set *read_fds, fd_set *write_fds) { s->tls_state == REXMPP_TLS_CLOSING) { rexmpp_tls_err_t err = rexmpp_tls_disconnect(s, s->tls); if (err == REXMPP_TLS_SUCCESS) { + rexmpp_log(s, LOG_DEBUG, "TLS disconnected"); s->tls_state = REXMPP_TLS_INACTIVE; rexmpp_cleanup(s); s->tcp_state = REXMPP_TCP_CLOSED; - } else { + } else if (err != REXMPP_TLS_E_AGAIN) { s->tls_state = REXMPP_TLS_ERROR; return REXMPP_E_TLS; } diff --git a/src/rexmpp.h b/src/rexmpp.h index 8cc78ed..e9d833f 100644 --- a/src/rexmpp.h +++ b/src/rexmpp.h @@ -534,8 +534,6 @@ void rexmpp_log (rexmpp_t *s, int priority, const char *format, ...); */ char *rexmpp_get_name (rexmpp_t *s, const char *jid_str); -char *rexmpp_gen_id (rexmpp_t *s); - /** @brief Finds a PEP event. @param[in] s ::rexmpp diff --git a/src/rexmpp_base64.h b/src/rexmpp_base64.h index e681ed9..d11cd91 100644 --- a/src/rexmpp_base64.h +++ b/src/rexmpp_base64.h @@ -10,5 +10,26 @@ #include -int rexmpp_base64_to (const char *in, size_t in_len, char **out, size_t *out_len); -int rexmpp_base64_from (const char *in, size_t in_len, char **out, size_t *out_len); +/** + @brief Encodes data in Base64 + @param[in] in Data to encode + @param[in] in_len Length of the input data + @param[out] out A pointer to the output buffer; its memory will be + allocated by the function, the caller receives ownership over it + @param[out] out_len Length of the produced Base64-encoded string + @returns 0 on success, a non-zero value otherwise +*/ +int rexmpp_base64_to (const char *in, size_t in_len, + char **out, size_t *out_len); + +/** + @brief Decodes data from Base64 + @param[in] in Data to decode + @param[in] in_len Length of the input data + @param[out] out A pointer to the output buffer; its memory will be + allocated by the function, the caller receives ownership over it + @param[out] out_len Length of the decoded string + @returns 0 on success, a non-zero value otherwise +*/ +int rexmpp_base64_from (const char *in, size_t in_len, + char **out, size_t *out_len); diff --git a/src/rexmpp_console.c b/src/rexmpp_console.c index 2d2347f..64e5493 100644 --- a/src/rexmpp_console.c +++ b/src/rexmpp_console.c @@ -12,6 +12,7 @@ #include #include +#include #include "rexmpp.h" #include "rexmpp_xml.h" @@ -490,7 +491,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { msg_text = jid_str + strlen(jid_str) + 1; rexmpp_xml_t *msg = rexmpp_xml_new_elem("message", "jabber:client"); - rexmpp_xml_add_id(s, msg); + rexmpp_xml_add_id(msg); rexmpp_xml_add_attr(msg, "to", jid.full); rexmpp_xml_add_attr(msg, "type", "chat"); rexmpp_xml_t *body = rexmpp_xml_new_elem("body", NULL); @@ -527,7 +528,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { free(b64); rexmpp_xml_t *msg = rexmpp_xml_new_elem("message", "jabber:client"); - rexmpp_xml_add_id(s, msg); + rexmpp_xml_add_id(msg); rexmpp_xml_add_attr(msg, "to", jid.full); rexmpp_xml_add_attr(msg, "type", "chat"); rexmpp_xml_add_child(msg, openpgp); @@ -549,7 +550,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { msg_text = jid_str + strlen(jid_str) + 1; rexmpp_xml_t *msg = rexmpp_xml_new_elem("message", "jabber:client"); - rexmpp_xml_add_id(s, msg); + rexmpp_xml_add_id(msg); rexmpp_xml_add_attr(msg, "to", jid.full); rexmpp_xml_add_attr(msg, "type", "groupchat"); rexmpp_xml_t *body = rexmpp_xml_new_elem("body", NULL); @@ -573,7 +574,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { snprintf(full_jid, strlen(jid_str) + strlen(word) + 2, "%s/%s", jid.bare, word); presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); rexmpp_xml_add_attr(presence, "from", s->assigned_jid.full); rexmpp_xml_add_attr(presence, "to", full_jid); rexmpp_xml_t *x = @@ -598,7 +599,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { snprintf(full_jid, strlen(jid_str) + strlen(word) + 2, "%s/%s", jid.bare, word); presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); rexmpp_xml_add_attr(presence, "from", s->assigned_jid.full); rexmpp_xml_add_attr(presence, "to", full_jid); rexmpp_xml_add_attr(presence, "type", "unavailable"); @@ -683,7 +684,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { return; } presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); rexmpp_xml_add_attr(presence, "to", word); rexmpp_xml_add_attr(presence, "type", "subscribe"); rexmpp_send(s, presence); @@ -694,7 +695,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { return; } presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); rexmpp_xml_add_attr(presence, "to", word); rexmpp_xml_add_attr(presence, "type", "subscribed"); rexmpp_send(s, presence); @@ -705,7 +706,7 @@ void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) { return; } presence = rexmpp_xml_new_elem("presence", "jabber:client"); - rexmpp_xml_add_id(s, presence); + rexmpp_xml_add_id(presence); rexmpp_xml_add_attr(presence, "to", word); rexmpp_xml_add_attr(presence, "type", "unsubscribed"); rexmpp_send(s, presence); diff --git a/src/rexmpp_digest.c b/src/rexmpp_digest.c index e123636..c1dd436 100644 --- a/src/rexmpp_digest.c +++ b/src/rexmpp_digest.c @@ -87,7 +87,6 @@ int rexmpp_digest_init (rexmpp_digest_t *ctx, rexmpp_digest_algorithm algo) { int rexmpp_digest_update (rexmpp_digest_t *ctx, const void *in, size_t len) { #if defined(HAVE_GCRYPT) - printf("wirte: %s %lu\n", (const char*)in, len); gcry_md_write(*ctx, in, len); #elif defined(HAVE_NETTLE) ctx->nh->update(ctx->nh_ctx, len, in); diff --git a/src/rexmpp_digest.h b/src/rexmpp_digest.h index 77f198a..5001e12 100644 --- a/src/rexmpp_digest.h +++ b/src/rexmpp_digest.h @@ -31,14 +31,55 @@ typedef struct rexmpp_digest rexmpp_digest_t; typedef EVP_MD_CTX* rexmpp_digest_t; #endif +/** + @brief Finds the digest length for a given algorithm. + @param[in] algo An algorithm. + @returns Digest length in bytes. +*/ size_t rexmpp_digest_len (rexmpp_digest_algorithm algo); + +/** + @brief Computes a digest for a buffer. + @param[in] algo An algorithm. + @param[in] in Input data. + @param[in] in_len Input data length. + @param[out] out Output buffer. + @param[in] out_len Output buffer length. + @returns 0 on success, non-zero on failure. +*/ int rexmpp_digest_buffer (rexmpp_digest_algorithm algo, const void *in, size_t in_len, void *out, size_t out_len); + +/** + @brief Initializes a digest context. + @param[out] ctx Pointer to an allocated ::rexmpp_digest_t context + to initialize. + @param[in] algo An algorithm to use. + @returns 0 on success, non-zero on failure. +*/ int rexmpp_digest_init (rexmpp_digest_t *ctx, rexmpp_digest_algorithm algo); + +/** + @brief Updates a digest computation. + @param[in,out] ctx Context pointer. + @param[in] in Input data. + @param[in] len Length of the input buffer. + @returns 0 on success, non-zero on failure. +*/ int rexmpp_digest_update (rexmpp_digest_t *ctx, const void *in, size_t len); + +/** + @brief Finishes a digest computation, freeing the context and + providing the output. + @param[in,out] ctx Context pointer. + @param[out] out A place to write the computed digest into, can be + NULL to just free the context. + @param[in] len Length of the allocated output buffer. + @returns 0 on success, non-zero on failure. +*/ int rexmpp_digest_finish (rexmpp_digest_t *ctx, void *out, size_t len); #endif diff --git a/src/rexmpp_dns.c b/src/rexmpp_dns.c index d13472e..d56aa10 100644 --- a/src/rexmpp_dns.c +++ b/src/rexmpp_dns.c @@ -85,17 +85,33 @@ void rexmpp_dns_result_free (rexmpp_dns_result_t *result) { rexmpp_dns_result_t *result_from_hostent (struct hostent *hostinfo) { rexmpp_dns_result_t *r = malloc(sizeof(rexmpp_dns_result_t)); + if (r == NULL) { + return NULL; + } r->secure = 0; int i, size = 0; while (hostinfo->h_addr_list[size] != NULL) { size++; } r->data = malloc(sizeof(void *) * (size + 1)); + if (r->data == NULL) { + free(r); + return NULL; + } r->len = malloc(sizeof(int) * size); + if (r->len == NULL) { + free(r->data); + free(r); + return NULL; + } for (i = 0; i < size; i++) { r->len[i] = hostinfo->h_length; r->data[i] = malloc(r->len[i]); - memcpy(r->data[i], hostinfo->h_addr_list[i], hostinfo->h_length); + if (r->data[i] != NULL) { + memcpy(r->data[i], hostinfo->h_addr_list[i], hostinfo->h_length); + } else { + return r; + } } r->data[size] = NULL; return r; @@ -257,20 +273,54 @@ void rexmpp_dns_cb (void *ptr, size++; } rexmpp_dns_result_t *res = malloc(sizeof(rexmpp_dns_result_t)); - res->data = malloc(sizeof(void *) * (size + 1)); + if (res == NULL) { + rexmpp_log(s, LOG_DEBUG, + "Failed to allocate memory for a DNS resolution result"); + ub_resolve_free(result); + d->cb(s, d->ptr, NULL); + free(d); + return; + } + res->data = calloc((size + 1), sizeof(void *)); + if (res->data == NULL) { + rexmpp_log(s, LOG_DEBUG, + "Failed to allocate memory for a DNS resolution result's data"); + free(res); + ub_resolve_free(result); + d->cb(s, d->ptr, NULL); + free(d); + return; + } res->len = malloc(sizeof(int) * size); + if (res->len == NULL) { + rexmpp_log(s, LOG_DEBUG, + "Failed to allocate memory for a DNS resolution result's len"); + free(res->data); + free(res); + ub_resolve_free(result); + d->cb(s, d->ptr, NULL); + free(d); + return; + } for (i = 0; i < size; i++) { if (result->qtype == 33) { /* SRV */ res->len[i] = sizeof(rexmpp_dns_srv_t); res->data[i] = malloc(res->len[i]); + if (res->data[i] == NULL) { + rexmpp_log(s, LOG_ERR, + "Failed to allocate memory for an SRV record"); + d->cb(s, d->ptr, res); + rexmpp_dns_result_free(res); + free(d); + return; + } int err = rexmpp_parse_srv(result->data[i], result->len[i], (rexmpp_dns_srv_t*)res->data[i]); if (err) { rexmpp_log(s, LOG_WARNING, "Failed to parse an SRV record"); - res->data[i + 1] = NULL; + d->cb(s, d->ptr, res); rexmpp_dns_result_free(res); - d->cb(s, d->ptr, NULL); free(d); return; } @@ -278,7 +328,12 @@ void rexmpp_dns_cb (void *ptr, /* Non-SRV, for now that's just A or AAAA */ res->len[i] = result->len[i]; res->data[i] = malloc(res->len[i]); - memcpy(res->data[i], result->data[i], res->len[i]); + if (res->data[i] == NULL) { + rexmpp_log(s, LOG_WARNING, + "Failed to allocate memory for a DNS result's data record"); + } else { + memcpy(res->data[i], result->data[i], res->len[i]); + } } } res->data[size] = NULL; @@ -352,6 +407,10 @@ int rexmpp_dns_resolve (rexmpp_t *s, #if defined(USE_UNBOUND) struct rexmpp_dns_query_cb_data *d = malloc(sizeof(struct rexmpp_dns_query_cb_data)); + if (d == NULL) { + rexmpp_log(s, LOG_ERR, "Failed to allocate memory for a DNS query"); + return 1; + } d->s = s; d->cb = callback; d->ptr = ptr; @@ -365,6 +424,10 @@ int rexmpp_dns_resolve (rexmpp_t *s, #elif defined(USE_CARES) struct rexmpp_dns_query_cb_data *d = malloc(sizeof(struct rexmpp_dns_query_cb_data)); + if (d == NULL) { + rexmpp_log(s, LOG_ERR, "Failed to allocate memory for a DNS query"); + return 1; + } d->s = s; d->cb = callback; d->ptr = ptr; diff --git a/src/rexmpp_http_upload.c b/src/rexmpp_http_upload.c index 4d8c631..5d13f97 100644 --- a/src/rexmpp_http_upload.c +++ b/src/rexmpp_http_upload.c @@ -73,13 +73,19 @@ void rexmpp_http_upload_slot_cb (rexmpp_t *s, if (header_name != NULL) { const char *header_str = rexmpp_xml_text_child(header); if (header_str != NULL) { - size_t full_header_str_len = strlen(header_name) + 3 + strlen(header_str); + size_t full_header_str_len = + strlen(header_name) + 3 + strlen(header_str); char *full_header_str = malloc(full_header_str_len); - snprintf(full_header_str, full_header_str_len, "%s: %s", - header_name, header_str); - task->http_headers = - curl_slist_append(task->http_headers, full_header_str); - free(full_header_str); + if (full_header_str != NULL) { + snprintf(full_header_str, full_header_str_len, "%s: %s", + header_name, header_str); + task->http_headers = + curl_slist_append(task->http_headers, full_header_str); + free(full_header_str); + } else { + rexmpp_log(s, LOG_ERR, + "Failed to allocate memory for a header"); + } } } header = rexmpp_xml_next_elem_sibling(header); @@ -137,8 +143,18 @@ rexmpp_http_upload (rexmpp_t *s, http_upload_cb cb, void *cb_data) { + if (fname == NULL) { + rexmpp_log(s, LOG_ERR, "No file name is provided"); + fclose(fh); + return REXMPP_E_PARAM; + } struct rexmpp_http_upload_task *task = malloc(sizeof(struct rexmpp_http_upload_task)); + if (task == NULL) { + rexmpp_log(s, LOG_ERR, "Failed to allocate memory for an upload task"); + fclose(fh); + return REXMPP_E_MALLOC; + } task->fname = strdup(fname); task->fsize = fsize; task->fh = fh; diff --git a/src/rexmpp_jid.c b/src/rexmpp_jid.c index 522a492..f1c371c 100644 --- a/src/rexmpp_jid.c +++ b/src/rexmpp_jid.c @@ -64,8 +64,10 @@ int rexmpp_jid_parse (const char *str, struct rexmpp_jid *jid) { jid->local[local_len] = '\0'; strncpy(jid->domain, domain, domain_len); jid->domain[domain_len] = '\0'; - strncpy(jid->resource, resource, resource_len); - jid->resource[resource_len] = '\0'; + if (resource != NULL) { + strncpy(jid->resource, resource, resource_len); + jid->resource[resource_len] = '\0'; + } return 0; } diff --git a/src/rexmpp_jingle.c b/src/rexmpp_jingle.c index a147a5f..9e16d59 100644 --- a/src/rexmpp_jingle.c +++ b/src/rexmpp_jingle.c @@ -480,7 +480,7 @@ rexmpp_jingle_session_create (rexmpp_t *s, #endif /* HAVE_POUS */ #endif /* ENABLE_CALLS */ if (! rexmpp_jingle_session_add(s, sess)) { - rexmpp_jingle_session_destroy(sess); + /* The session is destroyed by rexmpp_jingle_session_add */ sess = NULL; } } else { @@ -684,8 +684,8 @@ rexmpp_jingle_send_file (rexmpp_t *s, len = fread(buf, 1, 4096, fh); } - char *sid = rexmpp_gen_id(s); - char *ibb_sid = rexmpp_gen_id(s); + char *sid = rexmpp_random_id(); + char *ibb_sid = rexmpp_random_id(); rexmpp_xml_t *jingle = rexmpp_xml_new_elem("jingle", "urn:xmpp:jingle:1"); @@ -1161,7 +1161,7 @@ rexmpp_jingle_candidate_gathering_done_cb (NiceAgent *agent, rexmpp_xml_add_attr(candidate, "component", buf); rexmpp_xml_add_attr(candidate, "foundation", c->foundation); rexmpp_xml_add_attr(candidate, "generation", "0"); - char *cid = rexmpp_gen_id(sess->s); + char *cid = rexmpp_random_id(); rexmpp_xml_add_attr(candidate, "id", cid); free(cid); nice_address_to_string(&c->addr, buf); @@ -1767,7 +1767,7 @@ rexmpp_jingle_call (rexmpp_t *s, const char *jid) { rexmpp_jingle_session_t *sess = - rexmpp_jingle_session_create(s, strdup(jid), rexmpp_gen_id(s), + rexmpp_jingle_session_create(s, strdup(jid), rexmpp_random_id(), REXMPP_JINGLE_SESSION_MEDIA, 1); rexmpp_jingle_ice_agent_init(sess); rexmpp_jingle_discover_turn(s, sess); @@ -1896,11 +1896,13 @@ int rexmpp_jingle_iq (rexmpp_t *s, rexmpp_xml_t *elem) { rexmpp_jingle_session_t *sess = rexmpp_jingle_session_create(s, strdup(from_jid), strdup(sid), REXMPP_JINGLE_SESSION_MEDIA, 0); - sess->rtcp_mux = - (rexmpp_xml_find_child(rtp_description, - "urn:xmpp:jingle:apps:rtp:1", - "rtcp-mux") != NULL); - sess->initiate = rexmpp_xml_clone(jingle); + if (sess != NULL) { + sess->rtcp_mux = + (rexmpp_xml_find_child(rtp_description, + "urn:xmpp:jingle:apps:rtp:1", + "rtcp-mux") != NULL); + sess->initiate = rexmpp_xml_clone(jingle); + } #endif /* ENABLE_CALLS */ } else if (file_description == NULL && rtp_description == NULL) { diff --git a/src/rexmpp_openpgp.c b/src/rexmpp_openpgp.c index 4ef7335..222ae6b 100644 --- a/src/rexmpp_openpgp.c +++ b/src/rexmpp_openpgp.c @@ -732,6 +732,11 @@ char *rexmpp_openpgp_payload (rexmpp_t *s, /* Add keys for encryption. */ allocated = 8; keys = malloc(sizeof(gpgme_key_t *) * allocated); + if (keys == NULL) { + rexmpp_log(s, LOG_ERR, "Failed to allocate memory for keys"); + rexmpp_xml_free(elem); + return NULL; + } keys[0] = NULL; rexmpp_openpgp_add_keys(s, s->initial_jid.bare, &keys, &nkeys, &allocated); for (i = 0; recipients[i] != NULL; i++) { diff --git a/src/rexmpp_random.c b/src/rexmpp_random.c index 8efabd3..11e2b73 100644 --- a/src/rexmpp_random.c +++ b/src/rexmpp_random.c @@ -7,6 +7,7 @@ */ #include "config.h" +#include "rexmpp_base64.h" #ifdef HAVE_GCRYPT #include @@ -23,3 +24,11 @@ void rexmpp_random_buf (void *buf, size_t len) { arc4random_buf(buf, len); #endif } + +char *rexmpp_random_id () { + char buf_raw[18], *buf_base64 = NULL; + size_t buf_base64_len = 0; + rexmpp_random_buf(buf_raw, 18); + rexmpp_base64_to(buf_raw, 18, &buf_base64, &buf_base64_len); + return buf_base64; +} diff --git a/src/rexmpp_random.h b/src/rexmpp_random.h index 1b21001..b0f1978 100644 --- a/src/rexmpp_random.h +++ b/src/rexmpp_random.h @@ -19,4 +19,11 @@ */ void rexmpp_random_buf (void *buf, size_t len); +/** + @brief Generates a random ASCII identifier. + @returns A null-terminated string, which must be freed by the + caller. +*/ +char *rexmpp_random_id (); + #endif diff --git a/src/rexmpp_tls.c b/src/rexmpp_tls.c index c8decc0..e483a2c 100644 --- a/src/rexmpp_tls.c +++ b/src/rexmpp_tls.c @@ -61,6 +61,10 @@ rexmpp_tls_err_t rexmpp_process_openssl_ret (rexmpp_t *s, rexmpp_tls_t *rexmpp_tls_ctx_new (rexmpp_t *s, int dtls) { rexmpp_tls_t *tls_ctx = malloc(sizeof(rexmpp_tls_t)); + if (tls_ctx == NULL) { + rexmpp_log(s, LOG_CRIT, "Failed to allocate memory for a TLS context"); + return NULL; + } #if defined(USE_GNUTLS) (void)dtls; int err; @@ -71,6 +75,7 @@ rexmpp_tls_t *rexmpp_tls_ctx_new (rexmpp_t *s, int dtls) { if (err) { rexmpp_log(s, LOG_CRIT, "gnutls credentials allocation error: %s", gnutls_strerror(err)); + free(tls_ctx); return NULL; } if (! dtls) { @@ -79,6 +84,7 @@ rexmpp_tls_t *rexmpp_tls_ctx_new (rexmpp_t *s, int dtls) { if (err < 0) { rexmpp_log(s, LOG_CRIT, "Certificates loading error: %s", gnutls_strerror(err)); + free(tls_ctx); return NULL; } @@ -91,6 +97,7 @@ rexmpp_tls_t *rexmpp_tls_ctx_new (rexmpp_t *s, int dtls) { : TLS_method()); if (tls_ctx->openssl_ctx == NULL) { rexmpp_log(s, LOG_CRIT, "OpenSSL context creation error"); + free(tls_ctx); return NULL; } SSL_CTX_set_verify(tls_ctx->openssl_ctx, SSL_VERIFY_PEER, NULL); @@ -99,6 +106,7 @@ rexmpp_tls_t *rexmpp_tls_ctx_new (rexmpp_t *s, int dtls) { "Failed to set default verify paths for OpenSSL context"); SSL_CTX_free(tls_ctx->openssl_ctx); tls_ctx->openssl_ctx = NULL; + free(tls_ctx); return NULL; } #else @@ -149,7 +157,7 @@ void rexmpp_tls_session_free (rexmpp_tls_t *tls_ctx) { } tls_ctx->openssl_direction = REXMPP_OPENSSL_NONE; #else - (void)s; + (void)tls_ctx; #endif } @@ -504,6 +512,8 @@ rexmpp_tls_disconnect (rexmpp_t *s, rexmpp_tls_t *tls_ctx) { int ret = gnutls_bye(tls_ctx->gnutls_session, GNUTLS_SHUT_RDWR); if (ret == GNUTLS_E_SUCCESS) { return REXMPP_TLS_SUCCESS; + } else if (ret == GNUTLS_E_AGAIN) { + return REXMPP_TLS_E_AGAIN; } else { rexmpp_log(s, LOG_WARNING, "Failed to close TLS connection: %s", gnutls_strerror(ret)); @@ -519,6 +529,7 @@ rexmpp_tls_disconnect (rexmpp_t *s, rexmpp_tls_t *tls_ctx) { "rexmpp_tls_disconnect", ret); } #else + (void)tls_ctx; rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support"); return REXMPP_TLS_E_OTHER; #endif @@ -558,8 +569,8 @@ rexmpp_tls_srtp_get_keys (rexmpp_t *s, (void)tls_ctx; (void)key_len; (void)salt_len; - (void)client_key_wsalt; - (void)server_key_wsalt; + (void)key_mat; + rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support"); return -1; #endif } @@ -598,6 +609,7 @@ rexmpp_tls_send (rexmpp_t *s, (void)data; (void)data_size; (void)written; + (void)tls_ctx; rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support"); return REXMPP_TLS_E_OTHER; #endif @@ -635,6 +647,7 @@ rexmpp_tls_recv (rexmpp_t *s, (void)data; (void)data_size; (void)received; + (void)tls_ctx; rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support"); return REXMPP_TLS_E_OTHER; #endif @@ -721,6 +734,7 @@ rexmpp_tls_set_x509_key_file (rexmpp_t *s, #else (void)cert_file; (void)key_file; + (void)tls_ctx; rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support"); return REXMPP_TLS_E_OTHER; #endif @@ -751,6 +765,7 @@ rexmpp_tls_set_x509_trust_file (rexmpp_t *s, return REXMPP_TLS_SUCCESS; #else (void)trust_file; + (void)tls_ctx; rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support"); return REXMPP_TLS_E_OTHER; #endif @@ -798,12 +813,13 @@ int rexmpp_tls_peer_fp (rexmpp_t *s, fp_str[*fp_size * 3 - 1] = 0; return 0; #else - (void)s; (void)tls_ctx; (void)algo_str; (void)raw_fp; (void)fp_str; (void)fp_size; + rexmpp_log(s, LOG_ERR, "rexmpp is compiled without TLS support"); + return -1; #endif } diff --git a/src/rexmpp_xml.c b/src/rexmpp_xml.c index 08e11dd..96b283d 100644 --- a/src/rexmpp_xml.c +++ b/src/rexmpp_xml.c @@ -12,6 +12,7 @@ #include "rexmpp.h" #include "rexmpp_utf8.h" #include "rexmpp_xml.h" +#include "rexmpp_random.h" #ifndef USE_RUST void rexmpp_xml_qname_free (rexmpp_xml_qname_t *qname) { @@ -449,10 +450,9 @@ char *rexmpp_xml_serialize (const rexmpp_xml_t *node, int pretty) { } rexmpp_xml_t * -rexmpp_xml_add_id (rexmpp_t *s, - rexmpp_xml_t *node) +rexmpp_xml_add_id (rexmpp_xml_t *node) { - char *buf = rexmpp_gen_id(s); + char *buf = rexmpp_random_id(); if (buf == NULL) { return NULL; } @@ -557,10 +557,12 @@ rexmpp_xml_t *rexmpp_xml_read_fd (FILE *fd) { size_t init_len = 0; ssize_t buf_len = 0; do { + buf = NULL; buf_len = getline(&buf, &init_len, fd); if (buf_len > 0) { rexmpp_xml_parser_feed(parser, buf, buf_len, 0); } + free(buf); } while (buf_len > 0 && ! (builder.root != NULL && builder.current == NULL) ); diff --git a/src/rexmpp_xml.h b/src/rexmpp_xml.h index d5a9af1..8f6d974 100644 --- a/src/rexmpp_xml.h +++ b/src/rexmpp_xml.h @@ -9,6 +9,8 @@ #ifndef REXMPP_XML_H #define REXMPP_XML_H +#include + typedef struct rexmpp_xml_qname rexmpp_xml_qname_t; typedef struct rexmpp_xml_attribute rexmpp_xml_attr_t; typedef struct rexmpp_xml_node rexmpp_xml_t; @@ -139,8 +141,7 @@ int rexmpp_xml_add_attr_ns (rexmpp_xml_t *node, composition. */ rexmpp_xml_t * -rexmpp_xml_add_id (rexmpp_t *s, - rexmpp_xml_t *node); +rexmpp_xml_add_id (rexmpp_xml_t *node); /** @brief A helper function for XML serialisation. diff --git a/src/rexmpp_xml_parser.c b/src/rexmpp_xml_parser.c index e00c70c..3f485d7 100644 --- a/src/rexmpp_xml_parser.c +++ b/src/rexmpp_xml_parser.c @@ -41,13 +41,15 @@ void rexmpp_xml_sax_elem_start (rexmpp_xml_parser_ctx_t ctx, for (i = nb_attributes - 1; i >= 0; i--) { size_t attr_len = attributes[i * 5 + 4] - attributes[i * 5 + 3]; char *attr_val = malloc(attr_len + 1); - attr_val[attr_len] = '\0'; - strncpy(attr_val, attributes[i * 5 + 3], attr_len); - rexmpp_xml_attr_t *attr = - rexmpp_xml_attr_new(attributes[i * 5], NULL, attr_val); - free(attr_val); - attr->next = attrs; - attrs = attr; + if (attr_val != NULL) { + attr_val[attr_len] = '\0'; + strncpy(attr_val, attributes[i * 5 + 3], attr_len); + rexmpp_xml_attr_t *attr = + rexmpp_xml_attr_new(attributes[i * 5], NULL, attr_val); + free(attr_val); + attr->next = attrs; + attrs = attr; + } } ctx->handlers->elem_start(ctx->user_data, localname, URI, attrs); diff --git a/tests/Makefile.am b/tests/Makefile.am index 22290a5..93c0b82 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,19 +1,24 @@ AM_CFLAGS = -Werror -Wall -Wextra -pedantic -std=gnu99 -COMMON_FLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) \ +COMMON_FLAGS = $(AM_CFLAGS) $(LIBXML_CFLAGS) $(EXPAT_CFLAGS) \ $(GNUTLS_CFLAGS) $(LIBDANE_CFLAGS) $(OPENSSL_CFLAGS) \ $(GSASL_CFLAGS) $(UNBOUND_CFLAGS) $(CARES_CFLAGS) $(GPGME_CFLAGS) \ $(ICU_I18N_CFLAGS) $(LIBGCRYPT_CFLAGS) $(CURL_CFLAGS) \ $(NICE_CFLAGS) $(GLIB_CFLAGS) $(SRTP_CFLAGS) \ - -I$(top_srcdir)/src -COMMON_LIBS = $(LIBXML_LIBS) \ - $(GNUTLS_LIBS) $(LIBDANE_LIBS) $(OPENSSL_LIBS) \ - $(GSASL_LIBS) $(UNBOUND_LIBS) $(CARES_LIBS) $(GPGME_LIBS) $(ICU_I18N_LIBS) \ - $(LIBGCRYPT_LIBS) $(CURL_LIBS) $(NICE_LIBS) $(GLIB_LIBS) $(SRTP_LIBS) \ - -L$(top_builddir)/src -lrexmpp + $(PORTAUDIO_CFLAGS) $(OPUS_CFLAGS) $(NETTLE_CFLAGS) +COMMON_LDADD = -L$(top_builddir)/src -lrexmpp send_to_self_CFLAGS = $(COMMON_FLAGS) -send_to_self_LDADD = $(COMMON_LIBS) +xml_parse_and_print_CFLAGS = $(COMMON_FLAGS) +xml_print_and_parse_CFLAGS = $(COMMON_FLAGS) +base64_CFLAGS = $(COMMON_FLAGS) -check_PROGRAMS = send_to_self -TESTS = send_to_self +send_to_self_LDADD = $(COMMON_LDADD) +xml_parse_and_print_LDADD = $(COMMON_LDADD) +xml_print_and_parse_LDADD = $(COMMON_LDADD) +base64_LDADD = $(COMMON_LDADD) + +check_PROGRAMS = send_to_self \ + xml_parse_and_print xml_print_and_parse base64 +TESTS = send_to_self \ + xml_parse_and_print xml_print_and_parse base64 diff --git a/tests/base64.c b/tests/base64.c new file mode 100644 index 0000000..b69ba0e --- /dev/null +++ b/tests/base64.c @@ -0,0 +1,18 @@ +#include +#include "rexmpp_base64.h" + +int main () { + char *original_plain = "test string"; + char *original_base64 = "dGVzdCBzdHJpbmc="; + char *encoded, *decoded; + size_t encoded_len, decoded_len; + if (rexmpp_base64_to(original_plain, strlen(original_plain), + &encoded, &encoded_len)) { + return -1; + } + if (rexmpp_base64_from(original_base64, strlen(original_base64), + &decoded, &decoded_len)) { + return -1; + } + return strcmp(original_plain, decoded) || strcmp(original_base64, encoded); +} diff --git a/tests/send_to_self.c b/tests/send_to_self.c index b5d6d7e..2fcb80f 100644 --- a/tests/send_to_self.c +++ b/tests/send_to_self.c @@ -16,7 +16,6 @@ that it's the expected message. #include #include #include -#include #include #include @@ -89,9 +88,7 @@ int my_xml_out_cb (rexmpp_t *s, rexmpp_xml_t *node) { return 0; } -int main (int argc, char **argv) { - (void)argc; - (void)argv; +int main () { jid = getenv("JID"); pass = getenv("PASS"); char *tls_policy = getenv("TLS_POLICY"); @@ -143,8 +140,7 @@ int main (int argc, char **argv) { if (stage == TEST_CONNECTING && s.stream_state == REXMPP_STREAM_READY) { rexmpp_xml_t *msg = - rexmpp_xml_add_id(&s, - rexmpp_xml_new_elem("message", "jabber:client")); + rexmpp_xml_add_id(rexmpp_xml_new_elem("message", "jabber:client")); rexmpp_xml_add_attr(msg, "to", jid); rexmpp_xml_add_attr(msg, "type", "chat"); rexmpp_xml_t *body = rexmpp_xml_new_elem("body", NULL); diff --git a/tests/xml_parse_and_print.c b/tests/xml_parse_and_print.c new file mode 100644 index 0000000..ad6bbca --- /dev/null +++ b/tests/xml_parse_and_print.c @@ -0,0 +1,27 @@ +#include +#include +#include "rexmpp_xml.h" + +int main () { + int ret = 0; + + char *str = "" + "a b c d" + "" + ""; + rexmpp_xml_t *xml = rexmpp_xml_parse (str, strlen(str)); + + if (xml == NULL) { + ret = -1; + } else { + char *str_new = rexmpp_xml_serialize (xml, 0); + if (str_new == NULL) { + ret = -2; + } else { + ret = strcmp(str, str_new); + free(str_new); + } + rexmpp_xml_free(xml); + } + return ret; +} diff --git a/tests/xml_print_and_parse.c b/tests/xml_print_and_parse.c new file mode 100644 index 0000000..9bd7a3f --- /dev/null +++ b/tests/xml_print_and_parse.c @@ -0,0 +1,64 @@ +#include +#include +#include "rexmpp_xml.h" + +int main () { + int ret = 0; + + rexmpp_xml_attr_t + foo_attributes = { .qname = {"bar", NULL}, + .value = "baz", + .next = NULL }, + quux_attributes_g = { .qname = {"g", NULL}, + .value = "h", + .next = NULL }, + quux_attributes = + { .qname = {"e", NULL}, + .value = "f", + .next = &quux_attributes_g }; + rexmpp_xml_t + quux = { .type = REXMPP_XML_ELEMENT, + .alt.elem = + { .qname = {"quux", NULL}, + .attributes = &quux_attributes, + .children = NULL + }, + .next = NULL + }, + qux_text = { .type = REXMPP_XML_TEXT, + .alt.text = "a b c d", + .next = NULL }, + qux = { .type = REXMPP_XML_ELEMENT, + .alt.elem = + { .qname = {"qux", "urn:dummy"}, + .attributes = NULL, + .children = &qux_text + }, + .next = &quux + }, + xml = + { .type = REXMPP_XML_ELEMENT, + .alt.elem = + { .qname = {"foo", NULL}, + .attributes = &foo_attributes, + .children = &qux + }, + .next = NULL + }; + + char *str_new = rexmpp_xml_serialize (&xml, 0); + if (str_new == NULL) { + ret = -1; + } else { + rexmpp_xml_t *xml_new = rexmpp_xml_parse (str_new, strlen(str_new)); + if (xml_new == NULL) { + ret = -2; + } else { + /* Compare the XML structures. */ + ret = (rexmpp_xml_eq(&xml, xml_new) == 0); + rexmpp_xml_free(xml_new); + } + free(str_new); + } + return ret; +} -- cgit v1.2.3