diff --git a/management/daemon.py b/management/daemon.py index 1099a596..dc16d7a5 100755 --- a/management/daemon.py +++ b/management/daemon.py @@ -155,7 +155,12 @@ def mail_users(): @authorized_personnel_only def mail_users_add(): try: - return add_mail_user(request.form.get('email', ''), request.form.get('password', ''), request.form.get('privileges', ''), env) + return add_mail_user(request.form.get('email', ''), + request.form.get('password', ''), + request.form.get('privileges', ''), + env, + dns_enabled=request.form.get('dns_enabled', False), + web_enabled=request.form.get('web_enabled', False)) except ValueError as e: return (str(e), 400) @@ -207,7 +212,9 @@ def mail_aliases_add(): request.form.get('forwards_to', ''), request.form.get('permitted_senders', ''), env, - update_if_exists=(request.form.get('update_if_exists', '') == '1') + update_if_exists=(request.form.get('update_if_exists', '') == '1'), + dns_enabled=request.form.get('dns_enabled', False), + web_enabled=request.form.get('web_enabled', False) ) @app.route('/mail/aliases/remove', methods=['POST']) @@ -335,7 +342,7 @@ def ssl_get_status(): # What domains can we provision certificates for? What unexpected problems do we have? provision, cant_provision = get_certificates_to_provision(env, show_extended_problems=False) - + # What's the current status of TLS certificates on all of the domain? domains_status = get_web_domains_info(env) domains_status = [{ "domain": d["domain"], "status": d["ssl_certificate"][0], "text": d["ssl_certificate"][1] } for d in domains_status ] diff --git a/management/dns_update.py b/management/dns_update.py index d3ef2cbc..c978a834 100755 --- a/management/dns_update.py +++ b/management/dns_update.py @@ -15,8 +15,7 @@ from utils import shell, load_env_vars_from_file, safe_domain_name, sort_domains def get_dns_domains(env): # Add all domain names in use by email users and mail aliases and ensure # PRIMARY_HOSTNAME is in the list. - domains = set() - domains |= get_mail_domains(env) + domains = get_mail_domains(env, filter_list='dns') domains.add(env['PRIMARY_HOSTNAME']) return domains @@ -144,7 +143,7 @@ def build_zone(domain, all_domains, additional_records, www_redirect_domains, en # Define ns2.PRIMARY_HOSTNAME or whatever the user overrides. # User may provide one or more additional nameservers secondary_ns_list = get_secondary_dns(additional_records, mode="NS") \ - or ["ns2." + env["PRIMARY_HOSTNAME"]] + or ["ns2." + env["PRIMARY_HOSTNAME"]] for secondary_ns in secondary_ns_list: records.append((None, "NS", secondary_ns+'.', False)) diff --git a/management/mailconfig.py b/management/mailconfig.py index d9ffdf65..befcc93b 100755 --- a/management/mailconfig.py +++ b/management/mailconfig.py @@ -3,8 +3,35 @@ import subprocess, shutil, os, sqlite3, re import utils from email_validator import validate_email as validate_email_, EmailNotValidError +import rtyaml import idna +def load_domain_blacklist(env, service): + try: + return set(rtyaml.load(open(os.path.join(env['STORAGE_ROOT'], '{}/ignored.yaml'.format(service))))) + except: + return set() + +def add_domain_blacklist(env, domain, service): + try: + ignored = set(rtyaml.load(open(os.path.join(env['STORAGE_ROOT'], '{}/ignored.yaml'.format(service))))) + ignored.add(domain) + except Exception as err: + # if non-existent or baldy formatted, consider it new + ignored = {domain} + with open(os.path.join(env['STORAGE_ROOT'], '{}/ignored.yaml'.format(service)), "w") as f: + f.write(rtyaml.dump(list(ignored))) + +def remove_domain_blacklist(env, domain, service): + try: + ignored = set(rtyaml.load(open(os.path.join(env['STORAGE_ROOT'], '{}/ignored.yaml'.format(service))))) + if domain in ignored: + ignored.remove(domain) + with open(os.path.join(env['STORAGE_ROOT'], '{}/ignored.yaml'.format(service)), "w") as f: + f.write(rtyaml.dump(list(ignored))) + except Exception as err: + pass + def validate_email(email, mode=None): # Checks that an email address is syntactically valid. Returns True/False. # Until Postfix supports SMTPUTF8, an email address may contain ASCII @@ -253,15 +280,20 @@ def get_domain(emailaddr, as_unicode=True): pass return ret -def get_mail_domains(env, filter_aliases=lambda alias : True): +def get_mail_domains(env, filter_aliases=lambda alias : True, filter_list=None): + ignored = set() + if filter_list == 'dns': + ignored |= load_domain_blacklist(env, 'dns') + if filter_list in ('web', 'www'): + ignored |= load_domain_blacklist(env, 'www') # Returns the domain names (IDNA-encoded) of all of the email addresses # configured on the system. return set( [get_domain(login, as_unicode=False) for login in get_mail_users(env)] + [get_domain(address, as_unicode=False) for address, *_ in get_mail_aliases(env) if filter_aliases(address) ] - ) + ) - ignored -def add_mail_user(email, pw, privs, env): +def add_mail_user(email, pw, privs, env, dns_enabled=True, web_enabled=True): # validate email if email.strip() == "": return ("No email address provided.", 400) @@ -303,6 +335,14 @@ def add_mail_user(email, pw, privs, env): # write databasebefore next step conn.commit() + # Add non dns enabled domain to the ignored domain list + if dns_enabled == 'false': + add_domain_blacklist(env, get_domain(email), 'dns') + + # Add non web enabled domain to the ignored domain list + if web_enabled == 'false': + add_domain_blacklist(env, get_domain(email), 'www') + # Update things in case any new domains are added. return kick(env, "mail user added") @@ -347,6 +387,9 @@ def remove_mail_user(email, env): return ("That's not a user (%s)." % email, 400) conn.commit() + remove_domain_blacklist(env, get_domain(address), 'dns') + remove_domain_blacklist(env, get_domain(address), 'www') + # Update things in case any domains are removed. return kick(env, "mail user removed") @@ -395,7 +438,7 @@ def add_remove_mail_user_privilege(email, priv, action, env): return "OK" -def add_mail_alias(address, forwards_to, permitted_senders, env, update_if_exists=False, do_kick=True): +def add_mail_alias(address, forwards_to, permitted_senders, env, update_if_exists=False, dns_enabled=True, web_enabled=True, do_kick=True): # convert Unicode domain to IDNA address = sanitize_idn_email_address(address) @@ -484,6 +527,14 @@ def add_mail_alias(address, forwards_to, permitted_senders, env, update_if_exist conn.commit() + # Add non dns enabled domain to the ignored domain list + if dns_enabled == 'false': + add_domain_blacklist(env, get_domain(address), 'dns') + + # Add non web enabled domain to the ignored domain list + if web_enabled == 'false': + add_domain_blacklist(env, get_domain(address), 'www') + if do_kick: # Update things in case any new domains are added. return kick(env, return_status) @@ -499,6 +550,9 @@ def remove_mail_alias(address, env, do_kick=True): return ("That's not an alias (%s)." % address, 400) conn.commit() + remove_domain_blacklist(env, get_domain(address), 'dns') + remove_domain_blacklist(env, get_domain(address), 'www') + if do_kick: # Update things in case any domains are removed. return kick(env, "alias removed") diff --git a/management/templates/aliases.html b/management/templates/aliases.html index dc916f95..50f538b2 100644 --- a/management/templates/aliases.html +++ b/management/templates/aliases.html @@ -64,6 +64,23 @@ +
+ +
+
+ +
+
+ +
+
+
@@ -174,6 +191,8 @@ function do_add_alias() { var form_address = $("#addaliasAddress").val(); var form_forwardsto = $("#addaliasForwardsTo").val(); var form_senders = ($('#addaliasForwardsToAdvanced').prop('checked') ? $("#addaliasSenders").val() : ''); + var form_dns = $('#addaliasDnsHandling').prop('checked'); + var form_web = $('#addaliasWebHandling').prop('checked'); if ($('#addaliasForwardsToAdvanced').prop('checked') && !/\S/.exec($("#addaliasSenders").val())) { show_modal_error(title, "You did not enter any permitted senders."); return false; @@ -185,7 +204,9 @@ function do_add_alias() { update_if_exists: is_alias_add_update ? '1' : '0', address: form_address, forwards_to: form_forwardsto, - permitted_senders: form_senders + permitted_senders: form_senders, + dns_enabled: form_dns, + web_enabled: form_web }, function(r) { // Responses are multiple lines of pre-formatted text. @@ -204,6 +225,8 @@ function aliases_reset_form() { $("#addaliasAddress").val('') $("#addaliasForwardsTo").val('') $("#addaliasSenders").val('') + $('#addaliasDnsHandling').prop('disabled', false); + $('#addaliasWebHandling').prop('disabled', false); $('#alias-cancel').addClass('hidden'); $('#add-alias-button').text('Add Alias'); is_alias_add_update = false; @@ -232,6 +255,8 @@ function aliases_edit(elem) { $('#addaliasForwardsToAdvanced').prop('checked', senders != ""); $('#addaliasForwardsToNotAdvanced').prop('checked', senders == ""); $("#addaliasSenders").val(senders); + $('#addaliasDnsHandling').prop('disabled', true); + $('#addaliasWebHandling').prop('disabled', true); $('#add-alias-button').text('Update'); $('body').animate({ scrollTop: 0 }) is_alias_add_update = true; diff --git a/management/templates/users.html b/management/templates/users.html index 010a1edf..6e07673a 100644 --- a/management/templates/users.html +++ b/management/templates/users.html @@ -28,6 +28,23 @@
+
+ +
+
+ +
+
+ +
+
+