def archive(self): # store zipped version of /opt/websafety/etc to the shared folder zip_dir = os.path.join(Paths.var_dir(), "cluster") if not os.path.exists(zip_dir): os.makedirs(zip_dir) # copy the database backup_db_file = os.path.join(Paths.etc_dir(), "config.sqlite") db_file = os.path.join(Paths.var_dir(), "db", "config.sqlite") try: c = connection.cursor() c.execute("BEGIN IMMEDIATE") shutil.copyfile(db_file, backup_db_file) finally: c.close() connection.rollback() # remove all old configs, only last 10 will stay files = [ f for f in os.listdir(zip_dir) if os.path.isfile(os.path.join(zip_dir, f)) ] for f in files[:-9]: os.remove(os.path.join(zip_dir, f)) # source and target paths etc_dir = Paths.etc_dir() zip_file = os.path.join( zip_dir, "%s-%s.zip" % (str(self.timestamp), str(self.version))) # zip it zipdir(etc_dir, zip_file)
def collect_license(self): # will write license data to a temp folder folder = os.path.join(Paths.var_dir(), "temp", "license_upload") try: shutil.rmtree(folder) except Exception as e: pass os.makedirs(folder) # collect all chunks into it data = self.request.FILES['file'] name = os.path.join(folder, "license.pem") try: os.unlink(name) except Exception as e: pass with open(name, "wb") as fout: for chunk in data.chunks(): fout.write(chunk) # also copy out the diladele.pem and websafety.pem files into temp folder too shutil.copy(os.path.join(Paths.etc_dir(), "diladele.pem"), os.path.join(folder, "diladele.pem")) shutil.copy(os.path.join(Paths.etc_dir(), "websafety.pem"), os.path.join(folder, "websafety.pem")) # fine, license is there return folder
def get_context_data(self, **kwargs): context = super(ViewSafetySystemInfo, self).get_context_data(**kwargs) v = Version() info = { 'product_name' : 'Web Safety for Squid Proxy', 'installed_version' : v.installed, 'latest_version' : v.latest, 'need_to_upgrade' : v.need_to_upgrade(), # 0 - no_need_to_upgrade, 1 - may_upgrade, 2 - should_upgrade, 3 - must_upgrade 'whats_new' : v.whats_new }; context['info'] = info # add hardcoded settings context['WEBSAFETY_ETC_DIR'] = Paths.etc_dir() context['WEBSAFETY_ETC_DIR_SIZE'] = long(FolderInfo(Paths.etc_dir()).get_size()) context['WEBSAFETY_VAR_DIR'] = Paths.var_dir() context['WEBSAFETY_VAR_DIR_SIZE'] = long(FolderInfo(Paths.var_dir()).get_size()) context['WEBSAFETY_BIN_DIR'] = Paths.bin_dir() context['WEBSAFETY_BIN_DIR_SIZE'] = long(FolderInfo(Paths.bin_dir()).get_size()) context['WEBSAFETY_VERSION'] = Build.version() context['WEBSAFETY_ARCH'] = Distrib.arch() context['WEBSAFETY_DISTRIB'] = Distrib.name() context['WEBSAFETY_SYSTEM'] = System.name() return context
def form_valid(self, form): try: # get realm realm = form.cleaned_data['realm'] # debug check it is fine assert(len(realm) > 0) assert(realm.upper() == realm) # aways update the kerberos conf file self.write_krb5_conf(realm) # update the kerberos keytab file if provided by user self.write_keytab(form.cleaned_data['krb5_spn'], form.cleaned_data.get('keytab', None)) # see what we must do enable = form.cleaned_data['krb5_enable'] if enable: # ok user wants to enable the authenticator, check if everything is in place keytab = os.path.join(Paths.etc_dir(), "krb5.keytab") krb5conf = os.path.join(Paths.etc_dir(), "krb5.conf") if os.path.isfile(krb5conf) and os.path.isfile(keytab): # good everything is fine, proceed pass else: # no-no, we cannot enable! if not os.path.isfile(keytab): errors = form._errors.setdefault("keytab", ErrorList()) errors.append(u"This field is required to enable Kerberos authenticator.") errstr = "Cannot enable Kerberos authenticator. KeyTab file '%s' is not found! Please click on the Browse button and upload the KeyTab from your computer." % keytab else: errstr = "Cannot enable Kerberos authenticator. krb5.conf file '%s' is not found!" % krb5conf # and fail raise Exception(errstr) # if we got here everything is fine (either enabled or disabled successfully) return super(ViewAuthNegotiateSchemeEdit, self).form_valid(form) except Exception as e: form.errors['__all__'] = form.error_class([ "%s\n%s" % (str(e), traceback.format_exc()) ]) # failure return super(ViewAuthNegotiateSchemeEdit, self).form_invalid(form)
def post(self, request, *args, **kwargs): form = ClusterClientForm(request.POST) if form.is_valid(): # ok form is valid, fill the data data = { "enabled" : form.cleaned_data['enabled'], "server_port" : form.cleaned_data['server_port'], "server_address": form.cleaned_data['server_address'], "sync_interval" : form.cleaned_data['sync_interval'] } # and write it w = FileWriter(os.path.join(Paths.etc_dir(), "node")) d = JsonDumper() w.write('cluster_client.json', d.dumps(data)) # mark as needing relstart messages.info(request, "need_squid_restart") return HttpResponseRedirect(self.get_success_url()) return render(request, self.template_name, {'form': form })
def test_ldap(self, object): # here we have django model auth domain updated, but we also need to generate JSON files in /opt/websafety/etc g = Generator(os.path.join(Paths.etc_dir(), "squid")) w = FileWriter(os.path.join(Paths.etc_dir(), "squid")) d = JsonDumper() g.generate_auth(w, d) # and run the tests result = LdapTester().run(); if result['exit_code'] == 0: return (True, "%s %s" % (result['stdout'], result['stderr'])) else: return (False, "Exit code: %s\nSTDOUT: %s\nSTDERR: %s\n" % (str(result['exit_code']), result['stdout'], result['stderr'])) pass
def generate_linux_debian_manual(self, manual): # construct file names cur_file = os.path.join(Paths.etc_dir(), "node", "etc_network_interfaces.manual") bak_file = cur_file + ".bak" new_file = cur_file + ".new" # clear the environment if os.path.exists(bak_file): os.unlink(bak_file) if os.path.exists(new_file): os.unlink(new_file) # always generate manual file (even if manual is empty) t = loader.get_template("node/network/etc_network_interfaces.manual") m = manual.replace("\r\n", "\n") c = {"manual": m} # the contents contents = t.render(c) # write data into new file with open(new_file, "w") as fout: fout.write(contents) fout.flush() # move files around if os.path.exists(cur_file): shutil.move(cur_file, bak_file) shutil.move(new_file, cur_file)
def form_valid(self, form): try: # ok the user wants us to reset the cache disk_cache = DiskCache.objects.first() # first we must enable the cache in the database disk_cache.enabled = True disk_cache.save() # now we generate the squid configuration on disk g = Generator( os.path.join(Paths.etc_dir(), "squid") ) g.generate() # and we call special sudoing binary that will stop squid, reset the cache and start squid again SquidCacheInitializer().initialize() # perfect now we have the cache enabled and reinitialized, return nicely return super(ViewCacheDiskReset, self).form_valid(form) except Exception as e: form.errors['__all__'] = form.error_class([ "%s\n%s" % (str(e), traceback.format_exc()) ]) # failure return super(ViewCacheDiskReset, self).form_invalid(form)
def form_valid(self, form): try: data = self.request.FILES['file'] # first we try to write the file next to actual one old_file = os.path.join(Paths.etc_dir(), "users.htpasswd") new_file = old_file + ".new" # remove the existing new file(s) which may not even exist try: os.remove(new_file) except OSError as e: if e.errno != errno.ENOENT: raise # write the new file with open(new_file, 'wb') as fout: for chunk in data.chunks(): fout.write(chunk) # now replace the new files if os.path.isfile(old_file): os.remove(old_file) os.rename(new_file, old_file) # ok if we got here everything is fine return super(ViewAuthLocalDbImport, self).form_valid(form) except Exception as e: form.errors['__all__'] = form.error_class(["%s" % str(e)]) # failure return super(ViewAuthLocalDbImport, self).form_invalid(form)
def save_certificate(self, cert_contents): # first we try to write the file next to actual one old_pem = os.path.join(Paths.etc_dir(), "ldaps.pem") new_pem = old_pem + ".new" # remove the existing new file(s) which may not even exist try: os.remove(new_pem) except OSError as e: if e.errno != errno.ENOENT: raise # write the new pem file with open(new_pem, 'wb') as fout: fout.write(cert_contents) # run the certmgr that will verify this file - may throw! detector = LdapsDetector() output = detector.dump(new_pem) # now replace the new files if os.path.isfile(old_pem): os.remove(old_pem) os.rename(new_pem, old_pem)
def get(self, request, *args, **kwargs): path = os.path.join(Paths.etc_dir(), "ldaps.pem") with open(path, "rb") as fin: response = HttpResponse(fin.read(), content_type="application/x-x509-ca-cert") response['Content-Disposition'] = "attachment; filename=\"%s\"" % "ldaps.pem" return response
def get_settings(self): name = os.path.join(Paths.etc_dir(), "system.json") with open(name) as fin: data = json.load(fin) return data
def install_license(self): # collect the license into a temporary folder folder = self.collect_license() # protect against users loading key instead of pem if os.path.getsize(os.path.join(folder, "license.pem")) < 255: raise Exception( "You might be uploading a 4.2 style license.key file. This version requires license.pem instead. Contact [email protected] to get it." ) # check if the license is fine try: license = CommandLicense().run(folder) if license['valid'] != "1": message = license["error"] if license["error"].find("local issuer certificate") != -1: message += ". You might be trying to upload a valid license key but for Web Safety version 5. Such keys are not supported. Please contact [email protected] to convert your valid license key to a new format." raise Exception(message) except Exception as e: raise Exception("License key is invalid, error: %s" % str(e)) # if we got here, then the license key is fine, replace the current one shutil.copy(os.path.join(folder, "license.pem"), os.path.join(Paths.etc_dir(), "license.pem")) # good, now if the license is community, activate/deactivate web safety self.activate_safety()
def __init__(self, dc_addr, port, use_ldaps, base_dn, bind_user, bind_pass): # set size limit self.size_limit = 150 # we do not support referrals ldap.set_option(ldap.OPT_REFERRALS, 0) ldap.set_option(ldap.OPT_SIZELIMIT, self.size_limit) # set schema schema = "ldap" if use_ldaps: schema = "ldaps" # it is ldapS so set the path to the trusted cert ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, os.path.join(Paths.etc_dir(), "ldaps.pem")) # disable certificate checking only on windows to ease development if System.name() == System.WS_WINDOWS: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER) # construct uri uri = "%s://%s:%d" % (schema, dc_addr, port) # init LDAP and bind to it self.conn = ldap.initialize(uri) # bind to LDAP server self.conn.simple_bind_s(bind_user, bind_pass) # and save the base dn self.base_dn = base_dn
def generate(self, contents): # debug check assert (len(contents) > 0) # first generate a temporary file in /opt/websafety/etc/node folder (it will be removed after close automatically) prefix = "etc_network_interfaces." folder = os.path.join(Paths.etc_dir(), "node") # write to temp file with tempfile.NamedTemporaryFile(prefix=prefix, dir=folder, delete=True) as temp: temp.write(contents) temp.flush() # call the sudoing binary exe = os.path.join(Paths.bin_dir(), "network_debian.py") arg1 = "--file=%s" % temp.name arg2 = "--system=%s" % System.name() arg3 = "--distrib=%s" % Distrib.name() args = [exe, arg1, arg2, arg3] # and run it (exit_code, stdout, stderr) = CommandElevated().run(args) if exit_code != 0: raise Exception( "Cannot generate network settings. Error: %d, STDOUT: %s, STDERR: %s" % (exit_code, stdout, stderr))
def get(self, request, *args, **kwargs): path = os.path.join(Paths.etc_dir(), "wpad.dat") with open(path, "rb") as fin: response = HttpResponse( fin.read(), content_type="application/x-ns-proxy-autoconfig") return response
def get(self, request, *args, **kwargs): # construct the path path = os.path.join(Paths.etc_dir(), "blocked_safe_browsing.html") # run it all in the exception block try: # get the file with open(path, "r") as fin: contents = fin.read() # render everything templ = Template(contents) context = { "VERSION" : Build.version(), "URI" : request.GET.get('url', ''), "RESULT_INFO" : request.GET.get('reason', '') } # and return response response = HttpResponse(templ.render(Context(context)), content_type="text/html") return response except Exception as e: return HttpResponse(str(e), content_type="text/html")
def get_context_data(self, **kwargs): context = super(ViewAuthNegotiateSchemeEdit, self).get_context_data(**kwargs) # this is the path to keytab keytab_path = os.path.join(Paths.etc_dir(), "krb5.keytab") # dump contents of keytab try: context['keytab'] = KeyTabDumper().dump(keytab_path) except Exception as e: context['keytab'] = str(e) # verify keytab is valid for spn (result, output) = KeyTabInitializer().initialize(keytab_path, self.object.krb5_spn) context['kinit_result'] = result context['kinit_output'] = output # read krb5.conf try: path = os.path.join(Paths.etc_dir(), "krb5.conf") with open(path, "r") as fin: context['krb5conf'] = fin.read() except Exception as e: context['krb5conf'] = "Error reading %s file: %s" % (path, str(e)) # construct some params use_ldaps = False if self.object.lookup_mode in (AuthAd.LOOKUP_MODE_LDAP, AuthAd.LOOKUP_MODE_GC): use_ldaps = False if self.object.lookup_mode in (AuthAd.LOOKUP_MODE_LDAPS, AuthAd.LOOKUP_MODE_GCS): use_ldaps = True # check kvno (result, output) = KvnoChecker( self.object.dc1addr, self.object.lookup_mode, use_ldaps, self.object.base_dn, self.object.bind_user, self.object.bind_pass ).check(keytab_path, self.object.krb5_spn) context['kvno_result'] = result context['kvno_output'] = output return context
def get(self, request, *args, **kwargs): wpad_dat = "" try: path = os.path.join(Paths.etc_dir(), "wpad.dat") os.unlink(path) except Exception as e: pass return HttpResponseRedirect(reverse_lazy("ToolsUploadWpad"))
def dump_raw(self, cacert): cacert_path = os.path.join(Paths.etc_dir(), cacert) if not os.path.isfile(cacert_path): raise Exception("File %s does not exist or is not accessible!" % cacert_path) with open(cacert_path, 'r') as fin: return fin.read()
def get(self, request, *args, **kwargs): path = os.path.join(Paths.etc_dir(), "users.htpasswd") with open(path, "rb") as fin: response = HttpResponse(fin.read(), content_type="application/octet-stream") response[ 'Content-Disposition'] = "attachment; filename=\"%s\"" % "users.htpasswd" return response
def get(self, request, *args, **kwargs): data = {} name = os.path.join(Paths.etc_dir(), "node", "cluster_client.json") if os.path.exists(name): with open(name) as fin: data = json.load(fin) form = ClusterClientForm(initial=data) return render(request, self.template_name, {'form': form })
def generate(self, country, state, city, organization, ou, email, cn, days): # first we try to write the file next to actual one cur_pem = os.path.join(Paths.etc_dir(), "myca.pem") new_pem = cur_pem + ".new" cur_der = os.path.join(Paths.etc_dir(), "myca.der") new_der = cur_der + ".new" # remove the existing new file(s) which may not even exist try: os.remove(new_pem) except OSError as e: if e.errno != errno.ENOENT: raise try: os.remove(new_der) except OSError as e: if e.errno != errno.ENOENT: raise # generate the new pem file by calling special command SquidCertGenerator().generate(new_pem, country, state, city, organization, ou, email, cn, days) # ok file is good; now we need to convert it to DER SquidCertConverter().to_der(new_pem, new_der) # replace the new files if os.path.isfile(cur_pem): os.remove(cur_pem) if os.path.isfile(cur_der): os.remove(cur_der) os.rename(new_pem, cur_pem) os.rename(new_der, cur_der) # perfect now reinitialize the SSL storage (ensure you have the right to write into squid folder!) SquidCertDbInitializer().initialize()
def get(self, request, *args, **kwargs): wpad_dat = "" try: path = os.path.join(Paths.etc_dir(), "wpad.dat") with open(path, "rb") as fin: wpad_dat = fin.read() except Exception as e: wpad_dat = str(e) return render(request, 'squid/tools/wpad.html', { 'form': WpadUploadForm(), 'wpad_dat': wpad_dat })
def do_import(self, form, unpack_dir, version2, version4): # see what we need to do test_only = form.cleaned_data.get('dryrun', False) restore_config = form.cleaned_data.get('restore_config', False) restore_certs = form.cleaned_data.get('restore_certs', False) restore_htmls = form.cleaned_data.get('restore_htmls', False) restore_lic = form.cleaned_data.get('restore_lic', False) restore_ad = form.cleaned_data.get('restore_ad', False) if restore_config: upgrader = Upgrader(test_only, version2) upgrader.upgrade(os.path.join(unpack_dir, "etc")) files = [] if restore_htmls: files.extend([ "blocked_adult.html", "blocked_domains.html", "blocked_general.html", "bypass_partial.html", "blocked_image.gif" ]) if restore_certs: files.extend(["myca.der", "myca.pem"]) if restore_lic: files.extend(["license.pem"]) if restore_ad: files.extend(["krb5.conf", "krb5.keytab", "ldaps.pem"]) # copy files for file in files: src_file = os.path.join(unpack_dir, "etc", file) if not os.path.isfile(src_file): continue bak_file = os.path.join(unpack_dir, "etc", file + ".bak") dst_file = os.path.join(Paths.etc_dir(), file) if os.path.isfile(bak_file): os.unlink(bak_file) if os.path.isfile(dst_file): shutil.move(dst_file, bak_file) shutil.move(src_file, dst_file) # do some additional actions for certificates if restore_certs: SquidCertDbInitializer().initialize()
def clean_enabled(self): enabled = self.cleaned_data['enabled'] if enabled: # ok admin wants to enable client, let's see we are NOT server already name = os.path.join(Paths.etc_dir(), "node", "cluster_server.json") with open(name) as fin: data = json.load(fin) if data['enabled']: self.errors['__all__'] = self.error_class(["Cannot activate configuration client functionality because this node is already activated as configuration server."]) raise forms.ValidationError("") return enabled
def get_context_data(self, **kwargs): context = super(ViewClusterServerNodesList, self).get_context_data(**kwargs) # allocate default response data = { 'error' : False, 'desc' : '', 'items' : {} } try: # get the wssyncd port for the REST service wsport = 18889 name = os.path.join(Paths.etc_dir(), "node", "wssyncd.json") with open(name) as fin: wssyncd = json.load(fin) wsport = wssyncd['rest_service']['port'] # see if server is enabled name = os.path.join(Paths.etc_dir(), "node", "cluster_server.json") with open(name) as fin: cluster = json.load(fin) print(cluster) if cluster['enabled']: data['items'] = ClusterServerNodesList().run(wsport) except Exception as e: data['error'] = True data['desc'] = str(e) context['nodes'] = data return context
def dump(self, cacert): cacert_path = os.path.join(Paths.etc_dir(), cacert) if not os.path.isfile(cacert_path): raise Exception("File %s does not exist or is not accessible!" % cacert_path) args = [self.exe, "x509", "-in", cacert_path, "-text"] (exit_code, stdout, stderr) = Command().run(args) if exit_code != 0: raise Exception("Cannot run command %s, error:\n%s" % (" ".join(args), stdout + stderr)) # if everything is fine - return the cert contents return "%s\n%s" % (stdout, stderr)
def get(self, request, *args, **kwargs): # construct the path path = os.path.join(Paths.etc_dir(), "squid", "foreign_intermediate_certs.pem") # if no file exist, create it if not os.path.isfile(path): with open(path, "wb") as fin: pass # and send contents with open(path, "rb") as fin: response = HttpResponse(fin.read(), content_type="application/x-x509-ca-cert") response[ 'Content-Disposition'] = "attachment; filename=\"%s\"" % "foreign_intermediate_certs.pem" return response
def get(self): # return (bool, license|error) try: # get contents of license key license = CommandLicense().run(Paths.etc_dir()) # let's try to parse expires field into python date license['expires_in'] = self._parse_expires(license['expires']) # and return nicely return (True, license) # color = 'default','cyan' except Exception as e: return (False, str(e))