From 0151dbceeb3b40e2436d6dbbd86072c6f099308a Mon Sep 17 00:00:00 2001 From: NaruX Date: Wed, 4 Apr 2018 16:24:57 +0200 Subject: [PATCH] =?UTF-8?q?IpAclManager=20ausgelagert=20in=20shared=20ACLs?= =?UTF-8?q?=20=C3=BCber=20Datei=20laden=20(Eine=20ACL=20pro=20Zeile)=20Pro?= =?UTF-8?q?cimgServer=20Parameter=20aclmode=20entfernt=20Codestyle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/etc/revpipyload/aclplcslave.conf | 3 + data/etc/revpipyload/aclxmlrpc.conf | 3 + data/etc/revpipyload/revpipyload.conf | 4 +- doc/helper.html | 137 +------------ doc/index-revpipyload.shared.html | 20 ++ doc/index.html | 8 + doc/picontrolserver.html | 4 +- doc/procimgserver.html | 5 +- doc/revpipyload.shared.ipaclmanager.html | 239 +++++++++++++++++++++++ doc/xrpcserver.html | 7 +- eric-revpipyload.api | 25 ++- revpipyload.e4p | 4 +- revpipyload/helper.py | 104 ---------- revpipyload/picontrolserver.py | 8 +- revpipyload/procimgserver.py | 23 +-- revpipyload/revpipyload.py | 60 ++++-- revpipyload/shared/__init__.py | 1 + revpipyload/shared/ipaclmanager.py | 189 ++++++++++++++++++ revpipyload/xrpcserver.py | 8 +- setup.py | 2 +- 20 files changed, 558 insertions(+), 296 deletions(-) create mode 100644 data/etc/revpipyload/aclplcslave.conf create mode 100644 data/etc/revpipyload/aclxmlrpc.conf create mode 100644 doc/index-revpipyload.shared.html create mode 100644 doc/revpipyload.shared.ipaclmanager.html create mode 100644 revpipyload/shared/__init__.py create mode 100644 revpipyload/shared/ipaclmanager.py diff --git a/data/etc/revpipyload/aclplcslave.conf b/data/etc/revpipyload/aclplcslave.conf new file mode 100644 index 0000000..403205c --- /dev/null +++ b/data/etc/revpipyload/aclplcslave.conf @@ -0,0 +1,3 @@ +# PLC-SLAVE Access Control List (acl) +# One entry per Line IPADRESS,LEVEL +# diff --git a/data/etc/revpipyload/aclxmlrpc.conf b/data/etc/revpipyload/aclxmlrpc.conf new file mode 100644 index 0000000..04c35f9 --- /dev/null +++ b/data/etc/revpipyload/aclxmlrpc.conf @@ -0,0 +1,3 @@ +# XML-RPC Access Control List (acl) +# One entry per Line IPADRESS,LEVEL +# diff --git a/data/etc/revpipyload/revpipyload.conf b/data/etc/revpipyload/revpipyload.conf index 89ccd4d..8afb9c1 100644 --- a/data/etc/revpipyload/revpipyload.conf +++ b/data/etc/revpipyload/revpipyload.conf @@ -14,11 +14,11 @@ zeroonexit = 0 [PLCSLAVE] plcslave = 0 -acl = +aclfile = /etc/revpipyload/aclplcslave.conf bindip = * port = 55234 [XMLRPC] xmlrpc = 0 -acl = +aclfile = /etc/revpipyload/aclxmlrpc.conf bindip = * diff --git a/doc/helper.html b/doc/helper.html index eb567fc..c6856f8 100644 --- a/doc/helper.html +++ b/doc/helper.html @@ -17,10 +17,7 @@ Global Attributes

Classes

- - - - +
IpAclManagerVerwaltung fuer IP Adressen und deren ACL Level.
None

Functions

@@ -37,138 +34,6 @@ Functions

- -

IpAclManager

-

-Verwaltung fuer IP Adressen und deren ACL Level. -

-

-Derived from

-None -

-Class Attributes

- - -
acl
regex_acl
-

-Class Methods

- - -
None
-

-Methods

