From e625eb47a3091d92eda2271b123f8aab06227b63 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 17 Mar 2016 15:48:01 -0400 Subject: [PATCH 17/19] Local secrets provider Content-Type handling Properly handle and enforce ithe presence of the content-type header in the local and proxy providers to conform to the Custoida protocol. Avoids different behavior between the local provider and a remote server that may cause developers to have an application working against the local storage and then fail when the administrator configures a remote storage. Signed-off-by: Simo Sorce Reviewed-by: Jakub Hrozek --- src/responder/secrets/local.c | 46 ++++++++++++++++++++++++++++------ src/responder/secrets/providers.c | 27 ++++++++++++++++++++ src/responder/secrets/secsrv_private.h | 3 +++ 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/src/responder/secrets/local.c b/src/responder/secrets/local.c index 6451ef95bf7e6b81936d492349a548b329748b22..6fb46c3cee316095332713cbe7a964c2f9fd033a 100644 --- a/src/responder/secrets/local.c +++ b/src/responder/secrets/local.c @@ -405,6 +405,8 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, struct local_secret_state *state; struct local_context *lctx; struct sec_data body = { 0 }; + const char *content_type; + bool body_is_json; char *req_path; char *secret; char **keys; @@ -423,6 +425,19 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, goto done; } + if (sec_req_has_header(secreq, "Content-Type", + "application/json")) { + body_is_json = true; + content_type = "application/json"; + } else if (sec_req_has_header(secreq, "Content-Type", + "application/octet-stream")) { + body_is_json = false; + content_type = "application/octet-stream"; + } else { + ret = EINVAL; + goto done; + } + ret = local_secrets_map_path(state, secreq, &req_path); if (ret) goto done; @@ -434,21 +449,36 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, ret = sec_array_to_json(state, keys, nkeys, &body.data); if (ret) goto done; - } else { - ret = local_db_get_simple(state, lctx, req_path, &secret); - if (ret) goto done; + body.length = strlen(body.data); + break; + } + + ret = local_db_get_simple(state, lctx, req_path, &secret); + if (ret) goto done; + + if (body_is_json) { ret = sec_simple_secret_to_json(state, secret, &body.data); if (ret) goto done; + + body.length = strlen(body.data); + } else { + body.data = (void *)sss_base64_decode(state, secret, &body.length); + ret = body.data ? EOK : ENOMEM; } + if (ret) goto done; - body.length = strlen(body.data); break; case HTTP_PUT: - /*FIXME: check fot content-type */ - - ret = sec_json_to_simple_secret(state, secreq->body.data, &secret); + if (body_is_json) { + ret = sec_json_to_simple_secret(state, secreq->body.data, + &secret); + } else { + secret = sss_base64_encode(state, (uint8_t *)secreq->body.data, + secreq->body.length); + ret = secret ? EOK : ENOMEM; + } if (ret) goto done; ret = local_db_put_simple(state, lctx, req_path, secret); @@ -467,7 +497,7 @@ struct tevent_req *local_secret_req(TALLOC_CTX *mem_ctx, if (body.data) { ret = sec_http_reply_with_body(secreq, &secreq->reply, STATUS_200, - "application/json", &body); + content_type, &body); } else { ret = sec_http_status_reply(secreq, &secreq->reply, STATUS_200); } diff --git a/src/responder/secrets/providers.c b/src/responder/secrets/providers.c index 5dff01a7fb966261f25f70dfabf71490a7b2b352..2826a7040fbcb52cc96b6314cf8c54699304aae9 100644 --- a/src/responder/secrets/providers.c +++ b/src/responder/secrets/providers.c @@ -242,6 +242,8 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, struct sec_data *body) { const char *reason_phrase = reason ? reason : ""; + bool add_content_length = true; + bool has_content_type = false; int ret; /* Status-Line */ @@ -251,11 +253,24 @@ int sec_http_reply_with_headers(TALLOC_CTX *mem_ctx, struct sec_data *reply, /* Headers */ for (int i = 0; i < num_headers; i++) { + if (strcasecmp(headers[i].name, "Content-Length") == 0) { + add_content_length = false; + } else if (strcasecmp(headers[i].name, "Content-Type") == 0) { + has_content_type = true; + } ret = sec_http_append_header(mem_ctx, &reply->data, headers[i].name, headers[i].value); if (ret) return ret; } + if (!has_content_type) return EINVAL; + + if (add_content_length) { + reply->data = talloc_asprintf_append_buffer(reply->data, + "Content-Length: %u\r\n", (unsigned)body->length); + if (!reply->data) return ENOMEM; + } + /* CRLF separator before body */ reply->data = talloc_strdup_append_buffer(reply->data, "\r\n"); @@ -461,3 +476,15 @@ int sec_add_provider(struct sec_ctx *sctx, struct provider_handle *handle) return EOK; } + +bool sec_req_has_header(struct sec_req_ctx *req, + const char *name, const char *value) +{ + for (int i = 0; i < req->num_headers; i++) { + if (strcasecmp(name, req->headers[i].name) == 0) { + if (value == NULL) return true; + return (strcasecmp(value, req->headers[i].value) == 0); + } + } + return false; +} diff --git a/src/responder/secrets/secsrv_private.h b/src/responder/secrets/secsrv_private.h index ce8cf821620ff25039d38e00eb91a6e4d24dd093..c3b663996e138bbb14f1ab74db75398ffd0bd5c7 100644 --- a/src/responder/secrets/secsrv_private.h +++ b/src/responder/secrets/secsrv_private.h @@ -131,6 +131,9 @@ int sec_array_to_json(TALLOC_CTX *mem_ctx, char **array, int count, char **output); +bool sec_req_has_header(struct sec_req_ctx *req, + const char *name, const char *value); + /* secsrv_cmd.c */ #define SEC_REQUEST_MAX_SIZE 65536 #define SEC_PACKET_MAX_RECV_SIZE 8192 -- 2.4.11