From a53c4afd13d92572b8c0ebb93d0dbe3f7c7bc680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Wed, 22 Feb 2017 10:38:56 +0100 Subject: [PATCH 83/90] secrets: use tcurl in proxy provider We switch from http-parser to libcurl for an http client. This gaves us many features for free such as tls and http basic authentication support instead of implementing it on our own. Resolves: https://pagure.io/SSSD/sssd/issue/3192 Reviewed-by: Simo Sorce Reviewed-by: Jakub Hrozek (cherry picked from commit df99d709c8cbef3c378c111944d83b7345e4c1ea) --- Makefile.am | 3 + src/responder/secrets/providers.c | 20 +++ src/responder/secrets/proxy.c | 246 ++++++++++++++++++++++----------- src/responder/secrets/secsrv_private.h | 5 + 4 files changed, 191 insertions(+), 83 deletions(-) diff --git a/Makefile.am b/Makefile.am index 573b37c52fdeab1add4ea057e1e1844ea4d348a5..4a414f77df999b8b1d81f663fcc18dbd2d6d2dc4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1486,6 +1486,8 @@ sssd_secrets_SOURCES = \ src/responder/secrets/local.c \ src/responder/secrets/proxy.c \ src/util/sss_sockets.c \ + src/util/sss_iobuf.c \ + src/util/tev_curl.c \ $(SSSD_RESPONDER_OBJ) \ $(SSSD_RESOLV_OBJ) \ $(NULL) @@ -1497,6 +1499,7 @@ sssd_secrets_LDADD = \ $(SYSTEMD_DAEMON_LIBS) \ $(CARES_LIBS) \ $(SSSD_INTERNAL_LTLIBS) \ + $(CURL_LIBS) \ $(NULL) endif diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c index 94831c73036d269addca45c0117811a2c68873fd..80a443d91135447ec8ce8d424b692a6d7e26a907 100644 --- a/src/responder/secrets/providers.c +++ b/src/responder/secrets/providers.c @@ -22,6 +22,7 @@ #include "responder/secrets/secsrv_private.h" #include "responder/secrets/secsrv_local.h" #include "responder/secrets/secsrv_proxy.h" +#include "util/sss_iobuf.h" #include typedef int (*url_mapper_fn)(struct sec_req_ctx *secreq, @@ -387,6 +388,25 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, return EOK; } +errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, + struct sec_data *reply, + int response_code, + struct sss_iobuf *response) +{ + DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code); + + reply->data = (char *)sss_iobuf_get_data(response); + reply->length = sss_iobuf_get_len(response); + + talloc_steal(mem_ctx, reply->data); + + if (reply->data == NULL) { + return EINVAL; + } + + return EOK; +} + enum sec_http_status_codes sec_errno_to_http_status(errno_t err) { DEBUG(SSSDBG_TRACE_LIBS, "Request errno: %d\n", err); diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c index 3ed03e6086d0de0f6f80de227ffc65ef4067db4f..fe2f0134e233d9a98f499fe563abe0af69762514 100644 --- a/src/responder/secrets/proxy.c +++ b/src/responder/secrets/proxy.c @@ -23,10 +23,15 @@ #include "util/crypto/sss_crypto.h" #include "resolv/async_resolv.h" #include "util/sss_sockets.h" +#include "util/sss_iobuf.h" +#include "util/tev_curl.h" + +#define SEC_PROXY_TIMEOUT 5 struct proxy_context { struct resolv_ctx *resctx; struct confdb_ctx *cdb; + struct tcurl_ctx *tcurl; }; enum proxy_auth_type { @@ -216,103 +221,177 @@ int proxy_sec_map_url(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, return EOK; } -int proxy_sec_map_headers(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq, - struct proxy_cfg *pcfg, char **req_headers) +static errno_t proxy_http_append_header(TALLOC_CTX *mem_ctx, + const char *name, + const char *value, + const char ***_headers, + size_t *_num_headers) { - int ret; - - for (int i = 0; i < secreq->num_headers; i++) { - bool forward = false; - for (int j = 0; pcfg->fwd_headers[j]; j++) { - if (strcasecmp(secreq->headers[i].name, - pcfg->fwd_headers[j]) == 0) { - forward = true; + const char **headers = *_headers; + size_t num_headers = *_num_headers; + + num_headers++; + headers = talloc_realloc(mem_ctx, headers, const char *, + num_headers + 1); + if (headers == NULL) { + return ENOMEM; + } + + headers[num_headers - 1] = talloc_asprintf(headers, "%s: %s", name, value); + if (headers[num_headers - 1] == NULL) { + return ENOMEM; + } + + headers[num_headers] = NULL; + + *_headers = headers; + *_num_headers = num_headers; + + return EOK; +} + +static const char ** +proxy_http_create_headers(TALLOC_CTX *mem_ctx, + struct sec_req_ctx *secreq, + struct proxy_cfg *pcfg) +{ + TALLOC_CTX *tmp_ctx; + const char **headers; + size_t num_headers; + errno_t ret; + int i, j; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); + return NULL; + } + + headers = talloc_zero_array(tmp_ctx, const char *, 1); + if (headers == NULL) { + ret = ENOMEM; + goto done; + } + + num_headers = 0; + for (i = 0; i < secreq->num_headers; i++) { + for (j = 0; pcfg->fwd_headers[j]; j++) { + if (strcasecmp(secreq->headers[i].name, pcfg->fwd_headers[j]) == 0) { + DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s: %s\n", + secreq->headers[i].name, secreq->headers[i].value); + + ret = proxy_http_append_header(tmp_ctx, secreq->headers[i].name, + secreq->headers[i].value, + &headers, &num_headers); + if (ret != EOK) { + goto done; + } + break; } } - if (forward) { - DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s:%s\n", - secreq->headers[i].name, secreq->headers[i].value); - - ret = sec_http_append_header(mem_ctx, req_headers, - secreq->headers[i].name, - secreq->headers[i].value); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Couldn't append header %s\n", secreq->headers[i].name); - return ret; - } - } } if (pcfg->auth_type == PAT_HEADER) { - DEBUG(SSSDBG_TRACE_LIBS, - "Forwarding header %s\n", pcfg->auth.header.name); + DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s\n", + pcfg->auth.header.name); - ret = sec_http_append_header(mem_ctx, req_headers, - pcfg->auth.header.name, - pcfg->auth.header.value); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, - "Couldn't append header %s\n", pcfg->auth.header.name); - return ret; + ret = proxy_http_append_header(tmp_ctx, pcfg->auth.header.name, + pcfg->auth.header.value, + &headers, &num_headers); + if (ret != EOK) { + goto done; } } - return EOK; + talloc_steal(mem_ctx, headers); + + ret = EOK; + +done: + talloc_free(tmp_ctx); + + if (ret != EOK) { + return NULL; + } + + return headers; } -static int proxy_http_create_request(TALLOC_CTX *mem_ctx, - struct sec_req_ctx *secreq, - struct proxy_cfg *pcfg, - const char *http_uri, - struct sec_data **http_req) +static errno_t proxy_http_create_request(TALLOC_CTX *mem_ctx, + struct sec_req_ctx *secreq, + struct proxy_cfg *pcfg, + const char *url, + struct tcurl_request **_tcurl_req) { - struct sec_data *req; - int ret; + TALLOC_CTX *tmp_ctx; + struct tcurl_request *tcurl_req; + enum tcurl_http_method method; + struct sss_iobuf *body; + const char **headers; + errno_t ret; - req = talloc_zero(mem_ctx, struct sec_data); - if (!req) return ENOMEM; + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory!\n"); + return ENOMEM; + } - /* Request-Line */ - req->data = talloc_asprintf(req, "%s %s HTTP/1.1\r\n", - http_method_str(secreq->method), http_uri); - if (!req->data) { + headers = proxy_http_create_headers(tmp_ctx, secreq, pcfg); + if (headers == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct HTTP headers!\n"); ret = ENOMEM; goto done; } - /* Headers */ - ret = proxy_sec_map_headers(req, secreq, pcfg, &req->data); - if (ret) { - DEBUG(SSSDBG_CRIT_FAILURE, "Couldn't map headers\n"); + body = sss_iobuf_init_readonly(tmp_ctx, (uint8_t *)secreq->body.data, + secreq->body.length); + if (body == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create HTTP body!\n"); + ret = ENOMEM; goto done; } - /* CRLF separator before body */ - req->data = talloc_strdup_append_buffer(req->data, "\r\n"); - - req->length = strlen(req->data); + switch (secreq->method) { + case HTTP_GET: + method = TCURL_HTTP_GET; + break; + case HTTP_PUT: + method = TCURL_HTTP_PUT; + break; + case HTTP_POST: + method = TCURL_HTTP_POST; + break; + case HTTP_DELETE: + method = TCURL_HTTP_DELETE; + break; + default: + DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected HTTP method: %d\n", + secreq->method); + ret = EINVAL; + goto done; + } - /* Message-Body */ - if (secreq->body.length > 0) { - req->data = talloc_realloc_size(req, req->data, - req->length + secreq->body.length); - if (!req->data) { - ret = ENOMEM; - goto done; - } + tcurl_req = tcurl_http(tmp_ctx, method, NULL, url, headers, body); + if (tcurl_req == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create TCURL request!\n"); + ret = ENOMEM; + goto done; + } - memcpy(&req->data[req->length], - secreq->body.data, secreq->body.length); - req->length += secreq->body.length; + /* TCURL will return response buffer also with headers. */ + ret = tcurl_req_enable_rawoutput(tcurl_req); + if (ret != EOK) { + goto done; } - *http_req = req; + talloc_steal(tcurl_req, body); + *_tcurl_req = talloc_steal(mem_ctx, tcurl_req); + ret = EOK; done: - if (ret) talloc_free(req); + talloc_free(tmp_ctx); return ret; } @@ -911,8 +990,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, { struct tevent_req *req, *subreq; struct proxy_secret_state *state; + struct tcurl_request *tcurl_req; struct proxy_context *pctx; - struct sec_data *http_req; char *http_uri; int ret; @@ -942,9 +1021,8 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, goto done; } - ret = proxy_http_create_request(state, state->secreq, state->pcfg, - http_uri, &http_req); + http_uri, &tcurl_req); if (ret) { DEBUG(SSSDBG_CRIT_FAILURE, "proxy_http_create_request failed [%d]: %s\n", @@ -952,10 +1030,9 @@ struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx, goto done; } - - subreq = proxy_http_req_send(pctx, state, ev, state->secreq, - http_uri, http_req); - if (!subreq) { + subreq = tcurl_request_send(mem_ctx, ev, pctx->tcurl, tcurl_req, + SEC_PROXY_TIMEOUT); + if (subreq == NULL) { ret = ENOMEM; goto done; } @@ -981,32 +1058,30 @@ static void proxy_secret_req_done(struct tevent_req *subreq) { struct tevent_req *req; struct proxy_secret_state *state; - struct proxy_http_reply *reply = NULL; + struct sss_iobuf *response; + int http_code; int ret; req = tevent_req_callback_data(subreq, struct tevent_req); state = tevent_req_data(req, struct proxy_secret_state); - ret = proxy_http_req_recv(subreq, state, &reply); + ret = tcurl_request_recv(state, subreq, &response, &http_code); talloc_zfree(subreq); if (ret != EOK) { - DEBUG(SSSDBG_OP_FAILURE, - "proxy_http request failed [%d]: %s\n", + DEBUG(SSSDBG_OP_FAILURE, "proxy_http request failed [%d]: %s\n", ret, sss_strerror(ret)); tevent_req_error(req, ret); return; } - ret = sec_http_reply_with_headers(state->secreq, &state->secreq->reply, - reply->status_code, reply->reason_phrase, - reply->headers, reply->num_headers, - &reply->body); + ret = sec_http_reply_iobuf(state->secreq, &state->secreq->reply, + http_code, response); if (ret == EOK) { tevent_req_done(req); } else { DEBUG(SSSDBG_OP_FAILURE, - "sec_http_reply_with_headers request failed [%d]: %s\n", + "sec_http_reply_iobuf request failed [%d]: %s\n", ret, sss_strerror(ret)); tevent_req_error(req, ret); } @@ -1034,6 +1109,11 @@ int proxy_secrets_provider_handle(struct sec_ctx *sctx, pctx->resctx = sctx->resctx; pctx->cdb = sctx->rctx->cdb; + pctx->tcurl = tcurl_init(pctx, sctx->rctx->ev); + if (pctx->tcurl == NULL) { + talloc_free(pctx); + return ENOMEM; + } handle->context = pctx; diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h index a8544f656517a17fe4576247779bff4850beaf97..2e68628f61a0a8e79cd48fb5a510221e6fc36c70 100644 --- a/src/responder/secrets/secsrv_private.h +++ b/src/responder/secrets/secsrv_private.h @@ -25,6 +25,7 @@ #include "config.h" #include "responder/common/responder.h" #include "responder/secrets/secsrv.h" +#include "util/sss_iobuf.h" #include struct sec_kvp { @@ -129,6 +130,10 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, int status_code, const char *reason, struct sec_kvp *headers, int num_headers, struct sec_data *body); +errno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx, + struct sec_data *reply, + int response_code, + struct sss_iobuf *response); enum sec_http_status_codes sec_errno_to_http_status(errno_t err); int sec_json_to_simple_secret(TALLOC_CTX *mem_ctx, -- 2.9.3