- - - - - - - - - - - - - - - - - - - - - - - -
IpAclManagerInit IpAclManager class.
__get_aclGetter fuer den rohen ACL-String.
__get_regex_aclGibt formatierten RegEx-String zurueck.
__iter__Gibt einzelne ACLs als aus.
__set_aclUebernimmt neue ACL-Liste fuer die Ausertung der Level.
get_acllevelPrueft IP gegen ACL List und gibt ACL-Wert aus.
loadaclLaed ACL String und gibt erfolg zurueck.
-

-Static Methods

- - -
None
- -

-IpAclManager (Constructor)

-IpAclManager(minlevel, maxlevel, acl=None) -

-Init IpAclManager class. -

-
minlevel
-
-Smallest access level (min. 0) -
maxlevel
-
-Biggest access level (max. 9) -
acl
-
-ACL Liste fuer Berechtigungen als -
-
-

-IpAclManager.__get_acl

-__get_acl() -

-Getter fuer den rohen ACL-String. - return ACLs als -

-

-IpAclManager.__get_regex_acl

-__get_regex_acl() -

-Gibt formatierten RegEx-String zurueck. - return RegEx Code als -

-

-IpAclManager.__iter__

-__iter__() -

-Gibt einzelne ACLs als aus. -

-

-IpAclManager.__set_acl

-__set_acl(value) -

-Uebernimmt neue ACL-Liste fuer die Ausertung der Level. -

-
value
-
-Neue ACL-Liste als -
-
-

-IpAclManager.get_acllevel

-get_acllevel(ipaddress) -

-Prueft IP gegen ACL List und gibt ACL-Wert aus. -

-
ipaddress
-
-zum pruefen -
-
-
Returns:
-
- ACL Wert oder -1 wenn nicht gefunden -
-
-

-IpAclManager.loadacl

-loadacl(str_acl) -

-Laed ACL String und gibt erfolg zurueck. -

-
str_acl
-
-ACL als -
-
-
Returns:
-
-True, wenn erfolgreich uebernommen -
-
-
Up
-

_setuprt

_setuprt(pid, evt_exit) diff --git a/doc/index-revpipyload.shared.html b/doc/index-revpipyload.shared.html new file mode 100644 index 0000000..387c9b5 --- /dev/null +++ b/doc/index-revpipyload.shared.html @@ -0,0 +1,20 @@ + + +revpipyload.shared + + + +

+revpipyload.shared

+ + + +

+Modules

+ + + + + +
ipaclmanagerVerwaltet IP Adressen und deren ACLs.
+ \ No newline at end of file diff --git a/doc/index.html b/doc/index.html index eb76236..b9be723 100644 --- a/doc/index.html +++ b/doc/index.html @@ -8,6 +8,14 @@ Table of contents +

+Packages

+ + + + + +
shared

Modules

diff --git a/doc/picontrolserver.html b/doc/picontrolserver.html index 1cef53d..ac57eb0 100644 --- a/doc/picontrolserver.html +++ b/doc/picontrolserver.html @@ -85,9 +85,9 @@ RevPiSlave (Constructor)

Instantiiert RevPiSlave-Klasse.

-
acl
+
ipacl
-Stringliste mit Leerstellen getrennt +AclManager
port
Listen Port fuer plc Slaveserver diff --git a/doc/procimgserver.html b/doc/procimgserver.html index 9a77e8c..1c0f2b8 100644 --- a/doc/procimgserver.html +++ b/doc/procimgserver.html @@ -93,16 +93,13 @@ Static Methods

ProcimgServer (Constructor)

-ProcimgServer(xmlserver, aclmode) +ProcimgServer(xmlserver)

Instantiiert RevPiCheckServer()-Klasse.

xmlserver
XML-RPC Server -
aclmode
-
-Zugriffsrechte

diff --git a/doc/revpipyload.shared.ipaclmanager.html b/doc/revpipyload.shared.ipaclmanager.html new file mode 100644 index 0000000..9fdebde --- /dev/null +++ b/doc/revpipyload.shared.ipaclmanager.html @@ -0,0 +1,239 @@ + + +revpipyload.shared.ipaclmanager + + + +

+revpipyload.shared.ipaclmanager

+

+Verwaltet IP Adressen und deren ACLs. +

+

+Global Attributes

+ + +
None
+

+Classes

+ + + + + +
IpAclManagerVerwaltung fuer IP Adressen und deren ACL Level.
+

+Functions

+ + + + + +
refullmatchre.fullmatch wegen alter python version aus wheezy nachgebaut.
+

