From cfb82199afe237b4e892aaf2816db63279d7cb21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20B=C5=99ezina?= Date: Tue, 28 Feb 2017 14:14:40 +0100 Subject: [PATCH 84/90] secrets: remove http-parser code in proxy provider We switche to libcurl in previous patch. This just removes the unused code. Resolves: https://pagure.io/SSSD/sssd/issue/3192 Reviewed-by: Simo Sorce Reviewed-by: Jakub Hrozek (cherry picked from commit 06744bf5a47d5971a338281c8243b11cf72dac90) --- src/responder/secrets/proxy.c | 581 ------------------------------------------ 1 file changed, 581 deletions(-) diff --git a/src/responder/secrets/proxy.c b/src/responder/secrets/proxy.c index fe2f0134e233d9a98f499fe563abe0af69762514..3c495716010ac468c9e2f1fb6356529a8dbdc614 100644 --- a/src/responder/secrets/proxy.c +++ b/src/responder/secrets/proxy.c @@ -395,587 +395,6 @@ done: 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) { - DEBUG(SSSDBG_CRIT_FAILURE, "Failed to parse URL [%s]: %d: %s\n", - http_uri, ret, sss_strerror(ret)); - goto done; - } - - if (!(parsed.field_set & (1 << UF_HOST))) { - DEBUG(SSSDBG_CRIT_FAILURE, "No UF_HOST flag found\n"); - 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; - } - DEBUG(SSSDBG_TRACE_LIBS, "proxy name: %s\n", state->proxyname); - - 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; - } - } - DEBUG(SSSDBG_TRACE_LIBS, "proxy port: %d\n", state->port); - - /* 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 = ERR_SEC_NO_PROXY; - 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; - int 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) { - DEBUG(SSSDBG_CRIT_FAILURE, - "sec_send_data failed [%d]: %s\n", ret, sss_strerror(ret)); - 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; -- 2.9.3