]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/ConfigParser.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / ConfigParser.cc
index e0a66cfda1302b4e513415d5ee5b76f646e95f7f..43c2314b7933029192eca65a0bbe742ecc1810f2 100644 (file)
@@ -1,34 +1,9 @@
-
 /*
+ * 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"
@@ -48,6 +23,9 @@ std::queue<char *> ConfigParser::CfgLineTokens_;
 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]";
@@ -60,18 +38,18 @@ ConfigParser::destruct()
         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
@@ -89,9 +67,9 @@ ConfigParser::TokenPutBack(const char *tok)
 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();
@@ -110,7 +88,7 @@ ConfigParser::strtokFile()
     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;
@@ -133,7 +111,7 @@ ConfigParser::strtokFile()
                 *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;
                 }
 
@@ -148,7 +126,7 @@ ConfigParser::strtokFile()
         }
 
         /* fromFile */
-        if (fgets(buf, CONFIG_LINE_LIMIT, wordFile) == NULL) {
+        if (fgets(buf, sizeof(buf), wordFile) == NULL) {
             /* stop reading from file */
             fclose(wordFile);
             wordFile = NULL;
@@ -240,9 +218,9 @@ ConfigParser::UnQuote(const char *token, const char **next)
 
     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();
         }
     }
@@ -284,14 +262,32 @@ ConfigParser::TokenParse(const char * &nextToken, ConfigParser::TokenType &type)
 
     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;
@@ -301,7 +297,7 @@ ConfigParser::TokenParse(const char * &nextToken, ConfigParser::TokenType &type)
                 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();
             }
         }
@@ -325,7 +321,7 @@ ConfigParser::TokenParse(const char * &nextToken, ConfigParser::TokenType &type)
                         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();
                     }
                 }
@@ -388,7 +384,7 @@ ConfigParser::NextToken()
 
             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;
             }
@@ -397,20 +393,20 @@ ConfigParser::NextToken()
             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;
@@ -450,14 +446,38 @@ ConfigParser::NextQuotedOrToEol()
     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;
 }
 
@@ -465,11 +485,12 @@ char *
 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;
 }
 
@@ -513,7 +534,7 @@ ConfigParser::CfgFile::startParse(char *path)
     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;
     }
 
@@ -575,3 +596,4 @@ ConfigParser::CfgFile::~CfgFile()
     if (wordFile)
         fclose(wordFile);
 }
+