[Git][NTPsec/ntpsec][master] Fixed ntpsnmpd config file parser.

Ian Bruene gitlab at mg.gitlab.com
Tue Mar 27 21:56:29 UTC 2018


Ian Bruene pushed to branch master at NTPsec / ntpsec


Commits:
5fa48ed0 by Ian Bruene at 2018-03-27T21:55:08Z
Fixed ntpsnmpd config file parser.

- - - - -


3 changed files:

- ntpclients/ntpsnmpd.py
- pylib/util.py
- tests/pylib/test_util.py


Changes:

=====================================
ntpclients/ntpsnmpd.py
=====================================
--- a/ntpclients/ntpsnmpd.py
+++ b/ntpclients/ntpsnmpd.py
@@ -825,7 +825,7 @@ class DataSource(ntp.agentx.MIBControl):
             return
 
         def boolify(d, k):
-            return True if d[k] == "True" else False
+            return True if d[k][0][1] == "True" else False
         optionList = ("notify-mode-change", "notify-stratum-change",
                       "notify-syspeer-change", "notify-add-association",
                       "notify-rm-association", "notify-leap-announced",
@@ -849,7 +849,7 @@ class DataSource(ntp.agentx.MIBControl):
             elif key == "notify-heartbeat":
                 self.notifyHeartbeat = boolify(settings, key)
             elif key == "heartbeat-interval":
-                self.heartbeatInterval = int(settings[key])
+                self.heartbeatInterval = settings[key][0][1]
 
     def misc_storeDynamicSettings(self):
         if self.settingsFilename is None:
@@ -1079,19 +1079,11 @@ def loadSettings(filename, optionList):
     options = {}
     with open(filename) as f:
         data = f.read()
-        parser = shlex.shlex(data)
-        parser.wordchars += "-.:"
-        data = [x for x in parser]
-        i = 0
-        dataLen = len(data)
-        while i < dataLen:
-            if data[i] in optionList:
-                arg = data[i+1]
-                if arg[0] in "\"'":
-                    arg = arg[1:-1]
-                options[data[i]] = arg
-                i += 1
-            i += 1
+        lines = ntp.util.parseConf(data)
+        for line in lines:
+            isQuote, token = line[0]
+            if token in optionList:
+                options[token] = line[1:]
     return options
 
 
@@ -1152,7 +1144,7 @@ if __name__ == "__main__":
     if conf is not None:
         for key in conf.keys():
             if key == "master-addr":  # Address of the SNMP master daemon
-                val = conf[key]
+                val = conf[key][0][1]
                 if ":" in val:
                     host, port = val.split(":")
                     port = int(port)
@@ -1160,12 +1152,12 @@ if __name__ == "__main__":
                 else:
                     masterAddr = val
             elif key == "logfile":
-                logfile = conf[key]
+                logfile = conf[key][0][1]
             elif key == "ntp-addr":  # Address of the NTP daemon
-                hostname = conf[key]
+                hostname = conf[key][0][1]
             elif key == "loglevel":
                 errmsg = "Error: loglevel parameter '%s' not a number\n"
-                debug = ntp.util.safeargcast(conf[key], int, errmsg, usage)
+                debug = conf[key][0][1]
 
     fileLogging = False
     for (switch, val) in options:


=====================================
pylib/util.py
=====================================
--- a/pylib/util.py
+++ b/pylib/util.py
@@ -10,6 +10,7 @@ import os
 import re
 import shutil
 import socket
+import string
 import sys
 import time
 import ntp.ntpc
@@ -157,6 +158,75 @@ def portsplit(hostname):
     return (hostname, portsuffix)
 
 
+def parseConf(text):
+    inQuote = False
+    quoteStarter = ""
+    lines = []
+    tokens = []
+    current = []
+
+    def pushToken():
+        token = "".join(current)
+        if inQuote is False:  # Attempt type conversion
+            try:
+                token = int(token)
+            except ValueError:
+                try:
+                    token = float(token)
+                except ValueError:
+                    pass
+        wrapper = (inQuote, token)
+        tokens.append(wrapper)
+        current[:] = []
+
+    def pushLine():
+        if len(current) > 0:
+            pushToken()
+        if len(tokens) > 0:
+            lines.append(tokens[:])
+            tokens[:] = []
+
+    i = 0
+    tlen = len(text)
+    while i < tlen:
+        if inQuote is True:
+            if text[i] == quoteStarter:  # Ending a text string
+                pushToken()
+                quoteStarter = ""
+                inQuote = False
+            elif text[i] == "\\":  # Starting an escape sequence
+                i += 1
+                if text[i] in "'\"n\\":
+                    print(repr(text[i]))
+                    current.append(eval("\'\\" + text[i] + "\'"))
+            else:
+                current.append(text[i])
+        else:
+            if text[i] == "#":  # Comment
+                while (i < tlen) and (text[i] != "\n"):
+                    i += 1  # Advance to end of line...
+                i -= 1  # ...and back up so we don't skip the newline
+            elif text[i] in "'\"":  # Starting a text string
+                inQuote = True
+                quoteStarter = text[i]
+                if len(current) > 0:
+                    pushToken()
+            elif text[i] == "\\":  # Linebreak escape
+                i += 1
+                if text[i] != "\n":
+                    raise SyntaxError
+            elif text[i] == "\n":  # EOL: break the lines
+                pushLine()
+            elif text[i] in string.whitespace:
+                if len(current) > 0:
+                    pushToken()
+            else:
+                current.append(text[i])
+        i += 1
+    pushLine()
+    return lines
+
+
 def stringfilt(data):
     "Pretty print string of space separated numbers"
     parts = data.split()


=====================================
tests/pylib/test_util.py
=====================================
--- a/tests/pylib/test_util.py
+++ b/tests/pylib/test_util.py
@@ -151,6 +151,17 @@ class TestPylibUtilMethods(unittest.TestCase):
             "[0000:1111:2222:3333:4444:5555:6666:7777]:123"),
             ("0000:1111:2222:3333:4444:5555:6666:7777", ":123"))
 
+    def test_parseConf(self):
+        data = """foo bar 42 #blah blah blah
+        "abcd"   poi? 3.14
+        "\\"\\n\\\\foo\\c" \\
+        poi! """
+        parsed = ntp.util.parseConf(data)
+        self.assertEqual(parsed,
+                         [[(False, "foo"), (False, "bar"), (False, 42)],
+                          [(True, "abcd"), (False, "poi?"), (False, 3.14)],
+                          [(True, "\"\n\\foo"), (False, "poi!")]])
+
     def test_stringfilt(self):
         f = ntp.util.stringfilt
 



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/5fa48ed012d328ffd08a2d256ff37e85052188ac

---
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/5fa48ed012d328ffd08a2d256ff37e85052188ac
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20180327/f3036b20/attachment.html>


More information about the vc mailing list