1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce Secrets Responder
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce Copyright (C) Simo Sorce <ssorce@redhat.com> 2016
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce This program is free software; you can redistribute it and/or modify
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce it under the terms of the GNU General Public License as published by
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce the Free Software Foundation; either version 3 of the License, or
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce (at your option) any later version.
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce This program is distributed in the hope that it will be useful,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce but WITHOUT ANY WARRANTY; without even the implied warranty of
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce GNU General Public License for more details.
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce You should have received a copy of the GNU General Public License
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce along with this program. If not, see <http://www.gnu.org/licenses/>.
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozektypedef int (*url_mapper_fn)(struct sec_req_ctx *secreq,
cf902c2b247c1b5793ae0ba58fd2dcbb0f78b686Jakub Hrozekstatic int sec_map_url_to_user_path(struct sec_req_ctx *secreq,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* change path to be user specific */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce talloc_asprintf(secreq, SEC_BASEPATH"users/%"SPRIuid"/%s",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce &secreq->parsed_url.path[sizeof(SEC_BASEPATH) - 1]);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Failed to map request to user specific url\n");
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek "User-specific secrets path is [%s]\n", *mapped_path);
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozekstatic int kcm_map_url_to_path(struct sec_req_ctx *secreq,
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek *mapped_path = talloc_strdup(secreq, secreq->parsed_url.path );
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek "Failed to map request to user specific url\n");
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek "User-specific KCM path is [%s]\n", *mapped_path);
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozekstatic struct url_pfx_router secrets_url_mapping[] = {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorceint sec_req_routing(TALLOC_CTX *mem_ctx, struct sec_req_ctx *secreq,
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce sctx = talloc_get_type(secreq->cctx->rctx->pvt_ctx, struct sec_ctx);
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek for (int i = 0; secrets_url_mapping[i].prefix != NULL; i++) {
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek "Mapping prefix %s\n", secrets_url_mapping[i].prefix);
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek "Path [%s] does not start with any allowed prefix\n",
60612b5fbdaaa62ebe6c7f4c27200316f08506d6Jakub Hrozek "Failed to map the user path [%d]: %s\n",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* source default provider */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = confdb_get_string(secreq->cctx->rctx->cdb, mem_ctx,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "The default provider is '%s'\n", def_provider);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = confdb_get_sub_sections(mem_ctx, secreq->cctx->rctx->cdb,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "confdb section %s has %d sub-sections\n",
677a31351c80453d9ce006481364399a96312052René Genz // TODO order by length?
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce for (int i = 0; i < num_sections; i++) {
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce secreq->base_path = talloc_asprintf(secreq, SEC_BASEPATH"%s/", sections[i]);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce if (strncmp(secreq->base_path, secreq->mapped_path, slen) == 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce secname = talloc_asprintf(mem_ctx, CONFDB_SEC_CONF_ENTRY"/%s",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce ret = confdb_get_string(secreq->cctx->rctx->cdb, mem_ctx,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "matched subsection %s with provider %s\n",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce secreq->cfg_section = talloc_steal(secreq, secname);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce if (!secreq->base_path) secreq->base_path = SEC_BASEPATH;
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "Request base path is [%s]\n", secreq->base_path);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce ret = local_secrets_provider_handle(sctx, handle);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce ret = proxy_secrets_provider_handle(sctx, handle);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_TRACE_INTERNAL, "Request finished\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "The request format is invalid." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Access to the requested resource requires authentication." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Access to the requested resource is forbidden." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "The requested resource was not found." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Request method not allowed for this resource." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "The request cannot be accepted." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "The requested resource already exists." },
7171a7584dda534dde5409f3e7f4657e845ece15Fabiano Fidêncio "The secret payload is too large." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "The server encountered an internal error." },
41cd6072648bb7a9e14e56ed38004a2947f67657Jakub Hrozek "No response from a proxy server." },
65a38b8c9cabde6c46cc0e9868f54cb9bb10afbfFabiano Fidêncio "The server is unable to store the resource needed to complete the request." },
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorceint sec_http_status_reply(TALLOC_CTX *mem_ctx, struct sec_data *reply,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "<html>\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "<head>\r\n<title>%d %s</title></head>\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "<body>\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "<h1>%s</h1>\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "<p>%s</p>\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "HTTP/1.1 %d %s\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Content-Length: %u\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Content-Type: text/html\r\n"
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "HTTP reply %d: %s\n",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorceint sec_http_reply_with_body(TALLOC_CTX *mem_ctx, struct sec_data *reply,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "HTTP/1.1 %d %s\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Content-Type: %s\r\n"
3e81e71124c75fd8709704e38561fa1f9d5bfbc2Lukas Slebodnik "Content-Length: %zu\r\n"
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce reply->data = talloc_realloc(mem_ctx, reply->data, char,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce memcpy(&reply->data[head_size], body->data, body->length);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek "HTTP reply %d: %s\n",
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorceint sec_http_append_header(TALLOC_CTX *mem_ctx, char **dest,
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce *dest = talloc_asprintf(mem_ctx, "%s: %s\r\n", field, value);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce *dest = talloc_asprintf_append_buffer(*dest, "%s: %s\r\n",
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorceint sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply,
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce const char *reason_phrase = reason ? reason : "";
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce /* Status-Line */
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce reply->data = talloc_asprintf(mem_ctx, "HTTP/1.1 %d %s\r\n",
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d: %s\n", status_code, reason_phrase);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce /* Headers */
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce for (int i = 0; i < num_headers; i++) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (strcasecmp(headers[i].name, "Content-Length") == 0) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce } else if (strcasecmp(headers[i].name, "Content-Type") == 0) {
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce ret = sec_http_append_header(mem_ctx, &reply->data,
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "No Content-Type header\n");
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce reply->data = talloc_asprintf_append_buffer(reply->data,
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce "Content-Length: %u\r\n", (unsigned)body->length);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce /* CRLF separator before body */
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce reply->data = talloc_strdup_append_buffer(reply->data, "\r\n");
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce /* Message-Body */
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce reply->data = talloc_realloc(mem_ctx, reply->data, char,
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce memcpy(&reply->data[reply->length], body->data, body->length);
13d720de13e490850c1139eea865bcd5195a2630Pavel Březinasec_http_iobuf_split(struct sss_iobuf *response,
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina const char **headers,
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina const char **body)
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina const char *data = (const char *)sss_iobuf_get_data(response);
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina /* The last header ends with \r\n and then comes \r\n again as a separator
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina * of body from headers. We can use this to find this point. */
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina /* Skip to the body delimiter. */
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina /* Replace \r\n with zeros turning data into:
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina * from HEADER\r\nBODY into HEADER\0\0BODY format. */
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina /* Split the buffer. */
13d720de13e490850c1139eea865bcd5195a2630Pavel Březinastatic const char *
13d720de13e490850c1139eea865bcd5195a2630Pavel Březinasec_http_iobuf_add_content_length(TALLOC_CTX *mem_ctx,
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina /* If Content-Length is already present we do nothing. */
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina if (strstr(headers, "Content-Length:") != NULL) {
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina return talloc_asprintf(mem_ctx, "%sContent-Length: %zu\r\n",
df99d709c8cbef3c378c111944d83b7345e4c1eaPavel Březinaerrno_t sec_http_reply_iobuf(TALLOC_CTX *mem_ctx,
df99d709c8cbef3c378c111944d83b7345e4c1eaPavel Březina DEBUG(SSSDBG_TRACE_LIBS, "HTTP reply %d\n", response_code);
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina ret = sec_http_iobuf_split(response, &headers, &body);
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina "Unexpected HTTP reply, returning what we got from server\n");
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina reply->data = (char *)sss_iobuf_get_data(response);
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina /* Add Content-Length header if not present so client does not await
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina * not-existing incoming data. */
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina headers = sec_http_iobuf_add_content_length(mem_ctx, headers, body_len);
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina reply->length = strlen(headers) + sizeof("\r\n") - 1 + body_len;
13d720de13e490850c1139eea865bcd5195a2630Pavel Březina reply->data = talloc_asprintf(mem_ctx, "%s\r\n%s", headers, body);
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorceenum sec_http_status_codes sec_errno_to_http_status(errno_t err)
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_TRACE_LIBS, "Request errno: %d\n", err);
efc65e78fa4e01e6cecc8690a9899af61213be62Fabiano Fidêncio case ERR_SEC_INVALID_CONTAINERS_NEST_LEVEL:
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorceint sec_json_to_simple_secret(TALLOC_CTX *mem_ctx,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce const char *input,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce "Failed to parse JSON payload on line %d: %s\n",
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce DEBUG(SSSDBG_CRIT_FAILURE, "Json data is not an object.\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce DEBUG(SSSDBG_CRIT_FAILURE, "Json data key 'type' not found.\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce DEBUG(SSSDBG_CRIT_FAILURE, "Json object 'type' is not a string.\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce if (strcmp(json_string_value(element), "simple") != 0) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce DEBUG(SSSDBG_CRIT_FAILURE, "Token type is not 'simple'.\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce DEBUG(SSSDBG_CRIT_FAILURE, "Json key 'value' not found.\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce DEBUG(SSSDBG_CRIT_FAILURE, "Json object 'value' is not a string.\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce *secret = talloc_strdup(mem_ctx, json_string_value(element));
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorceint sec_simple_secret_to_json(TALLOC_CTX *mem_ctx,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce const char *secret,
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce root = json_pack("{s:s, s:s}", "type", "simple", "value", secret);
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "Failed to pack Json object\n");
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "Failed to dump Json object\n");
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "Failed to create Json array\n");
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce for (int i = 0; i < count; i++) {
677a31351c80453d9ce006481364399a96312052René Genz // FIXME: json_string mem leak?
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce // FIXME: Error checking
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce json_array_append_new(root, json_string(array[i]));
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "Failed to dump Json object\n");
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorceint sec_get_provider(struct sec_ctx *sctx, const char *name,
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce for (int i = 0; sctx->providers && sctx->providers[i]; i++) {
7128fadade544efcd86b113a5090b00d20993671Jakub Hrozek DEBUG(SSSDBG_MINOR_FAILURE, "No handle for provider %s\n", name);
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorceint sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle)
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce for (c = 0; sctx->providers && sctx->providers[c]; c++)
8f2a34cc6964a1f80a1434e05315a7ae0bb5774eSimo Sorce sctx->providers = talloc_realloc(sctx, sctx->providers,
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce if (strcasecmp(name, req->headers[i].name) == 0) {
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce return (strcasecmp(value, req->headers[i].value) == 0);
e625eb47a3091d92eda2271b123f8aab06227b63Simo Sorce return false;