Automatically get PSK and ID when connecting to PYRO[S], so that future connection through PYROS can use that same key. Also fixed case to UPPER for *PSK.
--- a/Beremiz_service.py Tue Oct 23 16:19:20 2018 +0200
+++ b/Beremiz_service.py Mon Oct 29 11:33:36 2018 +0100
@@ -78,7 +78,7 @@
interface = ''
port = 3000
webport = 8009
-pskpath = None
+PSKpath = None
wampconf = None
servicename = None
autostart = False
@@ -120,7 +120,7 @@
elif o == "-c":
wampconf = None if a == "off" else a
elif o == "-s":
- pskpath = None if a == "off" else a
+ PSKpath = None if a == "off" else a
elif o == "-e":
fnameanddirname = list(os.path.split(os.path.realpath(a)))
fnameanddirname.reverse()
@@ -492,9 +492,9 @@
# Service name is used as an ID for stunnel's PSK
# Some extension may set 'servicename' to a computed ID or Serial Number
# instead of using commandline '-n'
-if servicename is not None and pskpath is not None:
- from runtime.Stunnel import ensurepsk
- ensurepsk(servicename, pskpath)
+if servicename is not None and PSKpath is not None:
+ from runtime.Stunnel import ensurePSK
+ ensurePSK(servicename, PSKpath)
runtime.CreatePLCObjectSingleton(
WorkingDir, argv, statuschange, evaluator, pyruntimevars)
@@ -517,7 +517,7 @@
if havewamp:
try:
WC.SetServer(pyroserver)
- WC.RegisterWampClient(wampconf, pskpath)
+ WC.RegisterWampClient(wampconf, PSKpath)
WC.RegisterWebSettings(NS)
except Exception:
LogMessageAndException(_("WAMP client startup failed. "))
--- a/connectors/PYRO/__init__.py Tue Oct 23 16:19:20 2018 +0200
+++ b/connectors/PYRO/__init__.py Mon Oct 29 11:33:36 2018 +0100
@@ -36,6 +36,7 @@
import Pyro.util
from Pyro.errors import PyroError
+
zeroconf_service_type = '_PYRO._tcp.local.'
# this module attribute contains a list of DNS-SD (Zeroconf) service types
# supported by this connector confnode.
@@ -54,14 +55,15 @@
if servicetype == "PYROS":
import connectors.PYRO.PSK_Adapter
schemename = "PYROLOCPSK"
- url, ID = location.split('#')
+ url, ID = location.split('#') #TODO fix exception when # not found
# load PSK from project
secpath = os.path.join(str(confnodesroot.ProjectPath), 'psk', ID+'.secret')
if not os.path.exists(secpath):
confnodesroot.logger.write_error(
'Error: Pre-Shared-Key Secret in %s is missing!\n' % secpath)
return None
- Pyro.config.PYROPSK = (open(secpath).read(), ID)
+ secret = open(secpath).read().partition(':')[2].rstrip('\n\r')
+ Pyro.config.PYROPSK = (secret, ID)
# strip ID from URL, so that pyro can understand it.
location = url
else:
@@ -88,9 +90,9 @@
# Try to get the proxy object
try:
RemotePLCObjectProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/PLCObject")
- except Exception:
- confnodesroot.logger.write_error(_("Connection to '%s' failed.\n") % location)
- confnodesroot.logger.write_error(traceback.format_exc())
+ except Exception,e:
+ confnodesroot.logger.write_error(_("Connection to '%s' failed with exception '%s'\n") % (location, str(e)))
+ #confnodesroot.logger.write_error(traceback.format_exc())
return None
def PyroCatcher(func, default=None):
@@ -117,10 +119,17 @@
# Check connection is effective.
# lambda is for getattr of GetPLCstatus to happen inside catcher
- if PyroCatcher(RemotePLCObjectProxy.GetPLCstatus)() is None:
- confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n"))
+ IDPSK = PyroCatcher(RemotePLCObjectProxy.GetPLCID)()
+ if IDPSK is None:
+ confnodesroot.logger.write_error(_("Cannot get PLC ID - connection failed.\n"))
return None
+ if servicetype != "PYROS":
+ ID,PSK = IDPSK
+ secpath = os.path.join(str(confnodesroot.ProjectPath), 'psk', ID+'.secret')
+ with open(secpath, 'w') as f:
+ f.write(ID+":"+PSK)
+
_special_return_funcs = {
"StartPLC": False,
"GetTraceVariables": ("Broken", None),
--- a/runtime/PLCObject.py Tue Oct 23 16:19:20 2018 +0200
+++ b/runtime/PLCObject.py Mon Oct 29 11:33:36 2018 +0100
@@ -33,6 +33,7 @@
from runtime.typemapping import TypeTranslator
from runtime.loglevels import LogLevelsDefault, LogLevelsCount
+from runtime.Stunnel import getPSKID
from runtime import MainWorker
if os.name in ("nt", "ce"):
@@ -438,6 +439,10 @@
return self.PLCStatus, map(self.GetLogCount, xrange(LogLevelsCount))
@RunInMain
+ def GetPLCID(self):
+ return getPSKID()
+
+ @RunInMain
def NewPLC(self, md5sum, data, extrafiles):
if self.PLCStatus in ["Stopped", "Empty", "Broken"]:
NewFileName = md5sum + lib_ext
--- a/runtime/Stunnel.py Tue Oct 23 16:19:20 2018 +0200
+++ b/runtime/Stunnel.py Mon Oct 29 11:33:36 2018 +0100
@@ -4,11 +4,13 @@
restart_stunnel_cmdline = ["/etc/init.d/S50stunnel","restart"]
-# stunnel takes no encoding for psk, so we try to lose minimum entropy
+# stunnel takes no encoding for PSK, so we try to lose minimum entropy
# by using all possible chars except '\0\n\r' (checked stunnel parser to be sure)
translator = ''.join([(lambda c: '#' if c in '\0\n\r' else c)(chr(i)) for i in xrange(256)])
-def pskgen(ID, pskpath):
+_PSKpath = None
+
+def PSKgen(ID, PSKpath):
secret = os.urandom(256) # 2048 bits is still safe nowadays
# following makes 512 length string, rejected by stunnel
@@ -16,14 +18,27 @@
# secretstring = hexlify(secret)
secretstring = secret.translate(translator)
- pskstring = ID+":"+secretstring
- with open(pskpath, 'w') as f:
- f.write(pskstring)
+ PSKstring = ID+":"+secretstring
+ with open(PSKpath, 'w') as f:
+ f.write(PSKstring)
call(restart_stunnel_cmdline)
-def ensurepsk(ID, pskpath):
+def ensurePSK(ID, PSKpath):
+ global _PSKpath
+ _PSKpath = PSKpath
# check if already there
- if not os.path.exists(pskpath):
+ if not os.path.exists(PSKpath):
# create if needed
- pskgen(ID, pskpath)
+ PSKgen(ID, PSKpath)
+def getPSKID():
+ if _PSKpath is not None :
+ if not os.path.exists(_PSKpath):
+ confnodesroot.logger.write_error(
+ 'Error: Pre-Shared-Key Secret in %s is missing!\n' % _PSKpath)
+ return None
+ ID,_sep,PSK = open(_PSKpath).read().partition(':')
+ PSK = PSK.rstrip('\n\r')
+ return (ID,PSK)
+ return None
+