Blame SOURCES/0083-secrets-use-tcurl-in-proxy-provider.patch

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