25f72e2845c89a153ca9d3279d7feccbc912524ematthew/*
25f72e2845c89a153ca9d3279d7feccbc912524ematthew SSSD
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew Secrets Responder
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew Copyright (C) Simo Sorce <ssorce@redhat.com> 2016
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew This program is free software; you can redistribute it and/or modify
25f72e2845c89a153ca9d3279d7feccbc912524ematthew it under the terms of the GNU General Public License as published by
25f72e2845c89a153ca9d3279d7feccbc912524ematthew the Free Software Foundation; either version 3 of the License, or
25f72e2845c89a153ca9d3279d7feccbc912524ematthew (at your option) any later version.
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew This program is distributed in the hope that it will be useful,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew but WITHOUT ANY WARRANTY; without even the implied warranty of
25f72e2845c89a153ca9d3279d7feccbc912524ematthew MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25f72e2845c89a153ca9d3279d7feccbc912524ematthew GNU General Public License for more details.
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew You should have received a copy of the GNU General Public License
25f72e2845c89a153ca9d3279d7feccbc912524ematthew along with this program. If not, see <http://www.gnu.org/licenses/>.
25f72e2845c89a153ca9d3279d7feccbc912524ematthew*/
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew#include "config.h"
25f72e2845c89a153ca9d3279d7feccbc912524ematthew#include "util/util.h"
25f72e2845c89a153ca9d3279d7feccbc912524ematthew#include "responder/common/responder.h"
a5b9f8fb834b1b2208e59a2fa76714bd91a5f147violette#include "responder/secrets/secsrv.h"
25f72e2845c89a153ca9d3279d7feccbc912524ematthew#include "responder/secrets/secsrv_private.h"
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew/* ##### Request Handling ##### */
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthewstruct sec_http_request_state {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct tevent_context *ev;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct sec_req_ctx *secreq;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew};
25f72e2845c89a153ca9d3279d7feccbc912524ematthewstatic void sec_http_request_pipeline_done(struct tevent_req *subreq);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthewstatic struct tevent_req *sec_http_request_send(TALLOC_CTX *mem_ctx,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct tevent_context *ev,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct sec_req_ctx *secreq)
25f72e2845c89a153ca9d3279d7feccbc912524ematthew{
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct tevent_req *req;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct tevent_req *subreq;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct sec_http_request_state *state;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct provider_handle *provider_handle;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew errno_t ret;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew req = tevent_req_create(mem_ctx, &state, struct sec_http_request_state);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew if (!req) return NULL;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew state->ev = ev;
7edeca432448c9eb6a7618b130fccc3eb04459aemark state->secreq = secreq;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew /* Go through the pipeline */
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew /* 1. mapping and path conversion */
25f72e2845c89a153ca9d3279d7feccbc912524ematthew ret = sec_req_routing(state, secreq, &provider_handle);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew if (ret) {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew DEBUG(SSSDBG_OP_FAILURE,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew "sec_req_routing failed [%d]: %s\n", ret, sss_strerror(ret));
25f72e2845c89a153ca9d3279d7feccbc912524ematthew goto done;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew }
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew /* 2. backend invocation */
25f72e2845c89a153ca9d3279d7feccbc912524ematthew subreq = provider_handle->fn(state, state->ev,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew provider_handle->context, secreq);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew if (!subreq) {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew ret = ENOMEM;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew goto done;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew }
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew tevent_req_set_callback(subreq, sec_http_request_pipeline_done, req);
a5b9f8fb834b1b2208e59a2fa76714bd91a5f147violette return req;
8890d0c686adc8442c156956735470bf289ba2d8mark
8890d0c686adc8442c156956735470bf289ba2d8markdone:
8890d0c686adc8442c156956735470bf289ba2d8mark if (ret != EOK) {
8890d0c686adc8442c156956735470bf289ba2d8mark tevent_req_error(req, ret);
8890d0c686adc8442c156956735470bf289ba2d8mark }
8890d0c686adc8442c156956735470bf289ba2d8mark return tevent_req_post(req, state->ev);
8890d0c686adc8442c156956735470bf289ba2d8mark}
8890d0c686adc8442c156956735470bf289ba2d8mark
8890d0c686adc8442c156956735470bf289ba2d8markstatic void sec_http_request_pipeline_done(struct tevent_req *subreq)
8890d0c686adc8442c156956735470bf289ba2d8mark{
8890d0c686adc8442c156956735470bf289ba2d8mark struct tevent_req *req;
8890d0c686adc8442c156956735470bf289ba2d8mark errno_t ret;
8890d0c686adc8442c156956735470bf289ba2d8mark
8890d0c686adc8442c156956735470bf289ba2d8mark req = tevent_req_callback_data(subreq, struct tevent_req);
8890d0c686adc8442c156956735470bf289ba2d8mark
8890d0c686adc8442c156956735470bf289ba2d8mark /* 3. reply construction */
8890d0c686adc8442c156956735470bf289ba2d8mark ret = sec_provider_recv(subreq);
8890d0c686adc8442c156956735470bf289ba2d8mark if (ret == ENOENT) {
8890d0c686adc8442c156956735470bf289ba2d8mark DEBUG(SSSDBG_TRACE_LIBS, "Did not find the requested data\n");
25f72e2845c89a153ca9d3279d7feccbc912524ematthew tevent_req_error(req, ret);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew } else if (ret != EOK) {
28a3ff3fa0d3b5e1c774217425cf609cc6339df7matthew DEBUG(SSSDBG_OP_FAILURE,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew "sec request failed [%d]: %s\n", ret, sss_strerror(ret));
25f72e2845c89a153ca9d3279d7feccbc912524ematthew tevent_req_error(req, ret);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew } else {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew DEBUG(SSSDBG_TRACE_INTERNAL, "sec request done\n");
25f72e2845c89a153ca9d3279d7feccbc912524ematthew tevent_req_done(req);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew }
8890d0c686adc8442c156956735470bf289ba2d8mark}
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthewstatic int sec_http_request_recv(struct tevent_req *req)
25f72e2845c89a153ca9d3279d7feccbc912524ematthew{
25f72e2845c89a153ca9d3279d7feccbc912524ematthew TEVENT_REQ_RETURN_ON_ERROR(req);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew return EOK;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew}
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew/* --- */
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthewstatic void
25f72e2845c89a153ca9d3279d7feccbc912524ematthewsec_http_request_done(struct tevent_req *req)
25f72e2845c89a153ca9d3279d7feccbc912524ematthew{
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct sec_req_ctx *secreq;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew struct cli_ctx *cctx;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew int ret;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew secreq = tevent_req_callback_data(req, struct sec_req_ctx);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew cctx = secreq->cctx;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew ret = sec_http_request_recv(req);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew if (ret != EOK) {
341664ce1d0029ac39e10f21cebc2d57bac59ce1matthew if (ret == ENOENT) {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew DEBUG(SSSDBG_TRACE_LIBS, "Did not find the requested data\n");
25f72e2845c89a153ca9d3279d7feccbc912524ematthew } else {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew DEBUG(SSSDBG_OP_FAILURE,
8890d0c686adc8442c156956735470bf289ba2d8mark "sec_http_request_recv failed [%d]: %s\n",
8890d0c686adc8442c156956735470bf289ba2d8mark ret, sss_strerror(ret));
8890d0c686adc8442c156956735470bf289ba2d8mark }
8890d0c686adc8442c156956735470bf289ba2d8mark /* Always return an error if we get here */
8890d0c686adc8442c156956735470bf289ba2d8mark ret = sec_http_status_reply(secreq, &secreq->reply,
8890d0c686adc8442c156956735470bf289ba2d8mark sec_errno_to_http_status(ret));
8890d0c686adc8442c156956735470bf289ba2d8mark }
8890d0c686adc8442c156956735470bf289ba2d8mark
8890d0c686adc8442c156956735470bf289ba2d8mark if (ret != EOK) {
8890d0c686adc8442c156956735470bf289ba2d8mark DEBUG(SSSDBG_FATAL_FAILURE,
8890d0c686adc8442c156956735470bf289ba2d8mark "Failed to find reply, aborting client!\n");
8890d0c686adc8442c156956735470bf289ba2d8mark talloc_free(cctx);
c474d6853192b277a73b133d56970bbf118d3fe3mark return;
820ed286b08eac25f26a4904ca06e9d600b612aemark }
c474d6853192b277a73b133d56970bbf118d3fe3mark
c474d6853192b277a73b133d56970bbf118d3fe3mark /* Turn writable on so we can write back the reply */
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew TEVENT_FD_WRITEABLE(cctx->cfde);
c474d6853192b277a73b133d56970bbf118d3fe3mark}
c474d6853192b277a73b133d56970bbf118d3fe3mark
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthewstatic void sec_cmd_execute(struct cli_ctx *cctx)
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew{
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew struct sec_req_ctx *secreq;
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew struct tevent_req *req;
c474d6853192b277a73b133d56970bbf118d3fe3mark
c474d6853192b277a73b133d56970bbf118d3fe3mark secreq = talloc_get_type(cctx->state_ctx, struct sec_req_ctx);
c474d6853192b277a73b133d56970bbf118d3fe3mark
820ed286b08eac25f26a4904ca06e9d600b612aemark req = sec_http_request_send(secreq, cctx->ev, secreq);
820ed286b08eac25f26a4904ca06e9d600b612aemark if (!req) {
c474d6853192b277a73b133d56970bbf118d3fe3mark DEBUG(SSSDBG_CRIT_FAILURE,
c474d6853192b277a73b133d56970bbf118d3fe3mark "Failed to schedule secret retrieval\n.");
c474d6853192b277a73b133d56970bbf118d3fe3mark talloc_free(cctx);
c474d6853192b277a73b133d56970bbf118d3fe3mark return;
c474d6853192b277a73b133d56970bbf118d3fe3mark }
c474d6853192b277a73b133d56970bbf118d3fe3mark tevent_req_set_callback(req, sec_http_request_done, secreq);
c474d6853192b277a73b133d56970bbf118d3fe3mark}
c474d6853192b277a73b133d56970bbf118d3fe3mark
820ed286b08eac25f26a4904ca06e9d600b612aemark
820ed286b08eac25f26a4904ca06e9d600b612aemark/* ##### HTTP Parsing Callbacks ##### */
820ed286b08eac25f26a4904ca06e9d600b612aemark
c474d6853192b277a73b133d56970bbf118d3fe3markstatic void sec_append_string(TALLOC_CTX *memctx, char **dest,
c474d6853192b277a73b133d56970bbf118d3fe3mark const char *src, size_t len)
c474d6853192b277a73b133d56970bbf118d3fe3mark{
25f72e2845c89a153ca9d3279d7feccbc912524ematthew if (*dest) {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew *dest = talloc_strndup_append_buffer(*dest, src, len);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew } else {
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew *dest = talloc_strndup(memctx, src, len);
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew }
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew}
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthewstatic bool sec_too_much_data(struct sec_req_ctx *req, size_t length)
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew{
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew req->total_size += length;
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew if (req->total_size > SEC_REQUEST_MAX_SIZE) {
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew DEBUG(SSSDBG_FATAL_FAILURE,
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew "Request too big, aborting client!\n");
25f72e2845c89a153ca9d3279d7feccbc912524ematthew return true;
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew }
25f72e2845c89a153ca9d3279d7feccbc912524ematthew return false;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew}
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthewstatic int sec_on_message_begin(http_parser *parser)
25f72e2845c89a153ca9d3279d7feccbc912524ematthew{
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew DEBUG(SSSDBG_TRACE_INTERNAL, "HTTP Message parsing begins\n");
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew return 0;
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew}
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew
b71b897e701bebae34ed137919077cd8374232eamatthewstatic int sec_on_url(http_parser *parser,
b71b897e701bebae34ed137919077cd8374232eamatthew const char *at, size_t length)
b71b897e701bebae34ed137919077cd8374232eamatthew{
b71b897e701bebae34ed137919077cd8374232eamatthew struct sec_req_ctx *req =
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew talloc_get_type(parser->data, struct sec_req_ctx);
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew if (sec_too_much_data(req, length)) return -1;
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew
5ffeac9af157b599c7fb34a23d6c50161fbd6a6cmatthew sec_append_string(req, &req->request_url, at, length);
25f72e2845c89a153ca9d3279d7feccbc912524ematthew if (!req->request_url) {
25f72e2845c89a153ca9d3279d7feccbc912524ematthew DEBUG(SSSDBG_FATAL_FAILURE,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew "Failed to store URL, aborting client!\n");
25f72e2845c89a153ca9d3279d7feccbc912524ematthew return -1;
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew }
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew return 0;
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew}
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew
803d79f1f1fd8c2134e01ac1383686389e267f3ematthewstatic int sec_on_header_field(http_parser *parser,
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew const char *at, size_t length)
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew{
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew struct sec_req_ctx *req =
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew talloc_get_type(parser->data, struct sec_req_ctx);
803d79f1f1fd8c2134e01ac1383686389e267f3ematthew int n = req->num_headers;
25f72e2845c89a153ca9d3279d7feccbc912524ematthew
25f72e2845c89a153ca9d3279d7feccbc912524ematthew if (sec_too_much_data(req, length)) return -1;
503c353d31964b01e67395d3b1207f3e408dd774matthew
503c353d31964b01e67395d3b1207f3e408dd774matthew if (!req->headers) {
503c353d31964b01e67395d3b1207f3e408dd774matthew req->headers = talloc_zero_array(req, struct sec_kvp, 10);
503c353d31964b01e67395d3b1207f3e408dd774matthew } else if ((n % 10 == 0) &&
503c353d31964b01e67395d3b1207f3e408dd774matthew (req->headers[n - 1].value)) {
503c353d31964b01e67395d3b1207f3e408dd774matthew req->headers = talloc_realloc(req, req->headers,
503c353d31964b01e67395d3b1207f3e408dd774matthew struct sec_kvp, n + 10);
8890d0c686adc8442c156956735470bf289ba2d8mark if (req->headers) {
503c353d31964b01e67395d3b1207f3e408dd774matthew memset(&req->headers[n], 0, sizeof(struct sec_kvp) * 10);
503c353d31964b01e67395d3b1207f3e408dd774matthew }
503c353d31964b01e67395d3b1207f3e408dd774matthew }
503c353d31964b01e67395d3b1207f3e408dd774matthew if (!req->headers) {
503c353d31964b01e67395d3b1207f3e408dd774matthew DEBUG(SSSDBG_FATAL_FAILURE,
503c353d31964b01e67395d3b1207f3e408dd774matthew "Failed to store headers, aborting client!\n");
503c353d31964b01e67395d3b1207f3e408dd774matthew return -1;
503c353d31964b01e67395d3b1207f3e408dd774matthew }
503c353d31964b01e67395d3b1207f3e408dd774matthew
503c353d31964b01e67395d3b1207f3e408dd774matthew if (!n || req->headers[n - 1].value) {
503c353d31964b01e67395d3b1207f3e408dd774matthew /* new field */
503c353d31964b01e67395d3b1207f3e408dd774matthew n++;
503c353d31964b01e67395d3b1207f3e408dd774matthew }
503c353d31964b01e67395d3b1207f3e408dd774matthew sec_append_string(req->headers, &req->headers[n - 1].name, at, length);
503c353d31964b01e67395d3b1207f3e408dd774matthew if (!req->headers[n - 1].name) {
503c353d31964b01e67395d3b1207f3e408dd774matthew DEBUG(SSSDBG_FATAL_FAILURE,
503c353d31964b01e67395d3b1207f3e408dd774matthew "Failed to store header name, aborting client!\n");
503c353d31964b01e67395d3b1207f3e408dd774matthew return -1;
503c353d31964b01e67395d3b1207f3e408dd774matthew }
503c353d31964b01e67395d3b1207f3e408dd774matthew
503c353d31964b01e67395d3b1207f3e408dd774matthew return 0;
8890d0c686adc8442c156956735470bf289ba2d8mark}
8890d0c686adc8442c156956735470bf289ba2d8mark
8890d0c686adc8442c156956735470bf289ba2d8markstatic int sec_on_header_value(http_parser *parser,
25f72e2845c89a153ca9d3279d7feccbc912524ematthew const char *at, size_t length)
{
struct sec_req_ctx *req =
talloc_get_type(parser->data, struct sec_req_ctx);
int n = req->num_headers;
if (sec_too_much_data(req, length)) return -1;
if (!req->headers) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Invalid headers pointer, aborting client!\n");
return -1;
}
if (req->headers[n].name && !req->headers[n].value) {
/* we increment on new value */
n = ++req->num_headers;
}
sec_append_string(req->headers, &req->headers[n - 1].value, at, length);
if (!req->headers[n - 1].value) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to store header value, aborting client!\n");
return -1;
}
return 0;
}
static int sec_on_headers_complete(http_parser *parser)
{
/* TODO: if message has no body we should return 1 */
return 0;
}
static int sec_on_body(http_parser *parser,
const char *at, size_t length)
{
struct sec_req_ctx *req =
talloc_get_type(parser->data, struct sec_req_ctx);
if (sec_too_much_data(req, length)) return -1;
sec_append_string(req, &req->body.data, at, length);
if (!req->body.data) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to store body, aborting client!\n");
return -1;
}
req->body.length += length;
return 0;
}
static int sec_get_parsed_field(TALLOC_CTX *mem_ctx, int field,
struct http_parser_url *parsed,
char *source_buf,
char **dest)
{
uint16_t off = parsed->field_data[field].off;
uint16_t len = parsed->field_data[field].len;
*dest = talloc_strndup(mem_ctx, &source_buf[off], len);
if (!*dest) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to parse url, aborting client!\n");
return ENOMEM;
}
return EOK;
}
static int sec_on_message_complete(http_parser *parser)
{
struct sec_req_ctx *req =
talloc_get_type(parser->data, struct sec_req_ctx);
struct http_parser_url parsed;
int ret;
/* parse url as well */
ret = http_parser_parse_url(req->request_url,
strlen(req->request_url),
0, &parsed);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to parse URL %s\n", req->request_url);
return ret;
}
if (parsed.field_set & (1 << UF_SCHEMA)) {
ret = sec_get_parsed_field(req, UF_SCHEMA, &parsed,
req->request_url,
&req->parsed_url.schema);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to retrieve schema from %s\n", req->request_url);
return -1;
}
DEBUG(SSSDBG_TRACE_INTERNAL, "schema: %s\n", req->parsed_url.schema);
}
if (parsed.field_set & (1 << UF_HOST)) {
ret = sec_get_parsed_field(req, UF_HOST, &parsed,
req->request_url,
&req->parsed_url.host);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to retrieve host from %s\n", req->request_url);
return -1;
}
DEBUG(SSSDBG_TRACE_INTERNAL, "host: %s\n", req->parsed_url.host);
}
if (parsed.field_set & (1 << UF_PORT)) {
req->parsed_url.port = parsed.port;
DEBUG(SSSDBG_TRACE_INTERNAL, "port: %d\n", req->parsed_url.port);
}
if (parsed.field_set & (1 << UF_PATH)) {
ret = sec_get_parsed_field(req, UF_PATH, &parsed,
req->request_url,
&req->parsed_url.path);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to retrieve path from %s\n", req->request_url);
return -1;
}
DEBUG(SSSDBG_TRACE_INTERNAL, "path: %s\n", req->parsed_url.path);
}
if (parsed.field_set & (1 << UF_QUERY)) {
ret = sec_get_parsed_field(req, UF_QUERY, &parsed,
req->request_url,
&req->parsed_url.query);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to retrieve query from %s\n", req->request_url);
return -1;
}
DEBUG(SSSDBG_TRACE_INTERNAL, "query: %s\n", req->parsed_url.query);
}
if (parsed.field_set & (1 << UF_FRAGMENT)) {
ret = sec_get_parsed_field(req, UF_FRAGMENT, &parsed,
req->request_url,
&req->parsed_url.fragment);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to retrieve fragment from %s\n", req->request_url);
return -1;
}
DEBUG(SSSDBG_TRACE_INTERNAL,
"fragment: %s\n", req->parsed_url.fragment);
}
if (parsed.field_set & (1 << UF_USERINFO)) {
ret = sec_get_parsed_field(req, UF_USERINFO, &parsed,
req->request_url,
&req->parsed_url.userinfo);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Failed to retrieve userinfo from %s\n", req->request_url);
return -1;
}
DEBUG(SSSDBG_TRACE_INTERNAL,
"userinfo: %s\n", req->parsed_url.userinfo);
}
req->method = parser->method;
req->complete = true;
DEBUG(SSSDBG_TRACE_INTERNAL, "parsing complete\n");
return 0;
}
/* ##### Communications ##### */
int sec_send_data(int fd, struct sec_data *data)
{
ssize_t len;
errno_t ret;
errno = 0;
len = send(fd, data->data, data->length, 0);
if (len == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
return EAGAIN;
} else {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"send failed [%d]: %s\n", ret, strerror(ret));
return ret;
}
}
if (len == 0) {
return EIO;
}
data->length -= len;
data->data += len;
DEBUG(SSSDBG_TRACE_INTERNAL, "sent %zu bytes\n", data->length);
return EOK;
}
static void sec_send(struct cli_ctx *cctx)
{
struct sec_req_ctx *req;
int ret;
req = talloc_get_type(cctx->state_ctx, struct sec_req_ctx);
ret = sec_send_data(cctx->cfd, &req->reply);
if (ret == EAGAIN) {
/* not all data was sent, loop again */
return;
}
if (ret != EOK) {
DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
talloc_free(cctx);
return;
}
/* ok all sent */
TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
TEVENT_FD_READABLE(cctx->cfde);
talloc_zfree(cctx->state_ctx);
return;
}
int sec_recv_data(int fd, struct sec_data *data)
{
ssize_t len;
errno_t ret;
errno = 0;
len = recv(fd, data->data, data->length, 0);
if (len == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
return EAGAIN;
} else {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"send failed [%d]: %s\n", ret, strerror(ret));
return ret;
}
}
if (len == 0) {
data->length = 0;
return ENODATA;
}
data->length = len;
DEBUG(SSSDBG_TRACE_INTERNAL, "received %zu bytes\n", data->length);
return EOK;
}
static void sec_recv(struct cli_ctx *cctx)
{
struct sec_proto_ctx *prctx;
struct sec_req_ctx *req;
char buffer[SEC_PACKET_MAX_RECV_SIZE];
struct sec_data data = { buffer,
SEC_PACKET_MAX_RECV_SIZE };
size_t len;
int ret;
prctx = talloc_get_type(cctx->protocol_ctx, struct sec_proto_ctx);
req = talloc_get_type(cctx->state_ctx, struct sec_req_ctx);
if (!req) {
/* A new request comes in, setup data structures */
req = talloc_zero(cctx, struct sec_req_ctx);
if (!req) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to setup request handlers, aborting client\n");
talloc_free(cctx);
return;
}
req->cctx = cctx;
cctx->state_ctx = req;
http_parser_init(&prctx->parser, HTTP_REQUEST);
prctx->parser.data = req;
}
ret = sec_recv_data(cctx->cfd, &data);
switch (ret) {
case ENODATA:
DEBUG(SSSDBG_TRACE_ALL,
"Client closed connection.\n");
talloc_free(cctx);
return;
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 client\n",
ret, sss_strerror(ret));
talloc_free(cctx);
return;
}
len = http_parser_execute(&prctx->parser, &prctx->callbacks,
data.data, data.length);
if (len != data.length) {
DEBUG(SSSDBG_FATAL_FAILURE,
"Failed to parse request, aborting client!\n");
talloc_free(cctx);
return;
}
if (!req->complete) {
return;
}
/* do not read anymore, client is done sending */
TEVENT_FD_NOT_READABLE(cctx->cfde);
sec_cmd_execute(cctx);
}
static void sec_fd_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *ptr)
{
errno_t ret;
struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx);
/* Always reset the idle timer on any activity */
ret = reset_idle_timer(cctx);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,
"Could not create idle timer for client. "
"This connection may not auto-terminate\n");
/* Non-fatal, continue */
}
if (flags & TEVENT_FD_READ) {
sec_recv(cctx);
return;
}
if (flags & TEVENT_FD_WRITE) {
sec_send(cctx);
return;
}
}
static http_parser_settings sec_callbacks = {
.on_message_begin = sec_on_message_begin,
.on_url = sec_on_url,
.on_header_field = sec_on_header_field,
.on_header_value = sec_on_header_value,
.on_headers_complete = sec_on_headers_complete,
.on_body = sec_on_body,
.on_message_complete = sec_on_message_complete
};
int sec_connection_setup(struct cli_ctx *cctx)
{
struct sec_proto_ctx *protocol_ctx;
protocol_ctx = talloc_zero(cctx, struct sec_proto_ctx);
if (!protocol_ctx) return ENOMEM;
protocol_ctx->callbacks = sec_callbacks;
cctx->protocol_ctx = protocol_ctx;
cctx->cfd_handler = sec_fd_handler;
return EOK;
}
/* Dummy, not used here but required to link to other responder files */
struct cli_protocol_version *register_cli_protocol_version(void)
{
return NULL;
}