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

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