diff options
author | Pavel Březina <pbrezina@redhat.com> | 2017-02-22 10:38:56 +0100 |
---|---|---|
committer | Lukas Slebodnik <lslebodn@redhat.com> | 2017-03-30 19:07:50 +0200 |
commit | df99d709c8cbef3c378c111944d83b7345e4c1ea (patch) | |
tree | d6863c37d1c673422ccf5edce724b75c26214b1b /src/responder/secrets | |
parent | 793f2573b2beaf8b48eab850429482acf68ec2b1 (diff) | |
download | sssd-df99d709c8cbef3c378c111944d83b7345e4c1ea.tar.gz sssd-df99d709c8cbef3c378c111944d83b7345e4c1ea.tar.xz sssd-df99d709c8cbef3c378c111944d83b7345e4c1ea.zip |
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 <simo@redhat.com>
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Diffstat (limited to 'src/responder/secrets')
-rw-r--r-- | src/responder/secrets/providers.c | 20 | ||||
-rw-r--r-- | src/responder/secrets/proxy.c | 248 | ||||
-rw-r--r-- | src/responder/secrets/secsrv_private.h | 5 |
3 files changed, 189 insertions, 84 deletions
diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c index 94831c730..80a443d91 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 <jansson.h> 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 3ed03e608..fe2f0134e 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; + 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; + } - 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; 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); - - 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; + DEBUG(SSSDBG_TRACE_LIBS, "Forwarding header %s\n", + pcfg->auth.header.name); + + 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; - - req = talloc_zero(mem_ctx, struct sec_data); - if (!req) return ENOMEM; + TALLOC_CTX *tmp_ctx; + struct tcurl_request *tcurl_req; + enum tcurl_http_method method; + struct sss_iobuf *body; + const char **headers; + errno_t ret; + + 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 a8544f656..2e68628f6 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 <http_parser.h> 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, |