From bf76aeeba1cf868ebe4d2f28976abb75c48031b0 Mon Sep 17 00:00:00 2001 From: rofl0r Date: Fri, 23 Feb 2018 20:21:32 +0000 Subject: [PATCH] implement HTTP basic auth for upstream proxies loosely based on @valenbg1's code from PR #38 closes #38 closes #96 --- etc/tinyproxy.conf.in | 3 +++ src/conf.c | 44 +++++++++++++++++++++++++++---------------- src/reqs.c | 11 +++++++++++ src/upstream.c | 26 +++++++++++++++++++++++-- src/upstream.h | 6 ++++++ 5 files changed, 72 insertions(+), 18 deletions(-) diff --git a/etc/tinyproxy.conf.in b/etc/tinyproxy.conf.in index c43266b..ac16efe 100644 --- a/etc/tinyproxy.conf.in +++ b/etc/tinyproxy.conf.in @@ -146,6 +146,9 @@ LogLevel Info # upstream testproxy:8008 ".our_testbed.example.com" # upstream testproxy:8008 "192.168.128.0/255.255.254.0" # +# # upstream proxy using basic authentication +# upstream user:pass@testproxy:8008 ".test.domain.invalid" +# # # no upstream proxy for internal websites and unqualified hosts # no upstream ".internal.example.com" # no upstream "www.example.com" diff --git a/src/conf.c b/src/conf.c index 80bdab8..7f62172 100644 --- a/src/conf.c +++ b/src/conf.c @@ -259,8 +259,11 @@ struct { BEGIN "(no" WS "upstream)" WS STR END, handle_upstream_no, NULL }, { - BEGIN "(upstream)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR - ")?" END, handle_upstream, NULL + BEGIN "(upstream)" WS + "(" ALNUM /*username*/ ":" ALNUM /*password*/ "@" ")?" + "(" IP "|" ALNUM ")" + ":" INT "(" WS STR ")?" + END, handle_upstream, NULL }, { BEGIN "(upstream4)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR @@ -1100,24 +1103,33 @@ static int _handle_upstream(struct config_s* conf, const char* line, regmatch_t match[], proxy_type type) { char *ip; - int port; - char *domain; + int port, mi = 3; + char *domain = 0, *user = 0, *pass = 0; - ip = get_string_arg (line, &match[2]); + if (match[mi].rm_so != -1) + user = get_string_arg (line, &match[mi]); + mi++; + + if (match[mi].rm_so != -1) + pass = get_string_arg (line, &match[mi]); + mi++; + + ip = get_string_arg (line, &match[mi]); if (!ip) return -1; - port = (int) get_long_arg (line, &match[7]); + mi += 5; - if (match[10].rm_so != -1) { - domain = get_string_arg (line, &match[10]); - if (domain) { - upstream_add (ip, port, domain, type, &conf->upstream_list); - safefree (domain); - } - } else { - upstream_add (ip, port, NULL, type, &conf->upstream_list); - } + port = (int) get_long_arg (line, &match[mi]); + mi += 3; + if (match[mi].rm_so != -1) + domain = get_string_arg (line, &match[mi]); + + upstream_add (ip, port, domain, user, pass, type, &conf->upstream_list); + + safefree (user); + safefree (pass); + safefree (domain); safefree (ip); return 0; @@ -1146,7 +1158,7 @@ static HANDLE_FUNC (handle_upstream_no) if (!domain) return -1; - upstream_add (NULL, 0, domain, HTTP_TYPE, &conf->upstream_list); + upstream_add (NULL, 0, domain, 0, 0, HTTP_TYPE, &conf->upstream_list); safefree (domain); return 0; diff --git a/src/reqs.c b/src/reqs.c index 0e4e5f7..180b35a 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -270,6 +270,17 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request) "Connection: close\r\n", request->method, request->path, request->host, portbuff); + } else if (connptr->upstream_proxy && + connptr->upstream_proxy->type == HTTP_TYPE && + connptr->upstream_proxy->ua.authstr) { + return write_message (connptr->server_fd, + "%s %s HTTP/1.0\r\n" + "Host: %s%s\r\n" + "Connection: close\r\n" + "Proxy-Authorization: Basic %s\r\n", + request->method, request->path, + request->host, portbuff, + connptr->upstream_proxy->ua.authstr); } else { return write_message (connptr->server_fd, "%s %s HTTP/1.0\r\n" diff --git a/src/upstream.c b/src/upstream.c index 91bf457..03a6b8e 100644 --- a/src/upstream.c +++ b/src/upstream.c @@ -27,6 +27,8 @@ #include "upstream.h" #include "heap.h" #include "log.h" +#include "base64.h" +#include "basicauth.h" #ifdef UPSTREAM_SUPPORT const char * @@ -44,6 +46,7 @@ proxy_type_name(proxy_type type) * Construct an upstream struct from input data. */ static struct upstream *upstream_build (const char *host, int port, const char *domain, + const char *user, const char *pass, proxy_type type) { char *ptr; @@ -57,8 +60,24 @@ static struct upstream *upstream_build (const char *host, int port, const char * } up->type = type; - up->host = up->domain = NULL; + up->host = up->domain = up->ua.user = up->pass = NULL; up->ip = up->mask = 0; + if (user) { + if (type == HTTP_TYPE) { + char b[BASE64ENC_BYTES((256+2)-1) + 1]; + ssize_t ret; + ret = basicauth_string(user, pass, b, sizeof b); + if (ret == 0) { + log_message (LOG_ERR, + "User / pass in upstream config too long"); + return NULL; + } + up->ua.authstr = safestrdup (b); + } else { + up->ua.user = safestrdup (user); + up->pass = safestrdup (pass); + } + } if (domain == NULL) { if (!host || host[0] == '\0' || port < 1) { @@ -121,6 +140,8 @@ static struct upstream *upstream_build (const char *host, int port, const char * return up; fail: + safefree (up->ua.user); + safefree (up->pass); safefree (up->host); safefree (up->domain); safefree (up); @@ -132,11 +153,12 @@ fail: * Add an entry to the upstream list */ void upstream_add (const char *host, int port, const char *domain, + const char *user, const char *pass, proxy_type type, struct upstream **upstream_list) { struct upstream *up; - up = upstream_build (host, port, domain, type); + up = upstream_build (host, port, domain, user, pass, type); if (up == NULL) { return; } diff --git a/src/upstream.h b/src/upstream.h index 7855214..9b664c8 100644 --- a/src/upstream.h +++ b/src/upstream.h @@ -36,6 +36,11 @@ struct upstream { struct upstream *next; char *domain; /* optional */ char *host; + union { + char *user; + char *authstr; + } ua; + char *pass; int port; in_addr_t ip, mask; proxy_type type; @@ -44,6 +49,7 @@ struct upstream { #ifdef UPSTREAM_SUPPORT const char *proxy_type_name(proxy_type type); extern void upstream_add (const char *host, int port, const char *domain, + const char *user, const char *pass, proxy_type type, struct upstream **upstream_list); extern struct upstream *upstream_get (char *host, struct upstream *up); extern void free_upstream_list (struct upstream *up);