summaryrefslogtreecommitdiffstats
path: root/src/responder
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2016-05-09 18:31:31 +0200
committerJakub Hrozek <jhrozek@redhat.com>2016-06-29 21:46:55 +0200
commit8f2a34cc6964a1f80a1434e05315a7ae0bb5774e (patch)
tree4dc176746c2abbd95b43a238f0a4b643feca49c4 /src/responder
parent625bb2ddf15e8f305a53afa44e87f2146fa930af (diff)
downloadsssd-8f2a34cc6964a1f80a1434e05315a7ae0bb5774e.tar.gz
sssd-8f2a34cc6964a1f80a1434e05315a7ae0bb5774e.tar.xz
sssd-8f2a34cc6964a1f80a1434e05315a7ae0bb5774e.zip
Secrets: Add Proxy backend
Signed-off-by: Simo Sorce <simo@redhat.com> Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
Diffstat (limited to 'src/responder')
-rw-r--r--src/responder/secrets/local.c75
-rw-r--r--src/responder/secrets/providers.c129
-rw-r--r--src/responder/secrets/proxy.c977
-rw-r--r--src/responder/secrets/secsrv.c7
-rw-r--r--src/responder/secrets/secsrv.h7
-rw-r--r--src/responder/secrets/secsrv_cmd.c8
-rw-r--r--src/responder/secrets/secsrv_local.h4
-rw-r--r--src/responder/secrets/secsrv_private.h24
-rw-r--r--src/responder/secrets/secsrv_proxy.h28
9 files changed, 1199 insertions, 60 deletions
diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c
index 5c99c1877..6451ef95b 100644
--- a/src/responder/secrets/local.c
+++ b/src/responder/secrets/local.c
@@ -506,57 +506,56 @@ int generate_master_key(const char *filename, size_t size)
return EOK;
}
-/* FIXME: allocate on the responder context */
-static struct provider_handle local_secrets_handle = {
- .fn = local_secret_req,
- .context = NULL,
-};
-
-int local_secrets_provider_handle(TALLOC_CTX *mem_ctx,
- struct provider_handle **handle)
+int local_secrets_provider_handle(struct sec_ctx *sctx,
+ struct provider_handle **out_handle)
{
+ const char *mkey = SECRETS_DB_PATH"/.secrets.mkey";
+ const char *dbpath = SECRETS_DB_PATH"/secrets.ldb";
+ struct provider_handle *handle;
struct local_context *lctx;
+ ssize_t size;
+ int mfd;
int ret;
- if (local_secrets_handle.context == NULL) {
- const char *mkey = SECRETS_DB_PATH"/.secrets.mkey";
- ssize_t size;
- int mfd;
+ handle = talloc_zero(sctx, struct provider_handle);
+ if (!handle) return ENOMEM;
- lctx = talloc_zero(NULL, struct local_context);
- if (!lctx) return ENOMEM;
+ handle->name = "LOCAL";
+ handle->fn = local_secret_req;
- lctx->ldb = ldb_init(lctx, NULL);
- if (!lctx->ldb) return ENOMEM;
+ lctx = talloc_zero(handle, struct local_context);
+ if (!lctx) return ENOMEM;
- ret = ldb_connect(lctx->ldb, SECRETS_DB_PATH"/secrets.ldb", 0, NULL);
- if (ret != LDB_SUCCESS) {
- talloc_free(lctx->ldb);
- return EIO;
- }
+ lctx->ldb = ldb_init(lctx, NULL);
+ if (!lctx->ldb) return ENOMEM;
+
+ ret = ldb_connect(lctx->ldb, dbpath, 0, NULL);
+ if (ret != LDB_SUCCESS) {
+ talloc_free(lctx->ldb);
+ return EIO;
+ }
- lctx->master_key.data = talloc_size(lctx, MKEY_SIZE);
- if (!lctx->master_key.data) return ENOMEM;
- lctx->master_key.length = MKEY_SIZE;
+ lctx->master_key.data = talloc_size(lctx, MKEY_SIZE);
+ if (!lctx->master_key.data) return ENOMEM;
+ lctx->master_key.length = MKEY_SIZE;
+ ret = check_and_open_readonly(mkey, &mfd, 0, 0,
+ S_IFREG|S_IRUSR|S_IWUSR, 0);
+ if (ret == ENOENT) {
+ ret = generate_master_key(mkey, MKEY_SIZE);
+ if (ret) return EFAULT;
ret = check_and_open_readonly(mkey, &mfd, 0, 0,
S_IFREG|S_IRUSR|S_IWUSR, 0);
- if (ret == ENOENT) {
- ret = generate_master_key(mkey, MKEY_SIZE);
- if (ret) return EFAULT;
- ret = check_and_open_readonly(mkey, &mfd, 0, 0,
- S_IFREG|S_IRUSR|S_IWUSR, 0);
- }
- if (ret) return EFAULT;
+ }
+ if (ret) return EFAULT;
- size = sss_atomic_io_s(mfd, lctx->master_key.data,
- lctx->master_key.length, true);
- close(mfd);
- if (size < 0 || size != lctx->master_key.length) return EIO;
+ size = sss_atomic_io_s(mfd, lctx->master_key.data,
+ lctx->master_key.length, true);
+ close(mfd);
+ if (size < 0 || size != lctx->master_key.length) return EIO;
- local_secrets_handle.context = lctx;
- }
+ handle->context = lctx;
- *handle = &local_secrets_handle;
+ *out_handle = handle;
return EOK;
}
diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c
index b641ebef8..5dff01a7f 100644
--- a/src/responder/secrets/providers.c
+++ b/src/responder/secrets/providers.c
@@ -21,6 +21,7 @@
#include "responder/secrets/secsrv_private.h"
#include "responder/secrets/secsrv_local.h"
+#include "responder/secrets/secsrv_proxy.h"
#include <jansson.h>
int sec_map_url_to_user_path(struct sec_req_ctx *secreq, char **mapped_path)
@@ -46,14 +47,15 @@ int sec_map_url_to_user_path(struct sec_req_ctx *secreq, char **mapped_path)
int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
struct provider_handle **handle)
{
+ struct sec_ctx *sctx;
char **sections;
char *def_provider;
char *provider;
- const char *upath;
- int ulen;
int num_sections;
int ret;
+ sctx = talloc_get_type(secreq->cctx->rctx->pvt_ctx, struct sec_ctx);
+
/* patch must start with /secrets/ for now */
ret = strncasecmp(secreq->parsed_url.path,
SEC_BASEPATH, sizeof(SEC_BASEPATH) - 1);
@@ -79,12 +81,16 @@ int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
if (ret != EOK) return ret;
provider = def_provider;
- upath = &secreq->parsed_url.path[sizeof(SEC_BASEPATH) - 1];
- ulen = strlen(upath);
// TODO order by length ?
- for (int i = 0; ulen > 0 && i < num_sections; i++) {
- if (strncmp(sections[i], upath, ulen) == 0) {
+ for (int i = 0; i < num_sections; i++) {
+ int slen;
+
+ secreq->base_path = talloc_asprintf(secreq, SEC_BASEPATH"%s/", sections[i]);
+ if (!secreq->base_path) return ENOMEM;
+ slen = strlen(secreq->base_path);
+
+ if (strncmp(secreq->base_path, secreq->mapped_path, slen) == 0) {
char *secname;
secname = talloc_asprintf(mem_ctx, CONFDB_SEC_CONF_ENTRY"/%s",
@@ -98,19 +104,31 @@ int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
if (ret || !provider) return EIO;
secreq->cfg_section = talloc_steal(secreq, secname);
+ if (!secreq->cfg_section) return ENOMEM;
break;
}
+ talloc_zfree(secreq->base_path);
}
- if (strcasecmp(provider, "LOCAL") == 0) {
- return local_secrets_provider_handle(mem_ctx, handle);
- } else {
- DEBUG(SSSDBG_FATAL_FAILURE,
- "Unknown provider type: %s\n", provider);
- return EIO;
+ if (!secreq->base_path) secreq->base_path = SEC_BASEPATH;
+
+ ret = sec_get_provider(sctx, provider, handle);
+ if (ret == ENOENT) {
+ if (strcasecmp(provider, "LOCAL") == 0) {
+ ret = local_secrets_provider_handle(sctx, handle);
+ } else if (strcasecmp(provider, "PROXY") == 0) {
+ ret = proxy_secrets_provider_handle(sctx, handle);
+ } else {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Unknown provider type: %s\n", provider);
+ ret = EIO;
+ }
+ if (ret == EOK) {
+ ret = sec_add_provider(sctx, *handle);
+ }
}
- return EINVAL;
+ return ret;
}
int sec_provider_recv(struct tevent_req *req) {
@@ -204,6 +222,58 @@ int sec_http_reply_with_body(TALLOC_CTX *mem_ctx, struct sec_data *reply,
return EOK;
}
+int sec_http_append_header(TALLOC_CTX *mem_ctx, char **dest,
+ char *field, char *value)
+{
+ if (*dest == NULL) {
+ *dest = talloc_asprintf(mem_ctx, "%s: %s\r\n", field, value);
+ } else {
+ *dest = talloc_asprintf_append_buffer(*dest, "%s: %s\r\n",
+ field, value);
+ }
+ if (!*dest) return ENOMEM;
+
+ return EOK;
+}
+
+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)
+{
+ const char *reason_phrase = reason ? reason : "";
+ int ret;
+
+ /* Status-Line */
+ reply->data = talloc_asprintf(mem_ctx, "HTTP/1.1 %d %s\r\n",
+ status_code, reason_phrase);
+ if (!reply->data) return ENOMEM;
+
+ /* Headers */
+ for (int i = 0; i < num_headers; i++) {
+ ret = sec_http_append_header(mem_ctx, &reply->data,
+ headers[i].name, headers[i].value);
+ if (ret) return ret;
+ }
+
+ /* CRLF separator before body */
+ reply->data = talloc_strdup_append_buffer(reply->data, "\r\n");
+
+ reply->length = strlen(reply->data);
+
+ /* Message-Body */
+ if (body && body->length) {
+ reply->data = talloc_realloc(mem_ctx, reply->data, char,
+ reply->length + body->length);
+ if (!reply->data) return ENOMEM;
+
+ memcpy(&reply->data[reply->length], body->data, body->length);
+ reply->length += body->length;
+ }
+
+ return EOK;
+}
+
enum sec_http_status_codes sec_errno_to_http_status(errno_t err)
{
switch (err) {
@@ -358,3 +428,36 @@ done:
free(jsonized);
return ret;
}
+
+int sec_get_provider(struct sec_ctx *sctx, const char *name,
+ struct provider_handle **out_handle)
+{
+ struct provider_handle *handle;
+
+ for (int i = 0; sctx->providers && sctx->providers[i]; i++) {
+ handle = sctx->providers[i];
+ if (strcasecmp(handle->name, name) != 0) {
+ continue;
+ }
+ *out_handle = handle;
+ return EOK;
+ }
+ return ENOENT;
+}
+
+int sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle)
+{
+ int c;
+
+ for (c = 0; sctx->providers && sctx->providers[c]; c++)
+ continue;
+
+ sctx->providers = talloc_realloc(sctx, sctx->providers,
+ struct provider_handle *, c + 2);
+ if (!sctx->providers) return ENOMEM;
+
+ sctx->providers[c] = talloc_steal(sctx, handle);
+ sctx->providers[c + 1] = NULL;
+
+ return EOK;
+}
diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c
new file mode 100644
index 000000000..13321c13e
--- /dev/null
+++ b/src/responder/secrets/proxy.c
@@ -0,0 +1,977 @@
+/*
+ SSSD
+
+ Secrets Responder
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "responder/secrets/secsrv_private.h"
+#include "util/crypto/sss_crypto.h"
+#include "resolv/async_resolv.h"
+#include "util/sss_sockets.h"
+
+struct proxy_context {
+ struct resolv_ctx *resctx;
+ struct confdb_ctx *cdb;
+};
+
+enum proxy_auth_type {
+ PAT_NONE = 0,
+ PAT_BASIC_AUTH = 1,
+ PAT_HEADER = 2,
+};
+
+struct pat_basic_auth {
+ char *username;
+ char *password;
+};
+
+struct pat_header {
+ char *name;
+ char *value;
+};
+
+struct proxy_cfg {
+ char *url;
+ char **fwd_headers;
+ int num_headers;
+ enum proxy_auth_type auth_type;
+ union {
+ struct pat_basic_auth basic;
+ struct pat_header header;
+ } auth;
+};
+
+static int proxy_get_config_string(struct proxy_context *pctx,
+ TALLOC_CTX *ctx, bool not_null,
+ struct sec_req_ctx *secreq,
+ const char *name, char **value)
+{
+ int ret;
+
+ ret = confdb_get_string(pctx->cdb, ctx,
+ secreq->cfg_section, name, NULL, value);
+ if (not_null && (ret == 0) && (*value == NULL)) ret = EINVAL;
+ return ret;
+}
+
+static int proxy_sec_get_cfg(struct proxy_context *pctx,
+ TALLOC_CTX *mem_ctx,
+ struct sec_req_ctx *secreq,
+ struct proxy_cfg **target)
+{
+ struct proxy_cfg *cfg;
+ char *auth_type;
+ int ret;
+
+ /* find matching remote and build the URI */
+ cfg = talloc_zero(mem_ctx, struct proxy_cfg);
+ if (!cfg) return ENOMEM;
+
+ ret = proxy_get_config_string(pctx, cfg, true, secreq,
+ "proxy_url", &cfg->url);
+ if (ret) goto done;
+
+ ret = proxy_get_config_string(pctx, cfg, false, secreq,
+ "auth_type", &auth_type);
+ if (ret) goto done;
+
+ if (auth_type) {
+ if (strcmp(auth_type, "basic_auth") == 0) {
+ cfg->auth_type = PAT_BASIC_AUTH;
+ ret = proxy_get_config_string(pctx, cfg, true, secreq, "username",
+ &cfg->auth.basic.username);
+ if (ret) goto done;
+ ret = proxy_get_config_string(pctx, cfg, true, secreq, "password",
+ &cfg->auth.basic.password);
+ if (ret) goto done;
+ } else if (strcmp(auth_type, "header") == 0) {
+ cfg->auth_type = PAT_HEADER;
+ ret = proxy_get_config_string(pctx, cfg, true, secreq,
+ "auth_header_name",
+ &cfg->auth.header.name);
+ if (ret) goto done;
+ ret = proxy_get_config_string(pctx, cfg, true, secreq,
+ "auth_header_value",
+ &cfg->auth.header.value);
+ if (ret) goto done;
+ } else {
+ ret = EINVAL;
+ goto done;
+ }
+ }
+
+ ret = confdb_get_string_as_list(pctx->cdb, cfg, secreq->cfg_section,
+ "forward_headers", &cfg->fwd_headers);
+ if ((ret != 0) && (ret != ENOENT)) goto done;
+
+ while (cfg->fwd_headers && cfg->fwd_headers[cfg->num_headers]) {
+ cfg->num_headers++;
+ }
+
+ /* Always whitelist Content-Type and Content-Length */
+ cfg->fwd_headers = talloc_realloc(cfg, cfg->fwd_headers, char *,
+ cfg->num_headers + 3);
+ if (!cfg->fwd_headers) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cfg->fwd_headers[cfg->num_headers] = talloc_strdup(cfg, "Content-Type");
+ if (!cfg->fwd_headers[cfg->num_headers]) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cfg->num_headers++;
+ cfg->fwd_headers[cfg->num_headers] = talloc_strdup(cfg, "Content-Length");
+ if (!cfg->fwd_headers[cfg->num_headers]) {
+ ret = ENOMEM;
+ goto done;
+ }
+ cfg->num_headers++;
+ cfg->fwd_headers[cfg->num_headers] = NULL;
+ ret = EOK;
+
+done:
+ if (ret) talloc_free(cfg);
+ else *target = cfg;
+ return ret;
+}
+
+#define REQ_HAS_SCHEMA(secreq) ((secreq)->parsed_url.schema != NULL)
+#define REQ_HAS_HOST(secreq) ((secreq)->parsed_url.host != NULL)
+#define REQ_HAS_PORT(secreq) ((secreq)->parsed_url.port != 0)
+#define REQ_HAS_PATH(secreq) ((secreq)->parsed_url.path != NULL)
+#define REQ_HAS_QUERY(secreq) ((secreq)->parsed_url.query != NULL)
+#define REQ_HAS_FRAGMENT(secreq) ((secreq)->parsed_url.fragment != NULL)
+#define REQ_HAS_USERINFO(secreq) ((secreq)->parsed_url.userinfo != NULL)
+
+#define SECREQ_HAS_PORT(secreq) ((secreq)->parsed_url.port != 0)
+#define SECREQ_PORT(secreq) ((secreq)->parsed_url.port)
+
+#define SECREQ_HAS_PART(secreq, part) ((secreq)->parsed_url.part != NULL)
+#define SECREQ_PART(secreq, part) \
+ ((secreq)->parsed_url.part ? (secreq)->parsed_url.part : "")
+
+int proxy_sec_map_url(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
+ struct proxy_cfg *pcfg, char **req_url)
+{
+ char port[6] = { 0 };
+ char *url;
+ int blen;
+ int ret;
+
+ if (SECREQ_HAS_PORT(secreq)) {
+ ret = snprintf(port, 6, "%d", SECREQ_PORT(secreq));
+ if (ret < 1 || ret > 5) return EINVAL;
+ }
+
+ blen = strlen(secreq->base_path);
+
+ url = talloc_asprintf(mem_ctx, "%s%s%s%s%s%s%s%s/%s%s%s%s%s",
+ SECREQ_PART(secreq, schema),
+ SECREQ_HAS_PART(secreq, schema) ? "://" : "",
+ SECREQ_PART(secreq, userinfo),
+ SECREQ_HAS_PART(secreq, userinfo) ? "@" : "",
+ SECREQ_PART(secreq, host),
+ SECREQ_HAS_PORT(secreq) ? ":" : "",
+ SECREQ_HAS_PORT(secreq) ? port : "",
+ pcfg->url, &secreq->mapped_path[blen],
+ SECREQ_HAS_PART(secreq, query) ? "?" :"",
+ SECREQ_PART(secreq, query),
+ SECREQ_HAS_PART(secreq, fragment) ? "?" :"",
+ SECREQ_PART(secreq, fragment));
+ if (!url) return ENOMEM;
+
+ *req_url = url;
+ return EOK;
+}
+
+int proxy_sec_map_headers(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
+ struct proxy_cfg *pcfg, char **req_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;
+ break;
+ }
+ }
+ if (forward) {
+ ret = sec_http_append_header(mem_ctx, req_headers,
+ secreq->headers[i].name,
+ secreq->headers[i].value);
+ if (ret) return ret;
+ }
+ }
+
+ if (pcfg->auth_type == PAT_HEADER) {
+ ret = sec_http_append_header(mem_ctx, req_headers,
+ pcfg->auth.header.name,
+ pcfg->auth.header.value);
+ if (ret) return ret;
+ }
+
+ return EOK;
+}
+
+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)
+{
+ struct sec_data *req;
+ int ret;
+
+ req = talloc_zero(mem_ctx, struct sec_data);
+ if (!req) 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) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ /* Headers */
+ ret = proxy_sec_map_headers(req, secreq, pcfg, &req->data);
+ if (ret) goto done;
+
+ /* CRLF separator before body */
+ req->data = talloc_strdup_append_buffer(req->data, "\r\n");
+
+ req->length = strlen(req->data);
+
+ /* 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;
+ }
+
+ memcpy(&req->data[req->length],
+ secreq->body.data, secreq->body.length);
+ req->length += secreq->body.length;
+ }
+
+ *http_req = req;
+ ret = EOK;
+
+done:
+ if (ret) talloc_free(req);
+ return ret;
+}
+
+struct proxy_http_request {
+ struct sec_data *data;
+ size_t written;
+};
+
+struct proxy_http_reply {
+ http_parser parser;
+ bool complete;
+
+ int status_code;
+ char *reason_phrase;
+ struct sec_kvp *headers;
+ int num_headers;
+ struct sec_data body;
+
+ size_t received;
+};
+
+struct proxy_http_req_state {
+ struct tevent_context *ev;
+
+ char *proxyname;
+ int port;
+
+ struct resolv_hostent *hostent;
+ int hostidx;
+
+ int sd;
+ struct tevent_fd *fde;
+
+ struct proxy_http_request request;
+ struct proxy_http_reply *reply;
+};
+
+static int proxy_http_req_state_destroy(void *data);
+static void proxy_http_req_gethostname_done(struct tevent_req *subreq);
+static void proxy_http_req_connect_step(struct tevent_req *req);
+static void proxy_http_req_connect_done(struct tevent_req *subreq);
+static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *ptr);
+
+struct tevent_req *proxy_http_req_send(struct proxy_context *pctx,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct sec_req_ctx *secreq,
+ const char *http_uri,
+ struct sec_data *http_req)
+{
+ struct proxy_http_req_state *state;
+ struct http_parser_url parsed;
+ struct tevent_req *req, *subreq;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct proxy_http_req_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->request.data = http_req;
+ state->sd = -1;
+ talloc_set_destructor((TALLOC_CTX *)state,
+ proxy_http_req_state_destroy);
+
+ /* STEP1: reparse URL to get hostname and port */
+ ret = http_parser_parse_url(http_uri, strlen(http_uri), 0, &parsed);
+ if (ret) goto done;
+
+ if (!(parsed.field_set & (1 << UF_HOST))) {
+ ret = EINVAL;
+ goto done;
+ }
+ state->proxyname =
+ talloc_strndup(state,
+ &http_uri[parsed.field_data[UF_HOST].off],
+ parsed.field_data[UF_HOST].len);
+ if (!state->proxyname) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ if (parsed.field_set & (1 << UF_PORT)) {
+ state->port = parsed.port;
+ } else if (parsed.field_set & (1 << UF_SCHEMA)) {
+ uint16_t off = parsed.field_data[UF_SCHEMA].off;
+ uint16_t len = parsed.field_data[UF_SCHEMA].len;
+
+ if ((len == 5) &&
+ (strncmp("https", &http_uri[off], len) == 0)) {
+ state->port = 443;
+ } else if ((len == 4) &&
+ (strncmp("http", &http_uri[off], len) == 0)) {
+ state->port = 80;
+ }
+ }
+
+ /* STEP2: resolve hostname first */
+ subreq = resolv_gethostbyname_send(state, ev, pctx->resctx,
+ state->proxyname, IPV4_FIRST,
+ default_host_dbs);
+ if (subreq == NULL) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, proxy_http_req_gethostname_done, req);
+
+ return req;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+ tevent_req_post(req, ev);
+
+ return req;
+}
+
+static void proxy_http_req_gethostname_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct proxy_http_req_state *state;
+ int resolv_status;
+ int ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct proxy_http_req_state);
+
+ ret = resolv_gethostbyname_recv(subreq, state, &resolv_status, NULL,
+ &state->hostent);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ if (ret == ENOENT) {
+ /* Empty result, just quit */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "No hostent found\n");
+ } else {
+ DEBUG(SSSDBG_OP_FAILURE,
+ "Could not resolve fqdn for this machine, error [%d]: %s, "
+ "resolver returned: [%d]: %s\n", ret, strerror(ret),
+ resolv_status, resolv_strerror(resolv_status));
+ }
+ goto done;
+ }
+
+ /* EOK */
+ DEBUG(SSSDBG_TRACE_INTERNAL, "Found fqdn: %s\n", state->hostent->name);
+
+ /* STEP3: connect to one of the servers */
+ proxy_http_req_connect_step(req);
+ return;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+static void proxy_http_req_connect_step(struct tevent_req *req)
+{
+ struct proxy_http_req_state *state;
+ struct sockaddr_storage *sockaddr;
+ char *ipaddr;
+ struct tevent_req *subreq;
+ int ret;
+
+ state = tevent_req_data(req, struct proxy_http_req_state);
+
+ if (!state->hostent->addr_list[state->hostidx]) {
+ DEBUG(SSSDBG_CRIT_FAILURE, "No more addresses to try.\n");
+ ret = ENXIO;
+ goto done;
+ }
+
+ sockaddr = resolv_get_sockaddr_address_index(state, state->hostent,
+ state->port, state->hostidx);
+ if (sockaddr == NULL) {
+ DEBUG(SSSDBG_OP_FAILURE, "resolv_get_sockaddr_address() failed\n");
+ ret = EIO;
+ goto done;
+ }
+
+ if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
+ ipaddr = resolv_get_string_address_index(state, state->hostent,
+ state->hostidx);
+ if (!ipaddr) {
+ ret = EFAULT;
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_FUNC, "Connecting to %s:%d\n",
+ ipaddr, state->port);
+ }
+
+ /* increase idx for next attempt */
+ state->hostidx++;
+
+ subreq = sssd_async_socket_init_send(state, state->ev, sockaddr,
+ sizeof(struct sockaddr_storage),
+ SEC_NET_TIMEOUT);
+ if (!subreq) {
+ ret = EIO;
+ goto done;
+ }
+ tevent_req_set_callback(subreq, proxy_http_req_connect_done, req);
+ return;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+static void proxy_http_req_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct proxy_http_req_state *state;
+ int ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct proxy_http_req_state);
+
+ ret = sssd_async_socket_init_recv(subreq, &state->sd);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_CRIT_FAILURE,
+ "sssd_async_socket_init request failed: [%d]: %s.\n",
+ ret, sss_strerror(ret));
+
+ /* try next server if any */
+ proxy_http_req_connect_step(req);
+ return;
+ }
+
+ /* EOK */
+ DEBUG(SSSDBG_TRACE_FUNC, "Connected to %s\n", state->hostent->name);
+
+ state->fde = tevent_add_fd(state->ev, state, state->sd,
+ TEVENT_FD_WRITE, proxy_fd_handler,
+ req);
+ if (!state->fde) {
+ ret = EIO;
+ goto done;
+ }
+
+ return;
+
+done:
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+
+int proxy_http_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+ struct proxy_http_reply **reply)
+{
+ struct proxy_http_req_state *state =
+ tevent_req_data(req, struct proxy_http_req_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *reply = talloc_move(mem_ctx, &state->reply);
+
+ return EOK;
+}
+
+static int proxy_http_req_state_destroy(void *data)
+{
+ struct proxy_http_req_state *state =
+ talloc_get_type(data, struct proxy_http_req_state);
+
+ if (!state) return 0;
+
+ if (state->sd != -1) {
+ DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
+ close(state->sd);
+ state->sd = -1;
+ }
+
+ return 0;
+}
+
+static int proxy_wire_send(int fd, struct proxy_http_request *req)
+{
+ struct sec_data data;
+ size_t ret;
+
+ data.data = req->data->data + req->written;
+ data.length = req->data->length - req->written;
+
+ ret = sec_send_data(fd, &data);
+ if (ret != EOK && ret != EAGAIN) return ret;
+
+ req->written = req->data->length - data.length;
+ return ret;
+}
+
+static void proxy_fd_send(void *data)
+{
+ struct proxy_http_req_state *state;
+ struct tevent_req * req;
+ int ret;
+
+ req = talloc_get_type(data, struct tevent_req);
+ state = tevent_req_data(req, struct proxy_http_req_state);
+
+ ret = proxy_wire_send(state->sd, &state->request);
+ if (ret == EAGAIN) {
+ /* not all data was sent, loop again */
+ return;
+ }
+ if (ret != EOK) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting!\n");
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* ok all sent, wait for reply now */
+ TEVENT_FD_NOT_WRITEABLE(state->fde);
+ TEVENT_FD_READABLE(state->fde);
+ return;
+}
+
+static bool ph_received_data(struct proxy_http_reply *reply, size_t length)
+{
+ reply->received += length;
+ if (reply->received > SEC_REQUEST_MAX_SIZE) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Request too big, aborting!\n");
+ return true;
+ }
+ return false;
+}
+
+static void ph_append_string(TALLOC_CTX *memctx, char **dest,
+ const char *src, size_t len)
+{
+ if (*dest) {
+ *dest = talloc_strndup_append_buffer(*dest, src, len);
+ } else {
+ *dest = talloc_strndup(memctx, src, len);
+ }
+}
+
+static int ph_on_message_begin(http_parser *parser)
+{
+ DEBUG(SSSDBG_TRACE_INTERNAL, "HTTP Message parsing begins\n");
+ return 0;
+}
+
+#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2))
+static int ph_on_status(http_parser *parser, const char *at, size_t length)
+{
+ struct proxy_http_reply *reply =
+ talloc_get_type(parser->data, struct proxy_http_reply);
+
+ if (ph_received_data(reply, length)) return -1;
+
+ ph_append_string(reply, &reply->reason_phrase, at, length);
+ if (!reply->reason_phrase) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to store reason phrase, aborting client!\n");
+ return -1;
+ }
+
+ return 0;
+}
+#endif
+
+static int ph_on_header_field(http_parser *parser,
+ const char *at, size_t length)
+{
+ struct proxy_http_reply *reply =
+ talloc_get_type(parser->data, struct proxy_http_reply);
+ int n = reply->num_headers;
+
+ if (ph_received_data(reply, length)) return -1;
+
+ if (!reply->headers) {
+ reply->headers = talloc_zero_array(reply, struct sec_kvp, 10);
+ } else if ((n % 10 == 0) &&
+ (reply->headers[n - 1].value)) {
+ reply->headers = talloc_realloc(reply, reply->headers,
+ struct sec_kvp, n + 10);
+ if (reply->headers) {
+ memset(&reply->headers[n], 0, sizeof(struct sec_kvp) * 10);
+ }
+ }
+ if (!reply->headers) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to store headers, aborting client!\n");
+ return -1;
+ }
+
+ if (!n || reply->headers[n - 1].value) {
+ /* new field */
+ n++;
+ }
+ ph_append_string(reply->headers, &reply->headers[n - 1].name, at, length);
+ if (!reply->headers[n - 1].name) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to store header name, aborting client!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ph_on_header_value(http_parser *parser,
+ const char *at, size_t length)
+{
+ struct proxy_http_reply *reply =
+ talloc_get_type(parser->data, struct proxy_http_reply);
+ int n = reply->num_headers;
+
+ if (ph_received_data(reply, length)) return -1;
+
+ if (!reply->headers) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Invalid headers pointer, aborting client!\n");
+ return -1;
+ }
+
+ if (reply->headers[n].name && !reply->headers[n].value) {
+ /* we increment on new value */
+ n = ++reply->num_headers;
+ }
+
+ ph_append_string(reply->headers, &reply->headers[n - 1].value, at, length);
+ if (!reply->headers[n - 1].value) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to store header value, aborting client!\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int ph_on_headers_complete(http_parser *parser)
+{
+ /* TODO: if message has no body we should return 1 */
+ return 0;
+}
+
+static int ph_on_body(http_parser *parser, const char *at, size_t length)
+{
+ struct proxy_http_reply *reply =
+ talloc_get_type(parser->data, struct proxy_http_reply);
+
+ if (ph_received_data(reply, length)) return -1;
+
+ /* FIXME: body may be binary */
+ ph_append_string(reply, &reply->body.data, at, length);
+ if (!reply->body.data) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to store body, aborting!\n");
+ return -1;
+ }
+ reply->body.length += length;
+
+ return 0;
+}
+
+static int ph_on_message_complete(http_parser *parser)
+{
+ struct proxy_http_reply *reply =
+ talloc_get_type(parser->data, struct proxy_http_reply);
+
+ reply->status_code = parser->status_code;
+ reply->complete = true;
+
+ return 0;
+}
+
+static http_parser_settings ph_callbacks = {
+ .on_message_begin = ph_on_message_begin,
+#if ((HTTP_PARSER_VERSION_MAJOR >= 2) && (HTTP_PARSER_VERSION_MINOR >= 2))
+ .on_status = ph_on_status,
+#endif
+ .on_header_field = ph_on_header_field,
+ .on_header_value = ph_on_header_value,
+ .on_headers_complete = ph_on_headers_complete,
+ .on_body = ph_on_body,
+ .on_message_complete = ph_on_message_complete
+};
+
+static void proxy_fd_recv(void *data)
+{
+ char buffer[SEC_PACKET_MAX_RECV_SIZE];
+ struct sec_data packet = { buffer,
+ SEC_PACKET_MAX_RECV_SIZE };
+ struct proxy_http_req_state *state;
+ struct tevent_req *req;
+ bool must_complete = false;
+ int ret;
+
+ req = talloc_get_type(data, struct tevent_req);
+ state = tevent_req_data(req, struct proxy_http_req_state);
+
+ if (!state->reply) {
+ /* A new reply */
+ state->reply = talloc_zero(state, struct proxy_http_reply);
+ if (!state->reply) {
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to allocate reply, aborting!\n");
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ http_parser_init(&state->reply->parser, HTTP_RESPONSE);
+ state->reply->parser.data = state->reply;
+ }
+
+ ret = sec_recv_data(state->sd, &packet);
+ switch (ret) {
+ case ENODATA:
+ DEBUG(SSSDBG_TRACE_ALL, "Server closed connection.\n");
+ /* if we got no content length and the request is not complete,
+ * then 0 length will indicate EOF to the parser, otherwise we
+ * have an error */
+ must_complete = true;
+ break;
+ case EAGAIN:
+ DEBUG(SSSDBG_TRACE_ALL,
+ "Interrupted before any data could be read, retry later\n");
+ return;
+ case EOK:
+ /* all fine */
+ break;
+ default:
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to receive data (%d, %s), aborting\n",
+ ret, sss_strerror(ret));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ ret = http_parser_execute(&state->reply->parser, &ph_callbacks,
+ packet.data, packet.length);
+ if (ret != packet.length) {
+ DEBUG(SSSDBG_FATAL_FAILURE,
+ "Failed to parse request, aborting!\n");
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ if (!state->reply->complete) {
+ if (must_complete) {
+ tevent_req_error(req, EIO);
+ }
+ return;
+ }
+
+ /* do not read anymore, server is done sending */
+ TEVENT_FD_NOT_READABLE(state->fde);
+ tevent_req_done(req);
+}
+
+static void proxy_fd_handler(struct tevent_context *ev, struct tevent_fd *fde,
+ uint16_t flags, void *data)
+{
+ if (flags & TEVENT_FD_READ) {
+ proxy_fd_recv(data);
+ } else if (flags & TEVENT_FD_WRITE) {
+ proxy_fd_send(data);
+ }
+}
+
+struct proxy_secret_state {
+ struct tevent_context *ev;
+ struct sec_req_ctx *secreq;
+ struct proxy_cfg *pcfg;
+};
+static void proxy_secret_req_done(struct tevent_req *subreq);
+
+struct tevent_req *proxy_secret_req(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ void *provider_ctx,
+ struct sec_req_ctx *secreq)
+{
+ struct tevent_req *req, *subreq;
+ struct proxy_secret_state *state;
+ struct proxy_context *pctx;
+ struct sec_data *http_req;
+ char *http_uri;
+ int ret;
+
+ req = tevent_req_create(mem_ctx, &state, struct proxy_secret_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->secreq = secreq;
+
+ pctx = talloc_get_type(provider_ctx, struct proxy_context);
+ if (!pctx) {
+ ret = EIO;
+ goto done;
+ }
+
+ ret = proxy_sec_get_cfg(pctx, state, state->secreq, &state->pcfg);
+ if (ret) goto done;
+
+ ret = proxy_sec_map_url(state, secreq, state->pcfg, &http_uri);
+ if (ret) goto done;
+
+ ret = proxy_http_create_request(state, state->secreq, state->pcfg,
+ http_uri, &http_req);
+ if (ret) goto done;
+
+ subreq = proxy_http_req_send(pctx, state, ev, state->secreq,
+ http_uri, http_req);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ tevent_req_set_callback(subreq, proxy_secret_req_done, req);
+
+ return req;
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ } else {
+ /* shortcircuit the request here as all called functions are
+ * synchronous and final and no further subrequests have been
+ * made if we get here */
+ tevent_req_done(req);
+ }
+
+ return tevent_req_post(req, ev);
+}
+
+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;
+ 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);
+ talloc_zfree(subreq);
+
+ if (ret != EOK) {
+ 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);
+ if (ret == EOK) {
+ tevent_req_done(req);
+ } else {
+ tevent_req_error(req, ret);
+ }
+}
+
+struct provider_handle proxy_secrets_handle = {
+ .fn = proxy_secret_req,
+ .context = NULL,
+};
+
+int proxy_secrets_provider_handle(struct sec_ctx *sctx,
+ struct provider_handle **out_handle)
+{
+ struct provider_handle *handle;
+ struct proxy_context *pctx;
+
+ handle = talloc_zero(sctx, struct provider_handle);
+ if (!handle) return ENOMEM;
+
+ handle->name = "PROXY";
+ handle->fn = proxy_secret_req;
+
+ pctx = talloc(handle, struct proxy_context);
+ if (!pctx) return ENOMEM;
+
+ pctx->resctx = sctx->resctx;
+ pctx->cdb = sctx->rctx->cdb;
+
+ handle->context = pctx;
+
+ *out_handle = handle;
+ return EOK;
+}
diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c
index 523aa6469..6f8052bdf 100644
--- a/src/responder/secrets/secsrv.c
+++ b/src/responder/secrets/secsrv.c
@@ -26,6 +26,7 @@
#include "responder/common/responder.h"
#include "responder/secrets/secsrv.h"
+#include "resolv/async_resolv.h"
#define DEFAULT_SEC_FD_LIMIT 2048
@@ -115,6 +116,12 @@ static int sec_process_init(TALLOC_CTX *mem_ctx,
goto fail;
}
+ ret = resolv_init(sctx, ev, SEC_NET_TIMEOUT, &sctx->resctx);
+ if (ret != EOK) {
+ /* not fatal for now */
+ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to initialize resolver library\n");
+ }
+
/* Set up file descriptor limits */
responder_set_fd_limit(sctx->fd_limit);
diff --git a/src/responder/secrets/secsrv.h b/src/responder/secrets/secsrv.h
index 91535ae2b..ace30f86a 100644
--- a/src/responder/secrets/secsrv.h
+++ b/src/responder/secrets/secsrv.h
@@ -30,9 +30,16 @@
#include <tevent.h>
#include <ldb.h>
+#define SEC_NET_TIMEOUT 5
+
+struct resctx;
+
struct sec_ctx {
+ struct resolv_ctx *resctx;
struct resp_ctx *rctx;
int fd_limit;
+
+ struct provider_handle **providers;
};
int sec_connection_setup(struct cli_ctx *cctx);
diff --git a/src/responder/secrets/secsrv_cmd.c b/src/responder/secrets/secsrv_cmd.c
index 00f0600d0..58340bae4 100644
--- a/src/responder/secrets/secsrv_cmd.c
+++ b/src/responder/secrets/secsrv_cmd.c
@@ -25,9 +25,6 @@
#include "responder/secrets/secsrv.h"
#include "responder/secrets/secsrv_private.h"
-#define SEC_REQUEST_MAX_SIZE 65536
-#define SEC_PACKET_MAX_RECV_SIZE 8192
-
/* ##### Request Handling ##### */
@@ -376,7 +373,7 @@ static int sec_on_message_complete(http_parser *parser)
/* ##### Communications ##### */
-static int sec_send_data(int fd, struct sec_data *data)
+int sec_send_data(int fd, struct sec_data *data)
{
ssize_t len;
@@ -424,7 +421,7 @@ static void sec_send(struct cli_ctx *cctx)
return;
}
-static int sec_recv_data(int fd, struct sec_data *data)
+int sec_recv_data(int fd, struct sec_data *data)
{
ssize_t len;
@@ -439,6 +436,7 @@ static int sec_recv_data(int fd, struct sec_data *data)
}
if (len == 0) {
+ data->length = 0;
return ENODATA;
}
diff --git a/src/responder/secrets/secsrv_local.h b/src/responder/secrets/secsrv_local.h
index d21b14953..1ec1a343e 100644
--- a/src/responder/secrets/secsrv_local.h
+++ b/src/responder/secrets/secsrv_local.h
@@ -22,7 +22,7 @@
#ifndef __SECSRV_LOCAL_H__
#define __SECSRV_LOCAL_H__
-int local_secrets_provider_handle(TALLOC_CTX *mem_ctx,
- struct provider_handle **handle);
+int local_secrets_provider_handle(struct sec_ctx *sctx,
+ struct provider_handle **out_handle);
#endif /* __SECSRV_LOCAL_H__ */
diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h
index 4b55f645a..ce8cf8216 100644
--- a/src/responder/secrets/secsrv_private.h
+++ b/src/responder/secrets/secsrv_private.h
@@ -24,6 +24,7 @@
#include "config.h"
#include "responder/common/responder.h"
+#include "responder/secrets/secsrv.h"
#include <http_parser.h>
struct sec_kvp {
@@ -58,13 +59,14 @@ struct sec_url {
char *host;
int port;
char *path;
+ char *query;
char *fragment;
char *userinfo;
- char *query;
};
struct sec_req_ctx {
struct cli_ctx *cctx;
+ const char *base_path;
const char *cfg_section;
bool complete;
@@ -73,7 +75,7 @@ struct sec_req_ctx {
char *request_url;
char *mapped_path;
- uint8_t method;
+ enum http_method method;
struct sec_url parsed_url;
struct sec_kvp *headers;
int num_headers;
@@ -88,9 +90,13 @@ typedef struct tevent_req *(*sec_provider_req_t)(TALLOC_CTX *mem_ctx,
struct sec_req_ctx *secreq);
struct provider_handle {
+ const char *name;
sec_provider_req_t fn;
void *context;
};
+int sec_get_provider(struct sec_ctx *sctx, const char *name,
+ struct provider_handle **out_handle);
+int sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle);
#define SEC_BASEPATH "/secrets/"
@@ -99,12 +105,19 @@ int sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
struct provider_handle **handle);
int sec_provider_recv(struct tevent_req *subreq);
+int sec_http_append_header(TALLOC_CTX *mem_ctx, char **dest,
+ char *field, char *value);
+
int sec_http_status_reply(TALLOC_CTX *mem_ctx, struct sec_data *reply,
enum sec_http_status_codes code);
int sec_http_reply_with_body(TALLOC_CTX *mem_ctx, struct sec_data *reply,
enum sec_http_status_codes code,
const char *content_type,
struct sec_data *body);
+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);
enum sec_http_status_codes sec_errno_to_http_status(errno_t err);
int sec_json_to_simple_secret(TALLOC_CTX *mem_ctx,
@@ -118,4 +131,11 @@ int sec_array_to_json(TALLOC_CTX *mem_ctx,
char **array, int count,
char **output);
+/* secsrv_cmd.c */
+#define SEC_REQUEST_MAX_SIZE 65536
+#define SEC_PACKET_MAX_RECV_SIZE 8192
+
+int sec_send_data(int fd, struct sec_data *data);
+int sec_recv_data(int fd, struct sec_data *data);
+
#endif /* __SECSRV_PRIVATE_H__ */
diff --git a/src/responder/secrets/secsrv_proxy.h b/src/responder/secrets/secsrv_proxy.h
new file mode 100644
index 000000000..cfce721b9
--- /dev/null
+++ b/src/responder/secrets/secsrv_proxy.h
@@ -0,0 +1,28 @@
+/*
+ SSSD
+
+ Secrets Proxy Provider
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> 2016
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __SECSRV_PROXY_H__
+#define __SECSRV_PROXY_H__
+
+int proxy_secrets_provider_handle(struct sec_ctx *sctx,
+ struct provider_handle **out_handle);
+
+#endif /* __SECSRV_PROXY_H__ */