Runtime : Ensure that a random PSK secret compatible with stunnel is generated if -s commandline switch is used. Stunnel service is restarted after generation, using spawn_subprocess. TODO : give stunnel restart command as a commandline parameter.
--- a/Beremiz_service.py Tue Oct 23 16:13:34 2018 +0200
+++ b/Beremiz_service.py Tue Oct 23 16:19:20 2018 +0200
@@ -50,7 +50,7 @@
print("""
Usage of Beremiz PLC execution service :\n
%s {[-n servicename] [-i IP] [-p port] [-x enabletaskbar] [-a autostart]|-h|--help} working_dir
- -n zeroconf service name (default:disabled)
+ -n service name (default:None, zeroconf discovery disabled)
-i IP address of interface to bind to (default:localhost)
-p port number default:3000
-h print this help text and quit
@@ -59,7 +59,7 @@
-t enable/disable Twisted web interface (0:disable 1:enable) (default:1)
-w web server port or "off" to disable web server (default:8009)
-c WAMP client config file (can be overriden by wampconf.json in project)
- -s WAMP client secret, given as a file (can be overriden by wamp.secret in project)
+ -s PSK secret path (default:PSK disabled)
-e python extension (absolute path .py)
working_dir - directory where are stored PLC files
@@ -78,7 +78,7 @@
interface = ''
port = 3000
webport = 8009
-wampsecret = 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":
- wampsecret = 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()
@@ -489,6 +489,12 @@
sys.path.append(extension_folder)
execfile(os.path.join(extension_folder, extention_file), locals())
+# 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)
runtime.CreatePLCObjectSingleton(
WorkingDir, argv, statuschange, evaluator, pyruntimevars)
@@ -511,7 +517,7 @@
if havewamp:
try:
WC.SetServer(pyroserver)
- WC.RegisterWampClient(wampconf, wampsecret)
+ WC.RegisterWampClient(wampconf, pskpath)
WC.RegisterWebSettings(NS)
except Exception:
LogMessageAndException(_("WAMP client startup failed. "))
--- a/runtime/Stunnel.py Tue Oct 23 16:13:34 2018 +0200
+++ b/runtime/Stunnel.py Tue Oct 23 16:19:20 2018 +0200
@@ -1,10 +1,21 @@
import os
-from binascii import hexlify
+#from binascii import hexlify
+from runtime.spawn_subprocess import call
restart_stunnel_cmdline = ["/etc/init.d/S50stunnel","restart"]
+# 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):
- secretstring = hexlify(os.urandom(256))
+ secret = os.urandom(256) # 2048 bits is still safe nowadays
+
+ # following makes 512 length string, rejected by stunnel
+ # using binascii hexlify loses 50% entropy
+ # secretstring = hexlify(secret)
+
+ secretstring = secret.translate(translator)
pskstring = ID+":"+secretstring
with open(pskpath, 'w') as f:
f.write(pskstring)
@@ -14,5 +25,5 @@
# check if already there
if not os.path.exists(pskpath):
# create if needed
- pskgen(IS, pskpath)
+ pskgen(ID, pskpath)