387014f928
required for building freeipa-4.5.x in rawhide
459 lines
15 KiB
Diff
459 lines
15 KiB
Diff
From df99d709c8cbef3c378c111944d83b7345e4c1ea Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
|
|
Date: Wed, 22 Feb 2017 10:38:56 +0100
|
|
Subject: [PATCH 86/97] 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>
|
|
---
|
|
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 <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 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 <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,
|
|
--
|
|
2.12.2
|
|
|