diff options
-rw-r--r-- | etc/tinyproxy.conf.in | 5 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/basicauth.c | 122 | ||||
-rw-r--r-- | src/basicauth.h | 31 | ||||
-rw-r--r-- | src/conf.c | 25 | ||||
-rw-r--r-- | src/conf.h | 1 | ||||
-rw-r--r-- | src/reqs.c | 25 |
7 files changed, 210 insertions, 0 deletions
diff --git a/etc/tinyproxy.conf.in b/etc/tinyproxy.conf.in index bca638a..c43266b 100644 --- a/etc/tinyproxy.conf.in +++ b/etc/tinyproxy.conf.in @@ -215,6 +215,11 @@ MaxRequestsPerChild 0 # Allow 127.0.0.1 +# BasicAuth: HTTP "Basic Authentication" for accessing the proxy. +# If there are any entries specified, access is only granted for authenticated +# users. +#BasicAuth user password + # # AddHeader: Adds the specified headers to outgoing HTTP requests that # Tinyproxy makes. Note that this option will not work for HTTPS diff --git a/src/Makefile.am b/src/Makefile.am index c42b0dd..60fda2c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,6 +47,7 @@ tinyproxy_SOURCES = \ utils.c utils.h \ vector.c vector.h \ upstream.c upstream.h \ + basicauth.c basicauth.h \ connect-ports.c connect-ports.h EXTRA_tinyproxy_SOURCES = filter.c filter.h \ diff --git a/src/basicauth.c b/src/basicauth.c new file mode 100644 index 0000000..ddc6e6e --- /dev/null +++ b/src/basicauth.c @@ -0,0 +1,122 @@ +/* tinyproxy - A fast light-weight HTTP proxy + * This file: Copyright (C) 2016-2017 rofl0r + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "main.h" +#include "basicauth.h" + +#include "conns.h" +#include "heap.h" +#include "html-error.h" +#include "log.h" +#include "conf.h" + +/* calculates number of bytes base64-encoded stream of N bytes will take. */ +#define BASE64ENC_BYTES(N) (((N+2)/3)*4) + +static const char base64_tbl[64] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* my own base64 impl (taken from libulz) */ +static void base64enc(char *dst, const void* src, size_t count) +{ + unsigned const char *s = src; + char* d = dst; + while(count) { + int i = 0, n = *s << 16; + s++; + count--; + if(count) { + n |= *s << 8; + s++; + count--; + i++; + } + if(count) { + n |= *s; + s++; + count--; + i++; + } + *d++ = base64_tbl[(n >> 18) & 0x3f]; + *d++ = base64_tbl[(n >> 12) & 0x3f]; + *d++ = i ? base64_tbl[(n >> 6) & 0x3f] : '='; + *d++ = i == 2 ? base64_tbl[n & 0x3f] : '='; + } + *d = 0; +} + +/* + * Add entry to the basicauth list + */ +void basicauth_add (vector_t authlist, + const char *user, const char *pass) +{ + char tmp[256+2]; + char b[BASE64ENC_BYTES((sizeof tmp)-1) + 1]; + int l; + size_t bl; + + if (user == NULL || pass == NULL) { + log_message (LOG_WARNING, + "Illegal basicauth rule: missing user or pass"); + return; + } + + l = snprintf(tmp, sizeof tmp, "%s:%s", user, pass); + + if(l >= (ssize_t) sizeof tmp) { + log_message (LOG_WARNING, + "User / pass in basicauth rule too long"); + return; + } + + base64enc(b, tmp, l); + bl = BASE64ENC_BYTES(l) + 1; + + if (vector_append(authlist, b, bl) == -ENOMEM) { + log_message (LOG_ERR, + "Unable to allocate memory in basicauth_add()"); + return; + } + + log_message (LOG_INFO, + "Added basic auth user : %s", user); +} + +/* + * Check if a user/password combination (encoded as base64) + * is in the basicauth list. + * return 1 on success, 0 on failure. + */ +int basicauth_check (vector_t authlist, const char *authstring) +{ + ssize_t vl, i; + size_t al, el; + const char* entry; + + vl = vector_length (authlist); + if (vl == -EINVAL) return 0; + + al = strlen (authstring); + for (i = 0; i < vl; i++) { + entry = vector_getentry (authlist, i, &el); + if (strncmp (authstring, entry, al) == 0) + return 1; + } + return 0; +} diff --git a/src/basicauth.h b/src/basicauth.h new file mode 100644 index 0000000..e9366bb --- /dev/null +++ b/src/basicauth.h @@ -0,0 +1,31 @@ +/* tinyproxy - A fast light-weight HTTP proxy + * Copyright (C) 2005 Robert James Kaes <rjkaes@users.sourceforge.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* See 'basicauth.c' for detailed information. */ + +#ifndef TINYPROXY_BASICAUTH_H +#define TINYPROXY_BASICAUTH_H + +#include "vector.h" + +extern void basicauth_add (vector_t authlist, + const char *user, const char *pass); + +extern int basicauth_check (vector_t authlist, const char *authstring); + +#endif @@ -36,6 +36,7 @@ #include "reverse-proxy.h" #include "upstream.h" #include "connect-ports.h" +#include "basicauth.h" /* * The configuration directives are defined in the structure below. Each @@ -116,6 +117,7 @@ static HANDLE_FUNC (handle_nop) } /* do nothing function */ static HANDLE_FUNC (handle_allow); +static HANDLE_FUNC (handle_basicauth); static HANDLE_FUNC (handle_anonymous); static HANDLE_FUNC (handle_bind); static HANDLE_FUNC (handle_bindsame); @@ -232,6 +234,7 @@ struct { handle_deny), STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind), /* other */ + STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth), STDCONF ("errorfile", INT WS STR, handle_errorfile), STDCONF ("addheader", STR WS STR, handle_addheader), @@ -299,6 +302,7 @@ static void free_config (struct config_s *conf) safefree (conf->user); safefree (conf->group); vector_delete(conf->listen_addrs); + vector_delete(conf->basicauth_list); #ifdef FILTER_ENABLE safefree (conf->filter); #endif /* FILTER_ENABLE */ @@ -1000,6 +1004,27 @@ static HANDLE_FUNC (handle_loglevel) return -1; } +static HANDLE_FUNC (handle_basicauth) +{ + char *user, *pass; + user = get_string_arg(line, &match[2]); + if (!user) + return -1; + pass = get_string_arg(line, &match[3]); + if (!pass) { + safefree (user); + return -1; + } + if (!conf->basicauth_list) { + conf->basicauth_list = vector_create (); + } + + basicauth_add (conf->basicauth_list, user, pass); + safefree (user); + safefree (pass); + return 0; +} + #ifdef FILTER_ENABLE static HANDLE_FUNC (handle_filter) { @@ -37,6 +37,7 @@ typedef struct { * Hold all the configuration time information. */ struct config_s { + vector_t basicauth_list; char *logf_name; char *config_file; unsigned int syslog; /* boolean */ @@ -48,6 +48,7 @@ #include "upstream.h" #include "connect-ports.h" #include "conf.h" +#include "basicauth.h" /* * Maximum length of a HTTP line @@ -1562,6 +1563,30 @@ void handle_connection (int fd) goto fail; } + if (config.basicauth_list != NULL) { + ssize_t len; + char *authstring; + int failure = 1; + len = hashmap_entry_by_key (hashofheaders, "proxy-authorization", + (void **) &authstring); + if (len > 0 && + /* currently only "basic" auth supported */ + (strncmp(authstring, "Basic ", 6) == 0 || + strncmp(authstring, "basic ", 6) == 0) && + basicauth_check (config.basicauth_list, authstring + 6) == 1) + failure = 0; + if(failure) { + update_stats (STAT_DENIED); + indicate_http_error (connptr, 403, "Access denied", + "detail", + "The administrator of this proxy has not configured " + "it to service requests from you.", + NULL); + goto fail; + } + hashmap_remove (hashofheaders, "proxy-authorization"); + } + /* * Add any user-specified headers (AddHeader directive) to the * outgoing HTTP request. |