-
/*
+ * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
*
- * 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) 2003, Robert Collins <robertc@squid-cache.org>
+ * 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 "squid.h"
std::queue<std::string> ConfigParser::Undo_;
bool ConfigParser::AllowMacros_ = false;
bool ConfigParser::ParseQuotedOrToEol_ = false;
+bool ConfigParser::ParseKvPair_ = false;
+ConfigParser::ParsingStates ConfigParser::KvPairState_ = ConfigParser::atParseKey;
+bool ConfigParser::RecognizeQuotedPair_ = false;
bool ConfigParser::PreviewMode_ = false;
static const char *SQUID_ERROR_TOKEN = "[invalid token]";
std::ostringstream message;
CfgFile *f = CfgFiles.top();
message << "Bungled " << f->filePath << " line " << f->lineNo <<
- ": " << f->currentLine << std::endl;
+ ": " << f->currentLine << std::endl;
CfgFiles.pop();
delete f;
while (!CfgFiles.empty()) {
f = CfgFiles.top();
message << " included from " << f->filePath << " line " <<
- f->lineNo << ": " << f->currentLine << std::endl;
+ f->lineNo << ": " << f->currentLine << std::endl;
CfgFiles.pop();
delete f;
}
message << " included from " << cfg_filename << " line " <<
- config_lineno << ": " << config_input_line << std::endl;
+ config_lineno << ": " << config_input_line << std::endl;
std::string msg = message.str();
fatalf("%s", msg.c_str());
} else
char *
ConfigParser::Undo()
{
- LOCAL_ARRAY(char, undoToken, CONFIG_LINE_LIMIT);
+ static char undoToken[CONFIG_LINE_LIMIT];
if (!Undo_.empty()) {
- strncpy(undoToken, Undo_.front().c_str(), sizeof(undoToken));
+ xstrncpy(undoToken, Undo_.front().c_str(), sizeof(undoToken));
undoToken[sizeof(undoToken) - 1] = '\0';
if (!PreviewMode_)
Undo_.pop();
static FILE *wordFile = NULL;
char *t;
- LOCAL_ARRAY(char, buf, CONFIG_LINE_LIMIT);
+ static char buf[CONFIG_LINE_LIMIT];
if ((t = ConfigParser::Undo()))
return t;
*t = '\0';
if ((wordFile = fopen(fn, "r")) == NULL) {
- debugs(3, DBG_CRITICAL, "Can not open file " << t << " for reading");
+ debugs(3, DBG_CRITICAL, "ERROR: Can not open file " << fn << " for reading");
return NULL;
}
}
/* fromFile */
- if (fgets(buf, CONFIG_LINE_LIMIT, wordFile) == NULL) {
+ if (fgets(buf, sizeof(buf), wordFile) == NULL) {
/* stop reading from file */
fclose(wordFile);
wordFile = NULL;
const char *s = token + 1;
char *d = UnQuoted;
/* scan until the end of the quoted string, handling escape sequences*/
- while (*s && *s != quoteChar && !errorStr && (d - UnQuoted) < sizeof(UnQuoted)) {
+ while (*s && *s != quoteChar && !errorStr && (size_t)(d - UnQuoted) < sizeof(UnQuoted)) {
if (*s == '\\') {
s++;
switch (*s) {
errorStr = "Unsupported cfg macro";
errorPos = s;
#endif
+#if 0
} else if (*s == '%' && quoteChar == '"' && (!AllowMacros_ )) {
errorStr = "Macros are not supported here";
errorPos = s;
+#endif
} else
*d = *s;
++s;
if (errorStr) {
if (PreviewMode_)
- strncpy(UnQuoted, SQUID_ERROR_TOKEN, sizeof(UnQuoted));
+ xstrncpy(UnQuoted, SQUID_ERROR_TOKEN, sizeof(UnQuoted));
else {
- debugs(3, DBG_CRITICAL, errorStr << ": " << errorPos);
+ debugs(3, DBG_CRITICAL, "FATAL: " << errorStr << ": " << errorPos);
self_destruct();
}
}
const char *tokenStart = nextToken;
const char *sep;
- if (ConfigParser::ParseQuotedOrToEol_)
+ if (ConfigParser::ParseKvPair_) {
+ if (ConfigParser::KvPairState_ == ConfigParser::atParseKey)
+ sep = "=";
+ else
+ sep = w_space;
+ } else if (ConfigParser::ParseQuotedOrToEol_)
sep = "\n";
+ else if (ConfigParser::RecognizeQuotedPair_)
+ sep = w_space "\\";
else if (!ConfigParser::RecognizeQuotedValues || *nextToken == '(')
sep = w_space;
else
sep = w_space "(";
nextToken += strcspn(nextToken, sep);
+ while (ConfigParser::RecognizeQuotedPair_ && *nextToken == '\\') {
+ // NP: do not permit \0 terminator to be escaped.
+ if (*(nextToken+1) && *(nextToken+1) != '\r' && *(nextToken+1) != '\n') {
+ nextToken += 2; // skip the quoted-pair (\-escaped) character
+ nextToken += strcspn(nextToken, sep);
+ } else {
+ debugs(3, DBG_CRITICAL, "FATAL: Unescaped '\' character in regex pattern: " << tokenStart);
+ self_destruct();
+ }
+ }
+
if (ConfigParser::RecognizeQuotedValues && *nextToken == '(') {
if (strncmp(tokenStart, "parameters", nextToken - tokenStart) == 0)
type = ConfigParser::FunctionParameters;
CfgLineTokens_.push(err);
return err;
} else {
- debugs(3, DBG_CRITICAL, "Unknown cfg function: " << tokenStart);
+ debugs(3, DBG_CRITICAL, "FATAL: Unknown cfg function: " << tokenStart);
self_destruct();
}
}
CfgLineTokens_.push(err);
return err;
} else {
- debugs(3, DBG_CRITICAL, "Not alphanumeric character '"<< *s << "' in unquoted token " << tokenStart);
+ debugs(3, DBG_CRITICAL, "FATAL: Not alphanumeric character '"<< *s << "' in unquoted token " << tokenStart);
self_destruct();
}
}
char *path = NextToken();
if (LastTokenType != ConfigParser::QuotedToken) {
- debugs(3, DBG_CRITICAL, "Quoted filename missing: " << token);
+ debugs(3, DBG_CRITICAL, "FATAL: Quoted filename missing: " << token);
self_destruct();
return NULL;
}
char *end = NextToken();
ConfigParser::PreviewMode_ = savePreview;
if (LastTokenType != ConfigParser::SimpleToken || strcmp(end, ")") != 0) {
- debugs(3, DBG_CRITICAL, "missing ')' after " << token << "(\"" << path << "\"");
+ debugs(3, DBG_CRITICAL, "FATAL: missing ')' after " << token << "(\"" << path << "\"");
self_destruct();
return NULL;
}
if (CfgFiles.size() > 16) {
- debugs(3, DBG_CRITICAL, "WARNING: can't open %s for reading parameters: includes are nested too deeply (>16)!\n" << path);
+ debugs(3, DBG_CRITICAL, "FATAL: can't open %s for reading parameters: includes are nested too deeply (>16)!\n" << path);
self_destruct();
return NULL;
}
ConfigParser::CfgFile *wordfile = new ConfigParser::CfgFile();
if (!path || !wordfile->startParse(path)) {
- debugs(3, DBG_CRITICAL, "Error opening config file: " << token);
+ debugs(3, DBG_CRITICAL, "FATAL: Error opening config file: " << token);
delete wordfile;
self_destruct();
return NULL;
return token;
}
+bool
+ConfigParser::NextKvPair(char * &key, char * &value)
+{
+ key = value = NULL;
+ ParseKvPair_ = true;
+ KvPairState_ = ConfigParser::atParseKey;
+ if ((key = NextToken()) != NULL) {
+ KvPairState_ = ConfigParser::atParseValue;
+ value = NextQuotedToken();
+ }
+ ParseKvPair_ = false;
+
+ if (!key)
+ return false;
+ if (!value) {
+ debugs(3, DBG_CRITICAL, "Error while parsing key=value token. Value missing after: " << key);
+ return false;
+ }
+
+ return true;
+}
+
char *
ConfigParser::RegexStrtokFile()
{
if (ConfigParser::RecognizeQuotedValues) {
- debugs(3, DBG_CRITICAL, "Can not read regex expresion while configuration_includes_quoted_values is enabled");
+ debugs(3, DBG_CRITICAL, "FATAL: Can not read regex expression while configuration_includes_quoted_values is enabled");
self_destruct();
}
+ ConfigParser::RecognizeQuotedPair_ = true;
char * token = strtokFile();
+ ConfigParser::RecognizeQuotedPair_ = false;
return token;
}
ConfigParser::RegexPattern()
{
if (ConfigParser::RecognizeQuotedValues) {
- debugs(3, DBG_CRITICAL, "Can not read regex expresion while configuration_includes_quoted_values is enabled");
+ debugs(3, DBG_CRITICAL, "FATAL: Can not read regex expression while configuration_includes_quoted_values is enabled");
self_destruct();
}
-
+ ConfigParser::RecognizeQuotedPair_ = true;
char * token = NextToken();
+ ConfigParser::RecognizeQuotedPair_ = false;
return token;
}
assert(wordFile == NULL);
debugs(3, 3, "Parsing from " << path);
if ((wordFile = fopen(path, "r")) == NULL) {
- debugs(3, DBG_CRITICAL, "file :" << path << " not found");
+ debugs(3, DBG_CRITICAL, "WARNING: file :" << path << " not found");
return false;
}
if (wordFile)
fclose(wordFile);
}
+