commit 324d10944c55d94dcfba78cd1831e14bc4fff543 Author: Janek Walkenhorst Date: Mon Aug 14 16:44:31 2017 +0200 sanitizing diff --git a/services/univention-bind/bind.py b/services/univention-bind/bind.py index 8b86a0b..6e8bbe9 100755 --- a/services/univention-bind/bind.py +++ b/services/univention-bind/bind.py @@ -45,6 +45,7 @@ import time import errno import signal import grp +import urllib name = 'bind' description = 'Update BIND zones' @@ -98,9 +99,11 @@ def handler(dn, new, old): _remove_zone(old['zoneName'][0]) if new.get('zoneName'): # Change - # Create an empty file to trigger the postrun() - zonefile = os.path.join(PROXY_CACHE_DIR, "%s.zone" % (new['zoneName'][0],)) + # Create a file to trigger the postrun() + zone = new['zoneName'][0] + zonefile = sanitized_path_join(PROXY_CACHE_DIR, "%s.zone" % (zone, )) proxy_cache = open(zonefile, 'w') + proxy_cache.write(zone) proxy_cache.close() os.chmod(zonefile, 0o640) chgrp_bind(zonefile) @@ -125,7 +128,7 @@ def _new_zone(ucr, zonename, dn): os.mkdir(NAMED_CONF_DIR) os.chmod(NAMED_CONF_DIR, 0o755) - zonefile = os.path.join(NAMED_CONF_DIR, zonename) + zonefile = sanitized_path_join(NAMED_CONF_DIR, zonename) # Create empty file and restrict permission named_zone = open(zonefile, 'w') @@ -149,11 +152,11 @@ def _new_zone(ucr, zonename, dn): named_zone.close() # Create proxy configuration file - proxy_file = os.path.join(NAMED_CONF_DIR, zonename + '.proxy') + proxy_file = sanitized_path_join(NAMED_CONF_DIR, zonename + '.proxy') proxy_zone = open(proxy_file, 'w') proxy_zone.write('zone "%s" {\n' % (zonename,)) proxy_zone.write('\ttype slave;\n') - proxy_zone.write('\tfile "%s.zone";\n' % (zonename,)) + proxy_zone.write('\tfile "%s.zone";\n' % (sanitize_filename(zonename),)) proxy_zone.write('\tmasters port 7777 { 127.0.0.1; };\n') proxy_zone.write('};\n') proxy_zone.close() @@ -167,8 +170,8 @@ def _new_zone(ucr, zonename, dn): def _remove_zone(zonename): """Handle removal of zone.""" ud.debug(ud.LISTENER, ud.INFO, 'DNS: Removing zone %s' % (zonename,)) - zonefile = os.path.join(NAMED_CONF_DIR, zonename) - cached_zonefile = os.path.join(NAMED_CACHE_DIR, zonename + '.zone') + zonefile = sanitized_path_join(NAMED_CONF_DIR, zonename) + cached_zonefile = sanitized_path_join(NAMED_CACHE_DIR, zonename + '.zone') # Remove zone file if os.path.exists(zonefile): os.unlink(zonefile) @@ -318,13 +321,18 @@ def postrun(): __zone_created_or_removed = False elif dns_backend == 'ldap': for filename in os.listdir(PROXY_CACHE_DIR): - os.remove(os.path.join(PROXY_CACHE_DIR, filename)) + filepath = os.path.join(PROXY_CACHE_DIR, filename) + zone = open(filepath, 'rb').read() + os.remove(filepath) if not os.path.exists(os.path.join(NAMED_CACHE_DIR, filename)): ud.debug(ud.LISTENER, ud.PROCESS, 'DNS: %s does not exist. Triggering a bind9 restart.' % (os.path.join(NAMED_CACHE_DIR, filename))) restart = True else: - zone = filename.replace(".zone", "") - zones.append(zone) + _, ext = os.path.splitext(filename) + if ext == '.zone': + zones.append(zone) + else: + ud.debug(ud.LISTENER, ud.WARN, 'DNS: strange file in PROXY_CACHE_DIR: %r' % (filename, )) if zones: ud.debug(ud.LISTENER, ud.INFO, 'DNS: Zones: %s' % (zones,)) elif dns_backend == 'none': @@ -341,3 +349,16 @@ def postrun(): _kill_children(pids) finally: listener.unsetuid() + +def sanitize_filename(bytestring): + escaped = urllib.quote(bytestring, safe='') + if escaped.startswith('.'): # always encode leading dot because '.' and '..' are special names + escaped = '%20' + escaped[1:] + return escaped + +def sanitized_path_join(directory, unsafe_filename): + filename = sanitize_filename(unsafe_filename) + assert '/' not in filename + assert '\0' not in filename + assert filename not in ('.', '..', ) + return os.path.join(directory, filename) diff --git a/services/univention-bind/debian/univention-bind.postinst b/services/univention-bind/debian/univention-bind.postinst index 93e1583..87fe36c 100644 --- a/services/univention-bind/debian/univention-bind.postinst +++ b/services/univention-bind/debian/univention-bind.postinst @@ -82,6 +82,10 @@ if [ "$1" = "configure" ]; then systemctl --system daemon-reload } if [ -n "$2" ]; then + if dpkg --compare-versions "$2" lt 10.0.2-6 # update to sanitized filenames + then + univention-directory-listener-ctrl resync bind + fi invoke-rc.d bind9 crestart else invoke-rc.d bind9 start