diff options
author | Timotej S <6674623+underhood@users.noreply.github.com> | 2022-12-21 08:29:18 +0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-21 08:29:18 +0700 |
commit | 474d80ef10c8476c210a5018a3f5c6edcf2d899d (patch) | |
tree | dc1a0b7862f94611b12a35f69b8b3afd0fd672c9 /aclk | |
parent | 0804995b0e45575411c860d243ded865cfbb1a16 (diff) |
Support HTTP proxy Basic auth (#13762)
Diffstat (limited to 'aclk')
-rw-r--r-- | aclk/aclk.c | 7 | ||||
-rw-r--r-- | aclk/aclk_otp.c | 25 | ||||
-rw-r--r-- | aclk/aclk_util.c | 102 | ||||
-rw-r--r-- | aclk/aclk_util.h | 4 | ||||
-rw-r--r-- | aclk/https_client.c | 22 | ||||
-rw-r--r-- | aclk/https_client.h | 2 |
6 files changed, 125 insertions, 37 deletions
diff --git a/aclk/aclk.c b/aclk/aclk.c index 45f3bb4760..c3d0fc891e 100644 --- a/aclk/aclk.c +++ b/aclk/aclk.c @@ -532,7 +532,7 @@ static int aclk_attempt_to_connect(mqtt_wss_client client) } struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT }; - aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type); + aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type); struct mqtt_connect_params mqtt_conn_params = { .clientid = "anon", @@ -630,7 +630,10 @@ static int aclk_attempt_to_connect(mqtt_wss_client client) freez((char*)mqtt_conn_params.username); #endif - freez((char *)mqtt_conn_params.will_msg); + freez((char*)mqtt_conn_params.will_msg); + freez((char*)proxy_conf.host); + freez((char*)proxy_conf.username); + freez((char*)proxy_conf.password); if (!ret) { last_conn_time_mqtt = now_realtime_sec(); diff --git a/aclk/aclk_otp.c b/aclk/aclk_otp.c index 2bdbb70fb1..940d5bdbe5 100644 --- a/aclk/aclk_otp.c +++ b/aclk/aclk_otp.c @@ -14,15 +14,19 @@ static int aclk_https_request(https_req_t *request, https_req_response_t *respon // wrapper for ACLK only which loads ACLK specific proxy settings // then only calls https_request struct mqtt_wss_proxy proxy_conf = { .host = NULL, .port = 0, .username = NULL, .password = NULL, .type = MQTT_WSS_DIRECT }; - aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, &proxy_conf.type); + aclk_set_proxy((char**)&proxy_conf.host, &proxy_conf.port, (char**)&proxy_conf.username, (char**)&proxy_conf.password, &proxy_conf.type); if (proxy_conf.type == MQTT_WSS_PROXY_HTTP) { request->proxy_host = (char*)proxy_conf.host; // TODO make it const as well request->proxy_port = proxy_conf.port; + request->proxy_username = proxy_conf.username; + request->proxy_password = proxy_conf.password; } rc = https_request(request, response); freez((char*)proxy_conf.host); + freez((char*)proxy_conf.username); + freez((char*)proxy_conf.password); return rc; } @@ -303,25 +307,6 @@ inline static int base64_decode_helper(unsigned char *out, int *outl, const unsi return 0; } -inline static int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len) -{ - int len; - unsigned char *str = out; - EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); - EVP_EncodeInit(ctx); - EVP_EncodeUpdate(ctx, str, outl, in, in_len); - str += *outl; - EVP_EncodeFinal(ctx, str, &len); - *outl += len; - // if we ever expect longer output than what OpenSSL would pack into single line - // we would have to skip the endlines, until then we can just cut the string short - str = (unsigned char*)strchr((char*)out, '\n'); - if (str) - *str = 0; - EVP_ENCODE_CTX_free(ctx); - return 0; -} - #define OTP_URL_PREFIX "/api/v1/auth/node/" int aclk_get_otp_challenge(url_t *target, const char *agent_id, unsigned char **challenge, int *challenge_bytes) { diff --git a/aclk/aclk_util.c b/aclk/aclk_util.c index 01eaedc8e0..27d536e75e 100644 --- a/aclk/aclk_util.c +++ b/aclk/aclk_util.c @@ -346,43 +346,117 @@ unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, un return delay; } +static inline int aclk_parse_pair(const char *src, const char c, char **a, char **b) +{ + const char *ptr = strchr(src, c); + if (ptr == NULL) + return 1; + +// allow empty string +/* if (!*(ptr+1)) + return 1;*/ + + *a = callocz(1, ptr - src + 1); + memcpy (*a, src, ptr - src); + + *b = strdupz(ptr+1); + + return 0; +} #define HTTP_PROXY_PREFIX "http://" -void aclk_set_proxy(char **ohost, int *port, enum mqtt_wss_proxy_type *type) +void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type) { ACLK_PROXY_TYPE pt; const char *ptr = aclk_get_proxy(&pt); char *tmp; - char *host; + if (pt != PROXY_TYPE_HTTP) return; + *uname = NULL; + *pwd = NULL; *port = 0; + char *proxy = strdupz(ptr); + ptr = proxy; + if (!strncmp(ptr, HTTP_PROXY_PREFIX, strlen(HTTP_PROXY_PREFIX))) ptr += strlen(HTTP_PROXY_PREFIX); - if ((tmp = strchr(ptr, '@'))) - ptr = tmp; + if ((tmp = strchr(ptr, '@'))) { + *tmp = 0; + if(aclk_parse_pair(ptr, ':', uname, pwd)) { + error_report("Failed to get username and password for proxy. Will attempt connection without authentication"); + } + ptr = tmp+1; + } - if ((tmp = strchr(ptr, '/'))) { - host = mallocz((tmp - ptr) + 1); - memcpy(host, ptr, (tmp - ptr)); - host[tmp - ptr] = 0; - } else - host = strdupz(ptr); + if (!*ptr) { + freez(proxy); + freez(*uname); + freez(*pwd); + return; + } - if ((tmp = strchr(host, ':'))) { + if ((tmp = strchr(ptr, ':'))) { *tmp = 0; tmp++; - *port = atoi(tmp); + if(*tmp) + *port = atoi(tmp); } + *ohost = strdupz(ptr); if (*port <= 0 || *port > 65535) *port = 8080; - *ohost = host; - if (type) *type = MQTT_WSS_PROXY_HTTP; + else { + freez(*uname); + freez(*pwd); + } + + freez(proxy); +} + +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < OPENSSL_VERSION_110 +static EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void) +{ + EVP_ENCODE_CTX *ctx = OPENSSL_malloc(sizeof(*ctx)); + + if (ctx != NULL) { + memset(ctx, 0, sizeof(*ctx)); + } + return ctx; +} +static void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx) +{ + OPENSSL_free(ctx); + return; +} +#endif + +int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len) +{ + int len; + unsigned char *str = out; + EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); + EVP_EncodeInit(ctx); + EVP_EncodeUpdate(ctx, str, outl, in, in_len); + str += *outl; + EVP_EncodeFinal(ctx, str, &len); + *outl += len; + + str = out; + while(*str) { + if (*str != 0x0D && *str != 0x0A) + *out++ = *str++; + else + str++; + } + *out = 0; + + EVP_ENCODE_CTX_free(ctx); + return 0; } diff --git a/aclk/aclk_util.h b/aclk/aclk_util.h index ed715e0466..6a9acbc6ae 100644 --- a/aclk/aclk_util.h +++ b/aclk/aclk_util.h @@ -107,6 +107,8 @@ extern volatile int aclk_conversation_log_counter; unsigned long int aclk_tbeb_delay(int reset, int base, unsigned long int min, unsigned long int max); #define aclk_tbeb_reset(x) aclk_tbeb_delay(1, 0, 0, 0) -void aclk_set_proxy(char **ohost, int *port, enum mqtt_wss_proxy_type *type); +void aclk_set_proxy(char **ohost, int *port, char **uname, char **pwd, enum mqtt_wss_proxy_type *type); + +int base64_encode_helper(unsigned char *out, int *outl, const unsigned char *in, int in_len); #endif /* ACLK_UTIL_H */ diff --git a/aclk/https_client.c b/aclk/https_client.c index 1a32f833ff..8af85f8546 100644 --- a/aclk/https_client.c +++ b/aclk/https_client.c @@ -6,6 +6,8 @@ #include "mqtt_websockets/c-rbuf/include/ringbuffer.h" +#include "aclk_util.h" + enum http_parse_state { HTTP_PARSE_INITIAL = 0, HTTP_PARSE_HEADERS, @@ -392,6 +394,24 @@ static int handle_http_request(https_req_ctx_t *ctx) { if (ctx->request->request_type == HTTP_REQ_POST && ctx->request->payload && ctx->request->payload_size) { buffer_sprintf(hdr, "Content-Length: %zu\x0D\x0A", ctx->request->payload_size); } + if (ctx->request->proxy_username) { + size_t creds_plain_len = strlen(ctx->request->proxy_username) + strlen(ctx->request->proxy_password) + 1 /* ':' */; + char *creds_plain = callocz(1, creds_plain_len + 1); + char *ptr = creds_plain; + strcpy(ptr, ctx->request->proxy_username); + ptr += strlen(ctx->request->proxy_username); + *ptr++ = ':'; + strcpy(ptr, ctx->request->proxy_password); + + int creds_base64_len = (((4 * creds_plain_len / 3) + 3) & ~3); + // OpenSSL encoder puts newline every 64 output bytes + // we remove those but during encoding we need that space in the buffer + creds_base64_len += (1+(creds_base64_len/64)) * strlen("\n"); + char *creds_base64 = callocz(1, creds_base64_len + 1); + base64_encode_helper((unsigned char*)creds_base64, &creds_base64_len, (unsigned char*)creds_plain, creds_plain_len); + buffer_sprintf(hdr, "Proxy-Authorization: Basic %s\x0D\x0A", creds_base64); + freez(creds_plain); + } buffer_strcat(hdr, "\x0D\x0A"); @@ -491,6 +511,8 @@ int https_request(https_req_t *request, https_req_response_t *response) { req.host = request->host; req.port = request->port; req.url = request->url; + req.proxy_username = request->proxy_username; + req.proxy_password = request->proxy_password; ctx->request = &req; if (handle_http_request(ctx)) { error("Failed to CONNECT with proxy"); diff --git a/aclk/https_client.h b/aclk/https_client.h index f7bc3d43d6..daf4766f87 100644 --- a/aclk/https_client.h +++ b/aclk/https_client.h @@ -25,6 +25,8 @@ typedef struct { char *proxy_host; int proxy_port; + const char *proxy_username; + const char *proxy_password; } https_req_t; typedef struct { |