proxy.c revision 7128fadade544efcd86b113a5090b00d20993671
/*
SSSD
Secrets Responder
Copyright (C) Simo Sorce <ssorce@redhat.com> 2016
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;
};
struct sec_req_ctx *secreq,
{
int ret;
return ret;
}
struct sec_req_ctx *secreq,
{
char *auth_type;
int ret;
/* find matching remote and build the URI */
"auth_type", &auth_type);
if (auth_type) {
"auth_header_name",
"auth_header_value",
} else {
goto done;
}
}
cfg->num_headers++;
}
/* Always whitelist Content-Type and Content-Length */
if (!cfg->fwd_headers) {
goto done;
}
goto done;
}
cfg->num_headers++;
goto done;
}
cfg->num_headers++;
done:
return ret;
}
{
char port[6] = { 0 };
char *url;
int blen;
int ret;
if (SECREQ_HAS_PORT(secreq)) {
return EINVAL;
}
}
return EOK;
}
{
int ret;
for (int i = 0; i < secreq->num_headers; i++) {
bool forward = false;
for (int j = 0; pcfg->fwd_headers[j]; j++) {
pcfg->fwd_headers[j]) == 0) {
forward = true;
break;
}
}
if (forward) {
if (ret) {
return ret;
}
}
}
if (ret) {
return ret;
}
}
return EOK;
}
struct sec_req_ctx *secreq,
const char *http_uri,
{
int ret;
/* Request-Line */
goto done;
}
/* Headers */
if (ret) {
goto done;
}
/* CRLF separator before body */
/* Message-Body */
goto done;
}
}
done:
return ret;
}
struct proxy_http_request {
};
struct proxy_http_reply {
bool complete;
int status_code;
char *reason_phrase;
int num_headers;
};
struct proxy_http_req_state {
struct tevent_context *ev;
char *proxyname;
int port;
struct resolv_hostent *hostent;
int hostidx;
int sd;
struct proxy_http_request request;
struct proxy_http_reply *reply;
};
static int proxy_http_req_state_destroy(void *data);
struct tevent_context *ev,
struct sec_req_ctx *secreq,
const char *http_uri,
{
struct proxy_http_req_state *state;
struct http_parser_url parsed;
int ret;
/* STEP1: reparse URL to get hostname and port */
if (ret) {
goto done;
}
goto done;
}
goto done;
}
if ((len == 5) &&
} else if ((len == 4) &&
}
}
/* STEP2: resolve hostname first */
goto done;
}
return req;
done:
} else {
}
return req;
}
{
struct tevent_req *req;
struct proxy_http_req_state *state;
int resolv_status;
int ret;
/* Empty result, just quit */
} else {
"Could not resolve fqdn for this machine, error [%d]: %s, "
}
goto done;
}
/* EOK */
/* STEP3: connect to one of the servers */
return;
done:
} else {
}
}
{
struct proxy_http_req_state *state;
struct sockaddr_storage *sockaddr;
char *ipaddr;
struct tevent_req *subreq;
int ret;
goto done;
}
goto done;
}
if (DEBUG_IS_SET(SSSDBG_TRACE_FUNC)) {
if (!ipaddr) {
goto done;
}
}
/* increase idx for next attempt */
sizeof(struct sockaddr_storage),
if (!subreq) {
goto done;
}
return;
done:
} else {
}
}
{
struct tevent_req *req;
struct proxy_http_req_state *state;
int ret;
"sssd_async_socket_init request failed: [%d]: %s.\n",
/* try next server if any */
return;
}
/* EOK */
req);
goto done;
}
return;
done:
} else {
}
}
struct proxy_http_reply **reply)
{
struct proxy_http_req_state *state =
return EOK;
}
static int proxy_http_req_state_destroy(void *data)
{
struct proxy_http_req_state *state =
if (!state) return 0;
}
return 0;
}
{
return ret;
}
return ret;
}
static void proxy_fd_send(void *data)
{
struct proxy_http_req_state *state;
struct tevent_req * req;
int ret;
/* not all data was sent, loop again */
return;
}
return;
}
/* ok all sent, wait for reply now */
return;
}
{
return true;
}
return false;
}
{
if (*dest) {
} else {
}
}
{
return 0;
}
{
struct proxy_http_reply *reply =
if (!reply->reason_phrase) {
"Failed to store reason phrase, aborting client!\n");
return -1;
}
return 0;
}
#endif
{
struct proxy_http_reply *reply =
int n = reply->num_headers;
} else if ((n % 10 == 0) &&
struct sec_kvp, n + 10);
}
}
"Failed to store headers, aborting client!\n");
return -1;
}
/* new field */
n++;
}
"Failed to store header name, aborting client!\n");
return -1;
}
return 0;
}
{
struct proxy_http_reply *reply =
int n = reply->num_headers;
"Invalid headers pointer, aborting client!\n");
return -1;
}
/* we increment on new value */
n = ++reply->num_headers;
}
"Failed to store header value, aborting client!\n");
return -1;
}
return 0;
}
{
/* TODO: if message has no body we should return 1 */
return 0;
}
{
struct proxy_http_reply *reply =
/* FIXME: body may be binary */
"Failed to store body, aborting!\n");
return -1;
}
return 0;
}
{
struct proxy_http_reply *reply =
return 0;
}
static http_parser_settings ph_callbacks = {
#endif
.on_body = ph_on_body,
};
static void proxy_fd_recv(void *data)
{
char buffer[SEC_PACKET_MAX_RECV_SIZE];
struct proxy_http_req_state *state;
struct tevent_req *req;
bool must_complete = false;
int ret;
/* A new reply */
return;
}
}
switch (ret) {
case ENODATA:
/* 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:
"Interrupted before any data could be read, retry later\n");
return;
case EOK:
/* all fine */
break;
default:
"Failed to receive data (%d, %s), aborting\n",
return;
}
"Failed to parse request, aborting!\n");
return;
}
if (must_complete) {
}
return;
}
/* do not read anymore, server is done sending */
}
{
if (flags & TEVENT_FD_READ) {
} else if (flags & TEVENT_FD_WRITE) {
}
}
struct proxy_secret_state {
struct tevent_context *ev;
struct sec_req_ctx *secreq;
};
struct tevent_context *ev,
void *provider_ctx,
struct sec_req_ctx *secreq)
{
struct proxy_secret_state *state;
struct proxy_context *pctx;
char *http_uri;
int ret;
if (!pctx) {
goto done;
}
if (ret) {
goto done;
}
if (ret) {
goto done;
}
if (ret) {
"proxy_http_create_request failed [%d]: %s\n",
goto done;
}
if (!subreq) {
goto done;
}
return req;
done:
} else {
/* shortcircuit the request here as all called functions are
* synchronous and final and no further subrequests have been
* made if we get here */
}
}
{
struct tevent_req *req;
struct proxy_secret_state *state;
int ret;
"proxy_http request failed [%d]: %s\n",
return;
}
} else {
"sec_http_reply_with_headers request failed [%d]: %s\n",
}
}
struct provider_handle proxy_secrets_handle = {
.fn = proxy_secret_req,
};
struct provider_handle **out_handle)
{
struct provider_handle *handle;
struct proxy_context *pctx;
*out_handle = handle;
return EOK;
}