+ +

IpAclManager

+

+Verwaltung fuer IP Adressen und deren ACL Level. +

+

+Derived from

+None +

+Class Attributes

+ + +
acl
filename
regex_acl
+

+Class Methods

+ + +
None
+

+Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IpAclManagerInit IpAclManager class.
__get_aclGetter fuer den rohen ACL-String.
__get_filenameGetter fuer Dateinamen.
__get_regex_aclGibt formatierten RegEx-String zurueck.
__iter__Gibt einzelne ACLs als aus.
__set_aclUebernimmt neue ACL-Liste fuer die Ausertung der Level.
get_acllevelPrueft IP gegen ACL List und gibt ACL-Wert aus.
loadaclLaed ACL String und gibt erfolg zurueck.
loadaclfileLaed ACL Definitionen aus Datei.
writeaclfileSchreibt ACL Definitionen in Datei.
+

+Static Methods

+ + +
None
+ +

+IpAclManager (Constructor)

+IpAclManager(minlevel, maxlevel, acl=None) +

+Init IpAclManager class. +

+
minlevel
+
+Smallest access level (min. 0) +
maxlevel
+
+Biggest access level (max. 9) +
acl
+
+ACL Liste fuer Berechtigungen als +
+
+

+IpAclManager.__get_acl

+__get_acl() +

+Getter fuer den rohen ACL-String. + return ACLs als +

+

+IpAclManager.__get_filename

+__get_filename() +

+Getter fuer Dateinamen. +

+
Returns:
+
+Filename der ACL +
+
+

+IpAclManager.__get_regex_acl

+__get_regex_acl() +

+Gibt formatierten RegEx-String zurueck. + return RegEx Code als +

+

+IpAclManager.__iter__

+__iter__() +

+Gibt einzelne ACLs als aus. +

+

+IpAclManager.__set_acl

+__set_acl(value) +

+Uebernimmt neue ACL-Liste fuer die Ausertung der Level. +

+
value
+
+Neue ACL-Liste als +
+
+

+IpAclManager.get_acllevel

+get_acllevel(ipaddress) +

+Prueft IP gegen ACL List und gibt ACL-Wert aus. +

+
ipaddress
+
+zum pruefen +
+
+
Returns:
+
+ ACL Wert oder -1 wenn nicht gefunden +
+
+

+IpAclManager.loadacl

+loadacl(str_acl) +

+Laed ACL String und gibt erfolg zurueck. +

+
str_acl
+
+ACL als +
+
+
Returns:
+
+True, wenn erfolgreich uebernommen +
+
+

+IpAclManager.loadaclfile

+loadaclfile(filename) +

+Laed ACL Definitionen aus Datei. +

+
filename
+
+Dateiname fuer Definitionen +
+
+
Returns:
+
+True, wenn Laden erfolgreich war +
+
+

+IpAclManager.writeaclfile

+writeaclfile(filename=None, aclname=None) +

+Schreibt ACL Definitionen in Datei. +

+
filename
+
+Dateiname fuer Definitionen +
+
+
Returns:
+
+True, wenn Schreiben erfolgreich war +
+
+
Up
+

+ +

refullmatch

+refullmatch(regex, string) +

+re.fullmatch wegen alter python version aus wheezy nachgebaut. +

+
regex
+
+RegEx Statement +
string
+
+Zeichenfolge gegen die getestet wird +
+
+
Returns:
+
+True, wenn komplett passt sonst False +
+
+
Up
+
+ \ No newline at end of file diff --git a/doc/xrpcserver.html b/doc/xrpcserver.html index 2b5fd14..9e66610 100644 --- a/doc/xrpcserver.html +++ b/doc/xrpcserver.html @@ -128,7 +128,12 @@ SaveXMLRPCServer (Constructor) SaveXMLRPCServer(addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=None)

Init SaveXMLRPCServer class. -

+

+
ipacl
+
+AclManager +
+

SaveXMLRPCServer._dispatch

