/*
- * DEBUG: section 0 CGI Cache Manager
- * AUTHOR: Duane Wessels
- *
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+ * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
*
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
*/
-#include "config.h"
+#include "squid.h"
+#include "base64.h"
+#include "getfullhostname.h"
+#include "html_quote.h"
+#include "ip/Address.h"
+#include "rfc1123.h"
#include "rfc1738.h"
+#include "util.h"
+#include <cctype>
+#include <cerrno>
+#include <csignal>
+#include <cstring>
+#include <ctime>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
-#if HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#if HAVE_STDIO_H
-#include <stdio.h>
-#endif
-#if HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#if HAVE_CTYPE_H
-#include <ctype.h>
-#endif
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_MEMORY_H
#include <memory.h>
#endif
-#if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_) /* protect NEXTSTEP */
-#define _SQUID_NETDB_H_
+#if HAVE_NETDB_H
#include <netdb.h>
#endif
#if HAVE_PWD_H
#include <pwd.h>
#endif
-#if HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#if HAVE_TIME_H
-#include <time.h>
-#endif
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
-#if HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if HAVE_SYS_RESOURCE_H
-#include <sys/resource.h> /* needs sys/time.h above it */
-#endif
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#if HAVE_LIBC_H
#include <libc.h>
#endif
-#if HAVE_STRING_H
-#include <string.h>
-#endif
#if HAVE_STRINGS_H
#include <strings.h>
#endif
#if HAVE_CRYPT_H
#include <crypt.h>
#endif
-#if HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
#if HAVE_FNMATCH_H
extern "C" {
#include <fnmatch.h>
}
#endif
-#include "util.h"
-#include "ip/IpAddress.h"
-#include "getfullhostname.h"
-
#ifndef DEFAULT_CACHEMGR_CONFIG
#define DEFAULT_CACHEMGR_CONFIG "/etc/squid/cachemgr.conf"
#endif
char *user_name;
char *passwd;
char *pub_auth;
+ char *workers;
+ char *processes;
} cachemgr_request;
/*
* Static variables and constants
*/
-static const time_t passwd_ttl = 60 * 60 * 3; /* in sec */
+static const time_t passwd_ttl = 60 * 60 * 3; /* in sec */
static const char *script_name = "/cgi-bin/cachemgr.cgi";
static const char *progname = NULL;
static time_t now;
/*
* Function prototypes
*/
-#define safe_free(str) { if (str) { xfree(str); (str) = NULL; } }
static const char *safe_str(const char *str);
static const char *xstrtok(char **str, char del);
static void print_trailer(void);
static int check_target_acl(const char *hostname, int port);
-#ifdef _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
static int s_iInitCount = 0;
int Win32SockInit(void)
int err;
if (s_iInitCount > 0) {
- s_iInitCount++;
+ ++s_iInitCount;
return (0);
} else if (s_iInitCount < 0)
return (s_iInitCount);
return (s_iInitCount);
}
- s_iInitCount++;
+ ++s_iInitCount;
return (s_iInitCount);
}
return;
}
-#endif /* ifdef _SQUID_MSWIN_ */
+#endif
static const char *
safe_str(const char *str)
tok[--len] = '\0';
while (xisspace(*tok))
- tok++;
+ ++tok;
return tok;
} else
if (!host || !strlen(host))
host = "";
+ fp = fopen("cachemgr.conf", "r");
+
+ if (fp == NULL)
+ fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
+
+ if (fp == NULL)
+ printf("X-Error: message=\"Unable to open config %s\"", DEFAULT_CACHEMGR_CONFIG);
+
printf("Content-Type: text/html\r\n\r\n");
printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
printf("<HTML><HEAD><TITLE>Cache Manager Interface</TITLE>\n");
- printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE></HEAD>\n");
+ printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n");
+
+ printf("<script type=\"text/javascript\">\n");
+ printf("function TS(t, s) {\n");
+ printf(" var x = new XMLHttpRequest();\n");
+ printf(" x.open('GET', 'http' + s + '://' + t + '/squid-internal-mgr/', true);\n");
+ printf(" x.onreadystatechange=function() {\n");
+ printf(" if (x.readyState==4) {\n");
+ printf(" if ((x.status>=200 && x.status <= 299) || x.status==401) {\n");
+ printf(" var v = x.getResponseHeader('Server');\n");
+ printf(" if (v.substring(0,8) == 'squid/3.' && (v[8]=='H' || parseInt(v.substring(8)) >= 2)) {\n");
+ printf(" var d = document.getElementById('H' + s + 'mgr');\n");
+ printf(" if (d.innerHTML == '') d.innerHTML = '<h2>HTTP' + (s=='s'?'S':'') + ' Managed Proxies</h2>';\n");
+ printf(" d.innerHTML = d.innerHTML + '<p>Host: <a href=\"http' + s + '://' + t + '/squid-internal-mgr/\">' + t + '</a></p>';\n");
+ printf(" }}}}\n");
+ printf(" x.send(null);\n");
+ printf("}\n");
+ printf("</script>\n");
+
+ printf("</HEAD>\n");
printf("<BODY><H1>Cache Manager Interface</H1>\n");
printf("<HR noshade size=\"1px\">\n");
+ printf("<div id=\"Hsmgr\"></div>\n");
+ printf("<div id=\"Hmgr\"></div>\n");
+ printf("<div id=\"Cmgr\">\n");
+ printf("<h2>CGI Managed Proxies</h2>\n");
printf("<FORM METHOD=\"POST\" ACTION=\"%s\">\n", script_name);
printf("<TABLE BORDER=\"0\" CELLPADDING=\"10\" CELLSPACING=\"1\">\n");
-
- fp = fopen("cachemgr.conf", "r");
-
- if (fp == NULL)
- fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
-
if (fp != NULL) {
int servers = 0;
char config_line[BUFSIZ];
if (comment)
while (*comment == ' ' || *comment == '\t')
- comment++;
+ ++comment;
if (!comment || !*comment)
comment = server;
- if (!servers) {
- printf("<TR><TH ALIGN=\"left\">Cache Server:</TH><TD><SELECT NAME=\"server\">\n");
- }
+ if (!servers)
+ printf("<TR><TH ALIGN=\"left\">Cache Server:</TH><TD><SELECT id=\"server\" NAME=\"server\">\n");
printf("<OPTION VALUE=\"%s\"%s>%s</OPTION>\n", server, (servers || *host) ? "" : " SELECTED", comment);
- servers++;
+ ++servers;
}
if (servers) {
printf("<INPUT TYPE=\"submit\" VALUE=\"Continue...\">\n");
- printf("</FORM>\n");
+ printf("</FORM></div>\n");
+
+ printf("<script type=\"text/javascript\">\n");
+ printf("var s = document.getElementById(\"server\");\n");
+ printf("for (var i = 0; i < s.childElementCount; i++) {\n");
+ printf(" TS(s.children[i].value, '');\n");
+ printf(" TS(s.children[i].value, 's');\n");
+ printf("}</script>\n");
print_trailer();
}
}
static const char *
-munge_other_line(const char *buf, cachemgr_request * req)
+munge_other_line(const char *buf, cachemgr_request *)
{
static const char *ttags[] = {"td", "th"};
const char *cell = xstrtok(&x, '\t');
while (x && *x == '\t') {
- column_span++;
- x++;
+ ++column_span;
+ ++x;
}
l += snprintf(html + l, sizeof(html) - l, "<%s colspan=\"%d\" align=\"%s\">%s</%s>",
xfree(buf_copy);
/* record ends */
- l += snprintf(html + l, sizeof(html) - l, "</tr>\n");
+ snprintf(html + l, sizeof(html) - l, "</tr>\n");
next_is_header = is_header && strstr(buf, "\t\t");
- table_line_num++;
+ ++table_line_num;
return html;
}
if ((p = strchr(x, '\n')))
*p = '\0';
action = xstrtok(&x, '\t');
+ if (!action) {
+ xfree(buf);
+ return "";
+ }
description = xstrtok(&x, '\t');
if (!description)
description = action;
- if (!action)
- return "";
snprintf(html, sizeof(html), " <a href=\"%s\">%s</a>", menu_url(req, action), description);
+ xfree(buf);
return html;
}
read_reply(int s, cachemgr_request * req)
{
char buf[4 * 1024];
-#ifdef _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
int reply;
char *tmpfile = tempnam(NULL, "tmp0000");
parse_menu = 1;
if (fp == NULL) {
-#ifdef _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
perror(tmpfile);
xfree(tmpfile);
#else
return 1;
}
-#ifdef _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
while ((reply=recv(s, buf , sizeof(buf), 0)) > 0)
fwrite(buf, 1, reply, fp);
if (status == 401 || status == 407) {
reset_auth(req);
- status = 403; /* Forbiden, see comments in case isForward: */
+ status = 403; /* Forbiden, see comments in case isForward: */
}
/* this is a way to pass HTTP status to the Web server */
if (statusStr)
- printf("Status: %d %s", status, statusStr); /* statusStr has '\n' */
+ printf("Status: %d %s", status, statusStr); /* statusStr has '\n' */
break;
case isHeaders:
/* forward header field */
- if (!strcmp(buf, "\r\n")) { /* end of headers */
- fputs("Content-Type: text/html\r\n", stdout); /* add our type */
+ if (!strcmp(buf, "\r\n")) { /* end of headers */
+ fputs("Content-Type: text/html\r\n", stdout); /* add our type */
istate = isBodyStart;
}
- if (strncasecmp(buf, "Content-Type:", 13)) /* filter out their type */
+ if (strncasecmp(buf, "Content-Type:", 13)) /* filter out their type */
fputs(buf, stdout);
break;
}
istate = isActions;
- /* yes, fall through, we do not want to loose the first line */
+ /* yes, fall through, we do not want to loose the first line */
case isActions:
if (strncmp(buf, "action:", 7) == 0) {
}
istate = isBody;
- /* yes, fall through, we do not want to loose the first line */
+ /* yes, fall through, we do not want to loose the first line */
case isBody:
/* interpret [and reformat] cache response */
* 401 to .cgi because web server filters out all auth info. Thus we
* disable authentication headers for now.
*/
- if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19)); /* skip */
+ if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19)); /* skip */
else
fputs(buf, stdout);
}
fclose(fp);
-#ifdef _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
remove(tmpfile);
xfree(tmpfile);
char ipbuf[MAX_IPSTRLEN];
struct addrinfo *AI = NULL;
- IpAddress S;
+ Ip::Address S;
int s;
int l;
}
if (!check_target_acl(req->hostname, req->port)) {
- snprintf(buf, 1024, "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port);
+ snprintf(buf, sizeof(buf), "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port);
error_html(buf);
return 1;
}
S = *gethostbyname(req->hostname);
- if ( !S.IsAnyAddr() ) {
+ if ( !S.isAnyAddr() ) {
(void) 0;
- } else if ( S = req->hostname)
+ } else if ((S = req->hostname))
(void) 0;
else {
- snprintf(buf, 1024, "Unknown host: %s\n", req->hostname);
+ snprintf(buf, sizeof(buf), "Unknown host: %s\n", req->hostname);
error_html(buf);
return 1;
}
- S.SetPort(req->port);
+ S.port(req->port);
- S.GetAddrInfo(AI);
+ S.getAddrInfo(AI);
#if USE_IPV6
if ((s = socket( AI->ai_family, SOCK_STREAM, 0)) < 0) {
#else
if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
#endif
- snprintf(buf, 1024, "socket: %s\n", xstrerror());
+ snprintf(buf, sizeof(buf), "socket: %s\n", xstrerror());
error_html(buf);
+ Ip::Address::FreeAddr(AI);
return 1;
}
if (connect(s, AI->ai_addr, AI->ai_addrlen) < 0) {
- snprintf(buf, 1024, "connect %s: %s\n",
- S.ToURL(ipbuf,MAX_IPSTRLEN),
+ snprintf(buf, sizeof(buf), "connect %s: %s\n",
+ S.toUrl(ipbuf,MAX_IPSTRLEN),
xstrerror());
error_html(buf);
- S.FreeAddrInfo(AI);
+ Ip::Address::FreeAddr(AI);
+ close(s);
return 1;
}
- S.FreeAddrInfo(AI);
+ Ip::Address::FreeAddr(AI);
l = snprintf(buf, sizeof(buf),
- "GET cache_object://%s/%s HTTP/1.0\r\n"
+ "GET cache_object://%s/%s%s%s HTTP/1.0\r\n"
+ "User-Agent: cachemgr.cgi/%s\r\n"
"Accept: */*\r\n"
- "%s" /* Authentication info or nothing */
+ "%s" /* Authentication info or nothing */
"\r\n",
req->hostname,
req->action,
+ req->workers? "?workers=" : (req->processes ? "?processes=" : ""),
+ req->workers? req->workers : (req->processes ? req->processes: ""),
+ VERSION,
make_auth_header(req));
if (write(s, buf, l) < 0) {
fprintf(stderr,"ERROR: (%d) writing request: '%s'\n", errno, buf);
cachemgr_request *req;
now = time(NULL);
-#ifdef _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
Win32SockInit();
atexit(Win32SockCleanup);
value = args[1] + 2;
} else if (argc > 2) {
value = args[2];
- args++;
- argc--;
+ ++args;
+ --argc;
} else
value = "";
#endif
break;
}
- args++;
- argc--;
+ ++args;
+ --argc;
}
req = read_request();
read_post_request(void)
{
char *s;
- char *buf;
- int len;
if ((s = getenv("REQUEST_METHOD")) == NULL)
return NULL;
if ((s = getenv("CONTENT_LENGTH")) == NULL)
return NULL;
- if ((len = atoi(s)) <= 0)
+ if (*s == '-') // negative length content huh?
return NULL;
- buf = (char *)xmalloc(len + 1);
+ uint64_t len;
- if (fread(buf, len, 1, stdin) == 0)
+ char *endptr = s+ strlen(s);
+ if ((len = strtoll(s, &endptr, 10)) <= 0)
return NULL;
- buf[len] = '\0';
+ // limit the input to something reasonable.
+ // 4KB should be enough for the GET/POST data length, but may be extended.
+ size_t bufLen = (len < 4096 ? len : 4095);
+ char *buf = (char *)xmalloc(bufLen + 1);
+
+ size_t readLen = fread(buf, 1, bufLen, stdin);
+ if (readLen == 0) {
+ xfree(buf);
+ return NULL;
+ }
+ buf[readLen] = '\0';
+ len -= readLen;
+
+ // purge the remainder of the request entity
+ while (len > 0 && readLen) {
+ char temp[65535];
+ readLen = fread(temp, 1, 65535, stdin);
+ len -= readLen;
+ }
return buf;
}
else
return NULL;
-#ifdef _SQUID_MSWIN_
+#if _SQUID_WINDOWS_
if (strlen(buf) == 0 || strlen(buf) == 4000)
#else
if (strlen(buf) == 0)
#endif
{
- free(buf);
+ xfree(buf);
return NULL;
}
if ((q = strchr(t, '=')) == NULL)
continue;
- *q++ = '\0';
+ *q = '\0';
+ ++q;
rfc1738_unescape(t);
rfc1738_unescape(q);
- if (0 == strcasecmp(t, "server") && strlen(q))
+ if (0 == strcmp(t, "server") && strlen(q))
req->server = xstrdup(q);
- else if (0 == strcasecmp(t, "host") && strlen(q))
+ else if (0 == strcmp(t, "host") && strlen(q))
req->hostname = xstrdup(q);
- else if (0 == strcasecmp(t, "port") && strlen(q))
+ else if (0 == strcmp(t, "port") && strlen(q))
req->port = atoi(q);
- else if (0 == strcasecmp(t, "user_name") && strlen(q))
+ else if (0 == strcmp(t, "user_name") && strlen(q))
req->user_name = xstrdup(q);
- else if (0 == strcasecmp(t, "passwd") && strlen(q))
+ else if (0 == strcmp(t, "passwd") && strlen(q))
req->passwd = xstrdup(q);
- else if (0 == strcasecmp(t, "auth") && strlen(q))
+ else if (0 == strcmp(t, "auth") && strlen(q))
req->pub_auth = xstrdup(q), decode_pub_auth(req);
- else if (0 == strcasecmp(t, "operation"))
+ else if (0 == strcmp(t, "operation"))
req->action = xstrdup(q);
+ else if (0 == strcmp(t, "workers") && strlen(q))
+ req->workers = xstrdup(q);
+ else if (0 == strcmp(t, "processes") && strlen(q))
+ req->processes = xstrdup(q);
+ safe_free(t);
}
if (req->server && !req->hostname) {
}
make_pub_auth(req);
- debug("cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s'\n",
- safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action));
+ debug("cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s' workers: '%s' processes: '%s'\n",
+ safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action), safe_str(req->workers), safe_str(req->processes));
return req;
}
-
/* Routines to support authentication */
/*
return;
/* host | time | user | passwd */
- snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
- req->hostname,
- (int) now,
- req->user_name ? req->user_name : "",
- req->passwd);
-
+ const int bufLen = snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
+ req->hostname,
+ (int) now,
+ req->user_name ? req->user_name : "",
+ req->passwd);
debug("cmgr: pre-encoded for pub: %s\n", buf);
- debug("cmgr: encoded: '%s'\n", base64_encode(buf));
- req->pub_auth = xstrdup(base64_encode(buf));
+ const int encodedLen = base64_encode_len(bufLen);
+ req->pub_auth = (char *) xmalloc(encodedLen);
+ struct base64_encode_ctx ctx;
+ base64_encode_init(&ctx);
+ size_t blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(req->pub_auth), bufLen, reinterpret_cast<uint8_t*>(buf));
+ blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(req->pub_auth)+blen);
+ req->pub_auth[blen] = '\0';
+ debug("cmgr: encoded: '%s'\n", req->pub_auth);
}
static void
if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
return;
- buf = xstrdup(base64_decode(req->pub_auth));
+ size_t decodedLen = BASE64_DECODE_LENGTH(strlen(req->pub_auth));
+ buf = (char*)xmalloc(decodedLen);
+ struct base64_decode_ctx ctx;
+ base64_decode_init(&ctx);
+ if (!base64_decode_update(&ctx, &decodedLen, reinterpret_cast<uint8_t*>(buf), strlen(req->pub_auth), reinterpret_cast<const uint8_t*>(req->pub_auth)) ||
+ !base64_decode_final(&ctx)) {
+ debug("cmgr: base64 decode failure. Incomplete auth token string.\n");
+ xfree(buf);
+ return;
+ }
debug("cmgr: length ok\n");
/* parse ( a lot of memory leaks, but that is cachemgr style :) */
- if ((host_name = strtok(buf, "|")) == NULL)
+ if ((host_name = strtok(buf, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug("cmgr: decoded host: '%s'\n", host_name);
- if ((time_str = strtok(NULL, "|")) == NULL)
+ if ((time_str = strtok(NULL, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug("cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now);
- if ((user_name = strtok(NULL, "|")) == NULL)
+ if ((user_name = strtok(NULL, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug("cmgr: decoded uname: '%s'\n", user_name);
- if ((passwd = strtok(NULL, "|")) == NULL)
+ if ((passwd = strtok(NULL, "|")) == NULL) {
+ xfree(buf);
return;
+ }
debug("cmgr: decoded passwd: '%s'\n", passwd);
/* verify freshness and validity */
- if (atoi(time_str) + passwd_ttl < now)
+ if (atoi(time_str) + passwd_ttl < now) {
+ xfree(buf);
return;
+ }
- if (strcasecmp(host_name, req->hostname))
+ if (strcasecmp(host_name, req->hostname)) {
+ xfree(buf);
return;
+ }
debug("cmgr: verified auth. info.\n");
/* ok, accept */
- xfree(req->user_name);
+ safe_free(req->user_name);
req->user_name = xstrdup(user_name);
{
static char buf[1024];
size_t stringLength = 0;
- const char *str64;
if (!req->passwd)
return "";
- snprintf(buf, sizeof(buf), "%s:%s",
- req->user_name ? req->user_name : "",
- req->passwd);
+ int bufLen = snprintf(buf, sizeof(buf), "%s:%s",
+ req->user_name ? req->user_name : "",
+ req->passwd);
- str64 = base64_encode(buf);
+ int encodedLen = base64_encode_len(bufLen);
+ if (encodedLen <= 0)
+ return "";
+
+ uint8_t *str64 = static_cast<uint8_t*>(xmalloc(encodedLen));
+ struct base64_encode_ctx ctx;
+ base64_encode_init(&ctx);
+ size_t blen = base64_encode_update(&ctx, str64, bufLen, reinterpret_cast<uint8_t*>(buf));
+ blen += base64_encode_final(&ctx, str64+blen);
+ str64[blen] = '\0';
- stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %s\r\n", str64);
+ stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %.*s\r\n", (int)blen, str64);
assert(stringLength < sizeof(buf));
- stringLength += snprintf(&buf[stringLength], sizeof(buf) - stringLength,
- "Proxy-Authorization: Basic %s\r\n", str64);
+ snprintf(&buf[stringLength], sizeof(buf) - stringLength, "Proxy-Authorization: Basic %.*s\r\n", (int)blen, str64);
+ xfree(str64);
return buf;
}
if (strcmp(token, "*") == 0)
; /* Wildcard port specification */
- else if (strcasecmp(token, "any") == 0)
+ else if (strcmp(token, "any") == 0)
; /* Wildcard port specification */
else if (sscanf(token, "%d", &i) != 1)
fclose(fp);
return ret;
}
+