From a6fab4ac0d180ee5503ba05860e177c69099eaa9 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Wed, 15 Nov 2017 23:13:20 +0100 Subject: [PATCH] [httpd/mpd] Adjustments to commit #69ff42f --- src/httpd.c | 58 ++++++++++++------------------------------------ src/httpd.h | 9 +++----- src/httpd_daap.c | 14 ++++++------ src/httpd_dacp.c | 2 +- src/httpd_rsp.c | 2 +- src/misc.c | 40 +++++++++++++++++++++++++++++++++ src/misc.h | 7 ++++++ src/mpd.c | 14 ++++++------ 8 files changed, 80 insertions(+), 66 deletions(-) diff --git a/src/httpd.c b/src/httpd.c index b5c6cdd0..4560c9dd 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -879,6 +879,7 @@ struct httpd_request * httpd_request_parse(struct evhttp_request *req, struct httpd_uri_parsed *uri_parsed, const char *user_agent, struct httpd_uri_map *uri_map) { struct httpd_request *hreq; + struct evhttp_connection *evcon; struct evkeyvalq *headers; int i; int ret; @@ -890,12 +891,19 @@ httpd_request_parse(struct evhttp_request *req, struct httpd_uri_parsed *uri_par hreq->uri_parsed = uri_parsed; hreq->query = &(uri_parsed->ev_query); - if (req && !user_agent) + if (req) { headers = evhttp_request_get_input_headers(req); hreq->user_agent = evhttp_find_header(headers, "User-Agent"); + + evcon = evhttp_request_get_connection(req); + if (evcon) + evhttp_connection_get_peer(evcon, &hreq->peer_address, &hreq->peer_port); + else + DPRINTF(E_LOG, L_HTTPD, "Connection to client lost or missing\n"); } - else + + if (user_agent) hreq->user_agent = user_agent; // Find a handler for the path @@ -1400,44 +1408,14 @@ httpd_redirect_to_index(struct evhttp_request *req, const char *uri) httpd_send_reply(req, HTTP_MOVETEMP, "Moved", NULL, HTTPD_SEND_NO_GZIP); } -/* |:todo:|This is also needed for mpd and should probably go somewhere else. */ bool -peer_address_is_trusted(const char *addr) -{ - cfg_t *section; - const char *network; - int i; - int n; - - if (strncmp(addr, "::ffff:", strlen("::ffff:")) == 0) - addr += strlen("::ffff:"); - - section = cfg_getsec(cfg, "general"); - - n = cfg_size(section, "trusted_networks"); - for (i = 0; i < n; i++) - { - network = cfg_getnstr(section, "trusted_networks", i); - - if (strncmp(network, addr, strlen(network)) == 0) - return true; - - if ((strcmp(network, "localhost") == 0) && (strcmp(addr, "127.0.0.1") == 0 || strcmp(addr, "::1") == 0)) - return true; - - if (strcmp(network, "any") == 0) - return true; - } - - return false; -} - -bool -httpd_peer_is_trusted(struct evhttp_request *req) +httpd_admin_check_auth(struct evhttp_request *req) { struct evhttp_connection *evcon; char *addr; uint16_t port; + const char *passwd; + int ret; evcon = evhttp_request_get_connection(req); if (!evcon) @@ -1447,16 +1425,8 @@ httpd_peer_is_trusted(struct evhttp_request *req) } evhttp_connection_get_peer(evcon, &addr, &port); - return peer_address_is_trusted(addr); -} -bool -httpd_admin_check_auth(struct evhttp_request *req) -{ - const char *passwd; - int ret; - - if (httpd_peer_is_trusted(req)) + if (peer_address_is_trusted(addr)) return true; passwd = cfg_getstr(cfg_getsec(cfg, "general"), "admin_password"); diff --git a/src/httpd.h b/src/httpd.h index 52158600..f6daa019 100644 --- a/src/httpd.h +++ b/src/httpd.h @@ -51,6 +51,9 @@ struct httpd_request { struct evkeyvalq *query; // http request struct (if available) struct evhttp_request *req; + // Source IP address (ipv4 or ipv6) and port of the request (if available) + char *peer_address; + unsigned short peer_port; // A pointer to extra data that the module handling the request might need void *extra_data; @@ -147,12 +150,6 @@ httpd_redirect_to_admin(struct evhttp_request *req); void httpd_redirect_to_index(struct evhttp_request *req, const char *uri); -bool -peer_address_is_trusted(const char *addr); - -bool -httpd_peer_is_trusted(struct evhttp_request *req); - bool httpd_admin_check_auth(struct evhttp_request *req); diff --git a/src/httpd_daap.c b/src/httpd_daap.c index 3bc9203d..831cd227 100644 --- a/src/httpd_daap.c +++ b/src/httpd_daap.c @@ -715,7 +715,7 @@ daap_request_authorize(struct httpd_request *hreq) char *passwd; int ret; - if (httpd_peer_is_trusted(hreq->req)) + if (peer_address_is_trusted(hreq->peer_address)) return 0; param = evhttp_find_header(hreq->query, "session-id"); @@ -913,11 +913,11 @@ daap_reply_login(struct httpd_request *hreq) CHECK_ERR(L_DAAP, evbuffer_expand(hreq->reply, 32)); param = evhttp_find_header(hreq->query, "pairing-guid"); - if (param && !httpd_peer_is_trusted(hreq->req)) + if (param && !peer_address_is_trusted(hreq->peer_address)) { if (strlen(param) < 3) { - DPRINTF(E_LOG, L_DAAP, "Login attempt with invalid pairing-guid: %s\n", param); + DPRINTF(E_LOG, L_DAAP, "Login attempt from %s with invalid pairing-guid: %s\n", hreq->peer_address, param); return DAAP_REPLY_FORBIDDEN; } @@ -927,20 +927,20 @@ daap_reply_login(struct httpd_request *hreq) ret = db_pairing_fetch_byguid(&pi); if (ret < 0) { - DPRINTF(E_LOG, L_DAAP, "Login attempt with invalid pairing-guid: %s\n", param); + DPRINTF(E_LOG, L_DAAP, "Login attempt from %s with invalid pairing-guid: %s\n", hreq->peer_address, param); free_pi(&pi, 1); return DAAP_REPLY_FORBIDDEN; } - DPRINTF(E_INFO, L_DAAP, "Remote '%s' logging in with GUID %s\n", pi.name, pi.guid); + DPRINTF(E_INFO, L_DAAP, "Remote '%s' (%s) logging in with GUID %s\n", pi.name, hreq->peer_address, pi.guid); free_pi(&pi, 1); } else { if (hreq->user_agent) - DPRINTF(E_INFO, L_DAAP, "Client '%s' logging in\n", hreq->user_agent); + DPRINTF(E_INFO, L_DAAP, "Client '%s' logging in from %s\n", hreq->user_agent, hreq->peer_address); else - DPRINTF(E_INFO, L_DAAP, "Client (unknown user-agent) logging in\n"); + DPRINTF(E_INFO, L_DAAP, "Client (unknown user-agent) logging in from %s\n", hreq->peer_address); } param = evhttp_find_header(hreq->query, "request-session-id"); diff --git a/src/httpd_dacp.c b/src/httpd_dacp.c index ccef9194..ea21e039 100644 --- a/src/httpd_dacp.c +++ b/src/httpd_dacp.c @@ -547,7 +547,7 @@ dacp_request_authorize(struct httpd_request *hreq) int32_t id; int ret; - if (httpd_peer_is_trusted(hreq->req)) + if (peer_address_is_trusted(hreq->peer_address)) return 0; param = evhttp_find_header(hreq->query, "session-id"); diff --git a/src/httpd_rsp.c b/src/httpd_rsp.c index 3ce9e49d..21db569c 100644 --- a/src/httpd_rsp.c +++ b/src/httpd_rsp.c @@ -284,7 +284,7 @@ rsp_request_authorize(struct httpd_request *hreq) char *passwd; int ret; - if (httpd_peer_is_trusted(hreq->req)) + if (peer_address_is_trusted(hreq->peer_address)) return 0; passwd = cfg_getstr(cfg_getsec(cfg, "library"), "password"); diff --git a/src/misc.c b/src/misc.c index 748555b6..f046d372 100644 --- a/src/misc.c +++ b/src/misc.c @@ -43,6 +43,7 @@ #include #include "logger.h" +#include "conffile.h" #include "misc.h" @@ -992,6 +993,45 @@ murmur_hash64(const void *key, int len, uint32_t seed) # error Platform not supported #endif + +bool +peer_address_is_trusted(const char *addr) +{ + cfg_t *section; + const char *network; + int i; + int n; + + if (!addr) + return false; + + if (strncmp(addr, "::ffff:", strlen("::ffff:")) == 0) + addr += strlen("::ffff:"); + + section = cfg_getsec(cfg, "general"); + + n = cfg_size(section, "trusted_networks"); + for (i = 0; i < n; i++) + { + network = cfg_getnstr(section, "trusted_networks", i); + + if (!network || network[0] == '\0') + return false; + + if (strncmp(network, addr, strlen(network)) == 0) + return true; + + if ((strcmp(network, "localhost") == 0) && (strcmp(addr, "127.0.0.1") == 0 || strcmp(addr, "::1") == 0)) + return true; + + if (strcmp(network, "any") == 0) + return true; + } + + return false; +} + + int clock_gettime_with_res(clockid_t clock_id, struct timespec *tp, struct timespec *res) { diff --git a/src/misc.h b/src/misc.h index 1337c307..6effbbc1 100644 --- a/src/misc.h +++ b/src/misc.h @@ -7,6 +7,7 @@ #endif #include +#include #include #include @@ -104,6 +105,12 @@ b64_encode(const uint8_t *in, size_t len); uint64_t murmur_hash64(const void *key, int len, uint32_t seed); + +/* Checks if the address is in a network that is configured as trusted */ +bool +peer_address_is_trusted(const char *addr); + + #ifndef HAVE_CLOCK_GETTIME #ifndef CLOCK_REALTIME diff --git a/src/mpd.c b/src/mpd.c index c735f27f..55ddc325 100644 --- a/src/mpd.c +++ b/src/mpd.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -43,9 +44,6 @@ #include #include -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -# include -#endif #include "artwork.h" #include "commands.h" @@ -4614,26 +4612,28 @@ mpd_input_filter(struct evbuffer *src, struct evbuffer *dst, ev_ssize_t lim, enu return BEV_OK; } -/* |:todo:| This should probably go somewhere else. */ static const char * sockaddr_to_string(const struct sockaddr *address, char *addr_str, int addr_str_len) { + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; const char *ret; if (address->sa_family == AF_INET) { - struct sockaddr_in *addr = (struct sockaddr_in *)address; + addr = (struct sockaddr_in *)address; ret = evutil_inet_ntop(AF_INET, &addr->sin_addr, addr_str, addr_str_len); } else if (address->sa_family == AF_INET6) { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)address; + addr6 = (struct sockaddr_in6 *)address; ret = evutil_inet_ntop(AF_INET6, &addr6->sin6_addr, addr_str, addr_str_len); } else { ret = NULL; } + return ret; } @@ -4659,6 +4659,7 @@ mpd_accept_conn_cb(struct evconnlistener *listener, struct event_base *base = evconnlistener_get_base(listener); struct bufferevent *bev = bufferevent_socket_new(base, sock, BEV_OPT_CLOSE_ON_FREE); struct mpd_cmd_ctx *cmd_ctx = (struct mpd_cmd_ctx *)malloc(sizeof(struct mpd_cmd_ctx)); + char addr_str[INET6_ADDRSTRLEN]; if (!cmd_ctx) { @@ -4670,7 +4671,6 @@ mpd_accept_conn_cb(struct evconnlistener *listener, cmd_ctx->authenticated = !cfg_getstr(cfg_getsec(cfg, "library"), "password"); if (!cmd_ctx->authenticated) { - char addr_str[INET6_ADDRSTRLEN]; sockaddr_to_string(address, addr_str, sizeof(addr_str)); cmd_ctx->authenticated = peer_address_is_trusted(addr_str); }