_dispatch(method, params) diff --git a/eric-revpipyload.api b/eric-revpipyload.api index 3d4c816..b654401 100644 --- a/eric-revpipyload.api +++ b/eric-revpipyload.api @@ -1,12 +1,3 @@ -helper.IpAclManager.__get_acl?6() -helper.IpAclManager.__get_regex_acl?6() -helper.IpAclManager.__iter__?6() -helper.IpAclManager.__set_acl?6(value) -helper.IpAclManager.acl?7 -helper.IpAclManager.get_acllevel?4(ipaddress) -helper.IpAclManager.loadacl?4(str_acl) -helper.IpAclManager.regex_acl?7 -helper.IpAclManager?1(minlevel, maxlevel, acl=None) helper._setuprt?5(pid, evt_exit) helper._zeroprocimg?5() helper.refullmatch?4(regex, string) @@ -42,7 +33,7 @@ procimgserver.ProcimgServer.setvalue?4(device, io, value) procimgserver.ProcimgServer.start?4() procimgserver.ProcimgServer.stop?4() procimgserver.ProcimgServer.values?4() -procimgserver.ProcimgServer?1(xmlserver, aclmode) +procimgserver.ProcimgServer?1(xmlserver) proginit.cleanup?4() proginit.configure?4() proginit.forked?7 @@ -85,6 +76,20 @@ revpipyload.RevPiPyLoad.xml_setconfig?4(dc, loadnow=False) revpipyload.RevPiPyLoad.xml_setpictoryrsc?4(filebytes, reset=False) revpipyload.RevPiPyLoad?1() revpipyload.pyloadversion?7 +revpipyload.shared.ipaclmanager.IpAclManager.__get_acl?6() +revpipyload.shared.ipaclmanager.IpAclManager.__get_filename?6() +revpipyload.shared.ipaclmanager.IpAclManager.__get_regex_acl?6() +revpipyload.shared.ipaclmanager.IpAclManager.__iter__?6() +revpipyload.shared.ipaclmanager.IpAclManager.__set_acl?6(value) +revpipyload.shared.ipaclmanager.IpAclManager.acl?7 +revpipyload.shared.ipaclmanager.IpAclManager.filename?7 +revpipyload.shared.ipaclmanager.IpAclManager.get_acllevel?4(ipaddress) +revpipyload.shared.ipaclmanager.IpAclManager.loadacl?4(str_acl) +revpipyload.shared.ipaclmanager.IpAclManager.loadaclfile?4(filename) +revpipyload.shared.ipaclmanager.IpAclManager.regex_acl?7 +revpipyload.shared.ipaclmanager.IpAclManager.writeaclfile?4(filename=None, aclname=None) +revpipyload.shared.ipaclmanager.IpAclManager?1(minlevel, maxlevel, acl=None) +revpipyload.shared.ipaclmanager.refullmatch?4(regex, string) xrpcserver.SaveXMLRPCRequestHandler.parse_request?4() xrpcserver.SaveXMLRPCServer._dispatch?5(method, params) xrpcserver.SaveXMLRPCServer.isAlive?4() diff --git a/revpipyload.e4p b/revpipyload.e4p index 930cc3d..e7f4e7a 100644 --- a/revpipyload.e4p +++ b/revpipyload.e4p @@ -1,7 +1,7 @@ - + en_US @@ -9,7 +9,7 @@ Python3 Console Dieser Loader wird über das Init-System geladen und führt das angegebene Pythonprogramm aus. Es ist für den RevolutionPi gedacht um automatisch das SPS-Programm zu starten. - 0.6.1 + 0.6.2 Sven Sager akira@narux.de diff --git a/revpipyload/helper.py b/revpipyload/helper.py index e73c960..e40f4fd 100644 --- a/revpipyload/helper.py +++ b/revpipyload/helper.py @@ -12,110 +12,6 @@ from re import match as rematch from subprocess import Popen, PIPE -class IpAclManager(): - - """Verwaltung fuer IP Adressen und deren ACL Level.""" - - def __init__(self, minlevel, maxlevel, acl=None): - """Init IpAclManager class. - - @param minlevel Smallest access level (min. 0) - @param maxlevel Biggest access level (max. 9) - @param acl ACL Liste fuer Berechtigungen als - - """ - if type(minlevel) != int: - raise ValueError("parameter minlevel must be ") - if type(maxlevel) != int: - raise ValueError("parameter maxlevel must be ") - if minlevel < 0: - raise ValueError("minlevel must be 0 or more") - if maxlevel > 9: - raise ValueError("maxlevel maximum is 9") - if minlevel > maxlevel: - raise ValueError("minlevel is smaller than maxlevel") - - self.__dict_acl = {} - self.__dict_regex = {} - self.__dict_knownips = {} - self.__re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[" \ - + str(minlevel) + "-" + str(maxlevel) + "] ?)*" - - # Liste erstellen, wenn übergeben - if acl is not None: - self.__set_acl(acl) - - def __iter__(self): - """Gibt einzelne ACLs als aus.""" - for aclip in sorted(self.__dict_acl): - yield (aclip, self.__dict_acl[aclip]) - - def __get_acl(self): - """Getter fuer den rohen ACL-String. - return ACLs als """ - str_acl = "" - for aclip in sorted(self.__dict_acl): - str_acl += "{},{} ".format(aclip, self.__dict_acl[aclip]) - return str_acl.strip() - - def __get_regex_acl(self): - """Gibt formatierten RegEx-String zurueck. - return RegEx Code als """ - return self.__re_ipacl - - def __set_acl(self, value): - """Uebernimmt neue ACL-Liste fuer die Ausertung der Level. - @param value Neue ACL-Liste als """ - if type(value) != str: - raise ValueError("parameter acl must be ") - - value = value.strip() - if not refullmatch(self.__re_ipacl, value): - raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1") - - # Klassenwerte übernehmen - self.__dict_acl = {} - self.__dict_regex = {} - self.__dict_knownips = {} - - # Liste neu füllen mit regex Strings - for ip_level in value.split(): - ip, level = ip_level.split(",", 1) - self.__dict_acl[ip] = int(level) - self.__dict_regex[ip] = \ - ip.replace(".", "\\.").replace("*", "\\d{1,3}") - - def get_acllevel(self, ipaddress): - """Prueft IP gegen ACL List und gibt ACL-Wert aus. - @param ipaddress zum pruefen - @return ACL Wert oder -1 wenn nicht gefunden""" - # Bei bereits aufgelösten IPs direkt ACL auswerten - if ipaddress in self.__dict_knownips: - return self.__dict_knownips[ipaddress] - - for aclip in sorted(self.__dict_acl, reverse=True): - if refullmatch(self.__dict_regex[aclip], ipaddress): - # IP und Level merken - self.__dict_knownips[ipaddress] = self.__dict_acl[aclip] - - # Level zurückgeben - return self.__dict_acl[aclip] - - return -1 - - def loadacl(self, str_acl): - """Laed ACL String und gibt erfolg zurueck. - @param str_acl ACL als - @return True, wenn erfolgreich uebernommen""" - if not refullmatch(self.__re_ipacl, str_acl): - return False - self.__set_acl(str_acl) - return True - - acl = property(__get_acl, __set_acl) - regex_acl = property(__get_regex_acl) - - def _setuprt(pid, evt_exit): """Konfiguriert Programm fuer den RT-Scheduler. @param pid PID, der angehoben werden soll diff --git a/revpipyload/picontrolserver.py b/revpipyload/picontrolserver.py index f9d9551..bc207da 100644 --- a/revpipyload/picontrolserver.py +++ b/revpipyload/picontrolserver.py @@ -8,6 +8,7 @@ """Modul fuer die Verwaltung der PLC-Slave Funktionen.""" import proginit import socket +from shared.ipaclmanager import IpAclManager from threading import Event, Thread from timeit import default_timer @@ -26,8 +27,13 @@ class RevPiSlave(Thread): def __init__(self, ipacl, port=55234): """Instantiiert RevPiSlave-Klasse. - @param acl Stringliste mit Leerstellen getrennt + @param ipacl AclManager @param port Listen Port fuer plc Slaveserver""" + if not type(ipacl) == IpAclManager: + raise ValueError("parameter ipacl must be ") + if not type(port) == int: + raise ValueError("parameter port must be ") + super().__init__() self.__ipacl = ipacl self._evt_exit = Event() diff --git a/revpipyload/procimgserver.py b/revpipyload/procimgserver.py index cf86d95..2b77a2c 100644 --- a/revpipyload/procimgserver.py +++ b/revpipyload/procimgserver.py @@ -28,17 +28,12 @@ class ProcimgServer(): """ - def __init__(self, xmlserver, aclmode): + def __init__(self, xmlserver): """Instantiiert RevPiCheckServer()-Klasse. - - @param xmlserver XML-RPC Server - @param aclmode Zugriffsrechte - - """ + @param xmlserver XML-RPC Server""" # Logger übernehmen proginit.logger.debug("enter ProcimgServer.__init__()") - self.acl = aclmode self.rpi = None # XML-Server übernehmen @@ -121,13 +116,6 @@ class ProcimgServer(): @return list() [device, io, status, msg] """ - # Zugriffsrechte prüfen - if self.acl < 3: - return [ - device, io, False, - "not allowed in XML-RPC permission mode {}".format(self.acl) - ] - # Binary() in bytes() umwandeln if type(value) == Binary: value = value.data @@ -192,9 +180,8 @@ class ProcimgServer(): for xmlfunc in self.xmlreadfuncs: if xmlfunc in self.xmlsrv.funcs: del self.xmlsrv.funcs[xmlfunc] - if self.acl >= 3: - for xmlfunc in self.xmlwritefuncs: - if xmlfunc in self.xmlsrv.funcs: - del self.xmlsrv.funcs[xmlfunc] + for xmlfunc in self.xmlwritefuncs: + if xmlfunc in self.xmlsrv.funcs: + del self.xmlsrv.funcs[xmlfunc] proginit.logger.debug("leave ProcimgServer.stop()") diff --git a/revpipyload/revpipyload.py b/revpipyload/revpipyload.py index e665643..0ce57a4 100755 --- a/revpipyload/revpipyload.py +++ b/revpipyload/revpipyload.py @@ -40,8 +40,9 @@ import signal import tarfile import zipfile from configparser import ConfigParser -from helper import refullmatch, IpAclManager +from helper import refullmatch from json import loads as jloads +from shared.ipaclmanager import IpAclManager from shutil import rmtree from tempfile import mkstemp from threading import Event @@ -49,7 +50,7 @@ from time import asctime from xmlrpc.client import Binary from xrpcserver import SaveXMLRPCServer -pyloadversion = "0.6.1" +pyloadversion = "0.6.2" class RevPiPyLoad(): @@ -140,8 +141,8 @@ class RevPiPyLoad(): self.plcslave = \ int(self.globalconfig["PLCSLAVE"].get("plcslave", 0)) self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=1) - if not self.plcslaveacl.loadacl( - self.globalconfig["PLCSLAVE"].get("acl", "")): + if not self.plcslaveacl.loadaclfile( + self.globalconfig["PLCSLAVE"].get("aclfile", "")): proginit.logger.warning( "can not load plcslave acl - wrong format" ) @@ -163,8 +164,8 @@ class RevPiPyLoad(): self.xmlrpc = \ int(self.globalconfig["XMLRPC"].get("xmlrpc", 0)) self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4) - if not self.xmlrpcacl.loadacl( - self.globalconfig["XMLRPC"].get("acl", "")): + if not self.xmlrpcacl.loadaclfile( + self.globalconfig["XMLRPC"].get("aclfile", "")): proginit.logger.warning( "can not load xmlrpc acl - wrong format" ) @@ -228,9 +229,7 @@ class RevPiPyLoad(): # Erweiterte Funktionen anmelden try: import procimgserver - self.xml_ps = procimgserver.ProcimgServer( - self.xsrv, self.xmlrpc - ) + self.xml_ps = procimgserver.ProcimgServer(self.xsrv) self.xsrv.register_function(1, self.xml_psstart, "psstart") self.xsrv.register_function(1, self.xml_psstop, "psstop") except: @@ -719,11 +718,46 @@ class RevPiPyLoad(): ) ) return False - self.globalconfig.set( - sektion, - key if localkey == "" else localkey, - str(dc[key]) + if localkey != "acl": + self.globalconfig.set( + sektion, + key if localkey == "" else localkey, + str(dc[key]) + ) + + # ACLs sofort übernehmen und schreiben + str_acl = dc.get("plcslaveacl", None) + if str_acl is not None and self.plcslaveacl.acl != str_acl: + self.plcslaveacl.acl = str_acl + if not self.plcslaveacl.writeaclfile(aclname="PLC-SLAVE"): + proginit.logger.error( + "can not write acl file '{}' for PLC-SLAVE".format( + self.plcslaveacl.filename ) + ) + return False + else: + proginit.logger.info( + "wrote new acl file '{}' for PLC-SLAVE".format( + self.plcslaveacl.filename + ) + ) + str_acl = dc.get("xmlrpcacl", None) + if str_acl is not None and self.xmlrpcacl.acl != str_acl: + self.xmlrpcacl.acl = str_acl + if not self.xmlrpcacl.writeaclfile(aclname="XML-RPC"): + proginit.logger.error( + "can not write acl file '{}' for XML-RPC".format( + self.xmlrpcacl.filename + ) + ) + return False + else: + proginit.logger.info( + "wrote new acl file '{}' for XML-RPC".format( + self.xmlrpcacl.filename + ) + ) # conf-Datei schreiben with open(proginit.globalconffile, "w") as fh: diff --git a/revpipyload/shared/__init__.py b/revpipyload/shared/__init__.py new file mode 100644 index 0000000..d059206 --- /dev/null +++ b/revpipyload/shared/__init__.py @@ -0,0 +1 @@ +"""Shared modules.""" diff --git a/revpipyload/shared/ipaclmanager.py b/revpipyload/shared/ipaclmanager.py new file mode 100644 index 0000000..5bf9aea --- /dev/null +++ b/revpipyload/shared/ipaclmanager.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +# +# IpAclManager +# +# (c) Sven Sager, License: LGPLv3 +# Version 0.1.0 +# +"""Verwaltet IP Adressen und deren ACLs.""" +from os import access, R_OK, W_OK +from re import match as rematch + + +def refullmatch(regex, string): + """re.fullmatch wegen alter python version aus wheezy nachgebaut. + + @param regex RegEx Statement + @param string Zeichenfolge gegen die getestet wird + @return True, wenn komplett passt sonst False + + """ + m = rematch(regex, string) + return m is not None and m.end() == len(string) + + +class IpAclManager(): + + """Verwaltung fuer IP Adressen und deren ACL Level.""" + + def __init__(self, minlevel, maxlevel, acl=None): + """Init IpAclManager class. + + @param minlevel Smallest access level (min. 0) + @param maxlevel Biggest access level (max. 9) + @param acl ACL Liste fuer Berechtigungen als + + """ + if type(minlevel) != int: + raise ValueError("parameter minlevel must be ") + if type(maxlevel) != int: + raise ValueError("parameter maxlevel must be ") + if minlevel < 0: + raise ValueError("minlevel must be 0 or more") + if maxlevel > 9: + raise ValueError("maxlevel maximum is 9") + if minlevel > maxlevel: + raise ValueError("minlevel is smaller than maxlevel") + + self.__dict_acl = {} + self.__dict_regex = {} + self.__dict_knownips = {} + self.__filename = None + self.__re_ipacl = "(([\\d\\*]{1,3}\\.){3}[\\d\\*]{1,3},[" \ + + str(minlevel) + "-" + str(maxlevel) + "] ?)*" + + # Liste erstellen, wenn übergeben + if acl is not None: + self.__set_acl(acl) + + def __iter__(self): + """Gibt einzelne ACLs als aus.""" + for aclip in sorted(self.__dict_acl): + yield (aclip, self.__dict_acl[aclip]) + + def __get_acl(self): + """Getter fuer den rohen ACL-String. + return ACLs als """ + str_acl = "" + for aclip in sorted(self.__dict_acl): + str_acl += "{},{} ".format(aclip, self.__dict_acl[aclip]) + return str_acl.strip() + + def __get_filename(self): + """Getter fuer Dateinamen. + @return Filename der ACL """ + return "" if self.__filename is None else self.__filename + + def __get_regex_acl(self): + """Gibt formatierten RegEx-String zurueck. + return RegEx Code als """ + return self.__re_ipacl + + def __set_acl(self, value): + """Uebernimmt neue ACL-Liste fuer die Ausertung der Level. + @param value Neue ACL-Liste als """ + if type(value) != str: + raise ValueError("parameter acl must be ") + + value = value.strip() + if not refullmatch(self.__re_ipacl, value): + raise ValueError("acl format ist not okay - 1.2.3.4,0 5.6.7.8,1") + + # Klassenwerte übernehmen + self.__dict_acl = {} + self.__dict_regex = {} + self.__dict_knownips = {} + + # Liste neu füllen mit regex Strings + for ip_level in value.split(): + ip, level = ip_level.split(",", 1) + self.__dict_acl[ip] = int(level) + self.__dict_regex[ip] = \ + ip.replace(".", "\\.").replace("*", "\\d{1,3}") + + def get_acllevel(self, ipaddress): + """Prueft IP gegen ACL List und gibt ACL-Wert aus. + @param ipaddress zum pruefen + @return ACL Wert oder -1 wenn nicht gefunden""" + # Bei bereits aufgelösten IPs direkt ACL auswerten + if ipaddress in self.__dict_knownips: + return self.__dict_knownips[ipaddress] + + for aclip in sorted(self.__dict_acl, reverse=True): + if refullmatch(self.__dict_regex[aclip], ipaddress): + # IP und Level merken + self.__dict_knownips[ipaddress] = self.__dict_acl[aclip] + + # Level zurückgeben + return self.__dict_acl[aclip] + + return -1 + + def loadacl(self, str_acl): + """Laed ACL String und gibt erfolg zurueck. + @param str_acl ACL als + @return True, wenn erfolgreich uebernommen""" + if not refullmatch(self.__re_ipacl, str_acl): + return False + self.__set_acl(str_acl) + return True + + def loadaclfile(self, filename): + """Laed ACL Definitionen aus Datei. + @param filename Dateiname fuer Definitionen + @return True, wenn Laden erfolgreich war""" + if type(filename) != str: + raise ValueError("parameter filename must be ") + + # Zugriffsrecht prüfen + if not access(filename, R_OK): + return False + + str_acl = "" + with open(filename, "r") as fh: + while True: + buff = fh.readline() + if buff == "": + break + buff = buff.split("#")[0].strip() + if len(buff) > 0: + str_acl += buff + " " + + acl_okay = self.loadacl(str_acl.strip()) + if acl_okay: + # Dateinamen für Schreiben übernehmen + self.__filename = filename + + return acl_okay + + def writeaclfile(self, filename=None, aclname=None): + """Schreibt ACL Definitionen in Datei. + @param filename Dateiname fuer Definitionen + @return True, wenn Schreiben erfolgreich war""" + if filename is not None and type(filename) != str: + raise ValueError("parameter filename must be ") + if aclname is not None and type(aclname) != str: + raise ValueError("parameter aclname must be ") + + # Dateinamen prüfen + if filename is None and self.__filename is not None: + filename = self.__filename + + # Zugriffsrecht prüfen + if not access(filename, W_OK): + return False + + header = "# {}Access Control List (acl)\n" \ + "# One entry per Line IPADRESS,LEVEL\n" \ + "#\n".format("" if aclname is None else aclname + " ") + + with open(filename, "w") as fh: + fh.write(header) + for aclip in sorted(self.__dict_acl): + fh.write("{},{}\n".format(aclip, self.__dict_acl[aclip])) + + return True + + acl = property(__get_acl, __set_acl) + filename = property(__get_filename) + regex_acl = property(__get_regex_acl) diff --git a/revpipyload/xrpcserver.py b/revpipyload/xrpcserver.py index 3304bed..1f3d1df 100644 --- a/revpipyload/xrpcserver.py +++ b/revpipyload/xrpcserver.py @@ -7,7 +7,7 @@ # """XML-RPC Server anpassungen fuer Absicherung.""" import proginit -from helper import IpAclManager +from shared.ipaclmanager import IpAclManager from concurrent import futures from xmlrpc.server import SimpleXMLRPCServer, SimpleXMLRPCRequestHandler @@ -19,9 +19,13 @@ class SaveXMLRPCServer(SimpleXMLRPCServer): def __init__( self, addr, logRequests=True, allow_none=False, use_builtin_types=False, ipacl=None): - """Init SaveXMLRPCServer class.""" + """Init SaveXMLRPCServer class. + @param ipacl AclManager """ proginit.logger.debug("enter SaveXMLRPCServer.__init__()") + if ipacl is not None and type(ipacl) != IpAclManager: + raise ValueError("parameter ipacl must be ") + # Vererbte Klasse instantiieren super().__init__( addr=addr, diff --git a/setup.py b/setup.py index 8102a5c..079f00e 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ setup( license="LGPLv3", name="revpipyload", - version="0.6.1", + version="0.6.2", scripts=["data/revpipyload"],