def run(self): main_domain = _get_maindomain() all_domains = domain_list()["domains"] for domain in all_domains: self.logger_debug("Diagnosing DNS conf for %s" % domain) is_subdomain = domain.split(".", 1)[1] in all_domains for report in self.check_domain(domain, domain == main_domain, is_subdomain=is_subdomain): yield report # Check if a domain buy by the user will expire soon psl = PublicSuffixList() domains_from_registrar = [ psl.get_public_suffix(domain) for domain in all_domains ] domains_from_registrar = [ domain for domain in domains_from_registrar if "." in domain ] domains_from_registrar = set(domains_from_registrar) - set( YNH_DYNDNS_DOMAINS + ["netlib.re"]) for report in self.check_expiration_date(domains_from_registrar): yield report
def _email_diagnosis_issues(): from yunohost.domain import _get_maindomain maindomain = _get_maindomain() from_ = "diagnosis@%s (Automatic diagnosis on %s)" % (maindomain, maindomain) to_ = "root" subject_ = "Issues found by automatic diagnosis on %s" % maindomain disclaimer = "The automatic diagnosis on your YunoHost server identified some issues on your server. You will find a description of the issues below. You can manage those issues in the 'Diagnosis' section in your webadmin." issues = diagnosis_show(issues=True)["reports"] if not issues: return content = _dump_human_readable_reports(issues) message = """\ From: %s To: %s Subject: %s %s --- %s """ % (from_, to_, subject_, disclaimer, content) import smtplib smtp = smtplib.SMTP("localhost") smtp.sendmail(from_, [to_], message) smtp.quit()
def run(self): self.ehlo_domain = _get_maindomain() self.mail_domains = domain_list()["domains"] self.ipversions, self.ips = self.get_ips_checked() # TODO Is a A/AAAA and MX Record ? # TODO Are outgoing public IPs authorized to send mail by SPF ? # TODO Validate DKIM and dmarc ? # TODO check that the recent mail logs are not filled with thousand of email sending (unusual number of mail sent) # TODO check for unusual failed sending attempt being refused in the logs ? checks = [ "check_outgoing_port_25", "check_ehlo", "check_fcrdns", "check_blacklist", "check_queue" ] for check in checks: self.logger_debug("Running " + check) reports = list(getattr(self, check)()) for report in reports: yield report if not reports: name = check[6:] yield dict(meta={"test": "mail_" + name}, status="SUCCESS", summary="diagnosis_mail_" + name + "_ok")
def setup_function(function): global maindomain maindomain = _get_maindomain() assert backup_test_dependencies_are_met() clean_tmp_backup_directory() reset_ssowat_conf() delete_all_backups() uninstall_test_apps_if_needed() assert len(backup_list()["archives"]) == 0 markers = { m.name: { 'args': m.args, 'kwargs': m.kwargs } for m in function.__dict__.get("pytestmark", []) } if "with_wordpress_archive_from_2p4" in markers: add_archive_wordpress_from_2p4() assert len(backup_list()["archives"]) == 1 if "with_legacy_app_installed" in markers: assert not app_is_installed("legacy_app") install_app("legacy_app_ynh", "/yolo") assert app_is_installed("legacy_app") if "with_backup_recommended_app_installed" in markers: assert not app_is_installed("backup_recommended_app") install_app("backup_recommended_app_ynh", "/yolo", "&helper_to_test=ynh_restore_file") assert app_is_installed("backup_recommended_app") if "with_backup_recommended_app_installed_with_ynh_restore" in markers: assert not app_is_installed("backup_recommended_app") install_app("backup_recommended_app_ynh", "/yolo", "&helper_to_test=ynh_restore") assert app_is_installed("backup_recommended_app") if "with_system_archive_from_2p4" in markers: add_archive_system_from_2p4() assert len(backup_list()["archives"]) == 1 if "with_permission_app_installed" in markers: assert not app_is_installed("permissions_app") user_create("alice", "Alice", "White", maindomain, "test123Ynh") install_app("permissions_app_ynh", "/urlpermissionapp" "&admin=alice") assert app_is_installed("permissions_app") if "with_custom_domain" in markers: domain = markers['with_custom_domain']['args'][0] if domain not in domain_list()['domains']: domain_add(domain)
def setup_function(function): clean_user_groups() global maindomain maindomain = _get_maindomain() user_create("alice", "Alice", "White", maindomain, "test123Ynh") user_create("bob", "Bob", "Snow", maindomain, "test123Ynh") user_create("jack", "Jack", "Black", maindomain, "test123Ynh") user_group_create("dev") user_group_create("apps") user_group_update("dev", add=["alice"]) user_group_update("apps", add=["bob"])
def tools_maindomain(auth, new_domain=None): """ Check the current main domain, or change it Keyword argument: new_domain -- The new domain to be set as the main domain """ # If no new domain specified, we return the current main domain if not new_domain: return {'current_main_domain': _get_maindomain()} # Check domain exists if new_domain not in domain_list(auth)['domains']: raise MoulinetteError(errno.EINVAL, m18n.n('domain_unknown')) # Apply changes to ssl certs ssl_key = "/etc/ssl/private/yunohost_key.pem" ssl_crt = "/etc/ssl/private/yunohost_crt.pem" new_ssl_key = "/etc/yunohost/certs/%s/key.pem" % new_domain new_ssl_crt = "/etc/yunohost/certs/%s/crt.pem" % new_domain try: if os.path.exists(ssl_key) or os.path.lexists(ssl_key): os.remove(ssl_key) if os.path.exists(ssl_crt) or os.path.lexists(ssl_crt): os.remove(ssl_crt) os.symlink(new_ssl_key, ssl_key) os.symlink(new_ssl_crt, ssl_crt) _set_maindomain(new_domain) except Exception as e: logger.warning("%s" % e, exc_info=1) raise MoulinetteError(errno.EPERM, m18n.n('maindomain_change_failed')) # Regen configurations try: with open('/etc/yunohost/installed', 'r') as f: service_regen_conf() except IOError: pass logger.success(m18n.n('maindomain_changed'))
def test_legacy_app_install_main_domain(): main_domain = _get_maindomain() install_legacy_app(main_domain, "/legacy") app_map_ = app_map(raw=True) assert main_domain in app_map_ assert "/legacy" in app_map_[main_domain] assert "id" in app_map_[main_domain]["/legacy"] assert app_map_[main_domain]["/legacy"]["id"] == "legacy_app" assert app_is_installed(main_domain, "legacy_app") assert app_is_exposed_on_http(main_domain, "/legacy", "This is a dummy app") app_remove("legacy_app") assert app_is_not_installed(main_domain, "legacy_app")
def anonymize(data): def anonymize_domain(data, domain, redact): data = data.replace(domain, redact) # This stuff appears sometimes because some folder in # /var/lib/metronome/ have some folders named this way data = data.replace(domain.replace(".", "%2e"), redact.replace(".", "%2e")) return data # First, let's replace every occurence of the main domain by "domain.tld" # This should cover a good fraction of the info leaked main_domain = _get_maindomain() data = anonymize_domain(data, main_domain, "maindomain.tld") # Next, let's replace other domains. We do this in increasing lengths, # because e.g. knowing that the domain is a sub-domain of another domain may # still be informative. # So e.g. if there's jitsi.foobar.com as a subdomain of foobar.com, it may # be interesting to know that the log is about a supposedly dedicated domain # for jisti (hopefully this explanation make sense). domains = domain_list()["domains"] domains = sorted(domains, key=lambda d: len(d)) count = 2 for domain in domains: if domain not in data: continue data = anonymize_domain(data, domain, "domain%s.tld" % count) count += 1 # We also want to anonymize the ips ipv4 = get_public_ip() ipv6 = get_public_ip(6) if ipv4: data = data.replace(str(ipv4), "xx.xx.xx.xx") if ipv6: data = data.replace(str(ipv6), "xx:xx:xx:xx:xx:xx") return data
def dyndns_subscribe(operation_logger, subscribe_host="dyndns.yunohost.org", domain=None, key=None): """ Subscribe to a DynDNS service Keyword argument: domain -- Full domain to subscribe with key -- Public DNS key subscribe_host -- Dynette HTTP API to subscribe to """ if _guess_current_dyndns_domain(subscribe_host) != (None, None): raise YunohostValidationError('domain_dyndns_already_subscribed') if domain is None: domain = _get_maindomain() operation_logger.related_to.append(("domain", domain)) # Verify if domain is provided by subscribe_host if not _dyndns_provides(subscribe_host, domain): raise YunohostValidationError("dyndns_domain_not_provided", domain=domain, provider=subscribe_host) # Verify if domain is available if not _dyndns_available(subscribe_host, domain): raise YunohostValidationError("dyndns_unavailable", domain=domain) operation_logger.start() if key is None: if len(glob.glob("/etc/yunohost/dyndns/*.key")) == 0: if not os.path.exists("/etc/yunohost/dyndns"): os.makedirs("/etc/yunohost/dyndns") logger.debug(m18n.n("dyndns_key_generating")) os.system( "cd /etc/yunohost/dyndns && " "dnssec-keygen -a hmac-sha512 -b 512 -r /dev/urandom -n USER %s" % domain) os.system( "chmod 600 /etc/yunohost/dyndns/*.key /etc/yunohost/dyndns/*.private" ) private_file = glob.glob("/etc/yunohost/dyndns/*%s*.private" % domain)[0] key_file = glob.glob("/etc/yunohost/dyndns/*%s*.key" % domain)[0] with open(key_file) as f: key = f.readline().strip().split(" ", 6)[-1] import requests # lazy loading this module for performance reasons # Send subscription try: r = requests.post( "https://%s/key/%s?key_algo=hmac-sha512" % (subscribe_host, base64.b64encode(key.encode()).decode()), data={"subdomain": domain}, timeout=30, ) except Exception as e: os.system("rm -f %s" % private_file) os.system("rm -f %s" % key_file) raise YunohostError("dyndns_registration_failed", error=str(e)) if r.status_code != 201: os.system("rm -f %s" % private_file) os.system("rm -f %s" % key_file) try: error = json.loads(r.text)["error"] except Exception: error = 'Server error, code: %s. (Message: "%s")' % (r.status_code, r.text) raise YunohostError("dyndns_registration_failed", error=error) # Yunohost regen conf will add the dyndns cron job if a private key exists # in /etc/yunohost/dyndns regen_conf(["yunohost"]) # Add some dyndns update in 2 and 4 minutes from now such that user should # not have to wait 10ish minutes for the conf to propagate cmd = "at -M now + {t} >/dev/null 2>&1 <<< \"/bin/bash -c 'yunohost dyndns update'\"" # For some reason subprocess doesn't like the redirections so we have to use bash -c explicity... subprocess.check_call(["bash", "-c", cmd.format(t="2 min")]) subprocess.check_call(["bash", "-c", cmd.format(t="4 min")]) logger.success(m18n.n('dyndns_registered'))
def user_create(operation_logger, username, firstname, lastname, domain, password, mailbox_quota="0", mail=None): from yunohost.domain import domain_list, _get_maindomain from yunohost.hook import hook_callback from yunohost.utils.password import assert_password_is_strong_enough from yunohost.utils.ldap import _get_ldap_interface # Ensure sufficiently complex password assert_password_is_strong_enough("user", password) if mail is not None: logger.warning( "Packagers ! Using --mail in 'yunohost user create' is deprecated ... please use --domain instead." ) domain = mail.split("@")[-1] # Validate domain used for email address/xmpp account if domain is None: if msettings.get('interface') == 'api': raise YunohostError('Invalide usage, specify domain argument') else: # On affiche les differents domaines possibles msignals.display(m18n.n('domains_available')) for domain in domain_list()['domains']: msignals.display("- {}".format(domain)) maindomain = _get_maindomain() domain = msignals.prompt( m18n.n('ask_user_domain') + ' (default: %s)' % maindomain) if not domain: domain = maindomain # Check that the domain exists if domain not in domain_list()['domains']: raise YunohostError('domain_name_unknown', domain=domain) mail = username + '@' + domain ldap = _get_ldap_interface() if username in user_list()["users"]: raise YunohostError("user_already_exists", user=username) # Validate uniqueness of username and mail in LDAP try: ldap.validate_uniqueness({ 'uid': username, 'mail': mail, 'cn': username }) except Exception as e: raise YunohostError('user_creation_failed', user=username, error=e) # Validate uniqueness of username in system users all_existing_usernames = {x.pw_name for x in pwd.getpwall()} if username in all_existing_usernames: raise YunohostError('system_username_exists') main_domain = _get_maindomain() aliases = [ 'root@' + main_domain, 'admin@' + main_domain, 'webmaster@' + main_domain, 'postmaster@' + main_domain, 'abuse@' + main_domain, ] if mail in aliases: raise YunohostError('mail_unavailable') operation_logger.start() # Get random UID/GID all_uid = {str(x.pw_uid) for x in pwd.getpwall()} all_gid = {str(x.gr_gid) for x in grp.getgrall()} uid_guid_found = False while not uid_guid_found: # LXC uid number is limited to 65536 by default uid = str(random.randint(200, 65000)) uid_guid_found = uid not in all_uid and uid not in all_gid # Adapt values for LDAP fullname = '%s %s' % (firstname, lastname) attr_dict = { 'objectClass': ['mailAccount', 'inetOrgPerson', 'posixAccount', 'userPermissionYnh'], 'givenName': [firstname], 'sn': [lastname], 'displayName': [fullname], 'cn': [fullname], 'uid': [username], 'mail': mail, # NOTE: this one seems to be already a list 'maildrop': [username], 'mailuserquota': [mailbox_quota], 'userPassword': [_hash_user_password(password)], 'gidNumber': [uid], 'uidNumber': [uid], 'homeDirectory': ['/home/' + username], 'loginShell': ['/bin/false'] } # If it is the first user, add some aliases if not ldap.search(base='ou=users,dc=yunohost,dc=org', filter='uid=*'): attr_dict['mail'] = [attr_dict['mail']] + aliases try: ldap.add('uid=%s,ou=users' % username, attr_dict) except Exception as e: raise YunohostError('user_creation_failed', user=username, error=e) # Invalidate passwd and group to take user and group creation into account subprocess.call(['nscd', '-i', 'passwd']) subprocess.call(['nscd', '-i', 'group']) try: # Attempt to create user home folder subprocess.check_call(["mkhomedir_helper", username]) except subprocess.CalledProcessError: if not os.path.isdir('/home/{0}'.format(username)): logger.warning(m18n.n('user_home_creation_failed'), exc_info=1) # Create group for user and add to group 'all_users' user_group_create(groupname=username, gid=uid, primary_group=True, sync_perm=False) user_group_update(groupname='all_users', add=username, force=True, sync_perm=True) # Trigger post_user_create hooks env_dict = { "YNH_USER_USERNAME": username, "YNH_USER_MAIL": mail, "YNH_USER_PASSWORD": password, "YNH_USER_FIRSTNAME": firstname, "YNH_USER_LASTNAME": lastname } hook_callback('post_user_create', args=[username, mail], env=env_dict) # TODO: Send a welcome mail to user logger.success(m18n.n('user_created')) return {'fullname': fullname, 'username': username, 'mail': mail}
def user_update(operation_logger, username, firstname=None, lastname=None, mail=None, change_password=None, add_mailforward=None, remove_mailforward=None, add_mailalias=None, remove_mailalias=None, mailbox_quota=None): """ Update user informations Keyword argument: lastname mail firstname add_mailalias -- Mail aliases to add remove_mailforward -- Mailforward addresses to remove username -- Username of user to update add_mailforward -- Mailforward addresses to add change_password -- New password to set remove_mailalias -- Mail aliases to remove """ from yunohost.domain import domain_list, _get_maindomain from yunohost.app import app_ssowatconf from yunohost.utils.password import assert_password_is_strong_enough from yunohost.utils.ldap import _get_ldap_interface from yunohost.hook import hook_callback domains = domain_list()['domains'] # Populate user informations ldap = _get_ldap_interface() attrs_to_fetch = ['givenName', 'sn', 'mail', 'maildrop'] result = ldap.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + username, attrs=attrs_to_fetch) if not result: raise YunohostError('user_unknown', user=username) user = result[0] env_dict = {"YNH_USER_USERNAME": username} # Get modifications from arguments new_attr_dict = {} if firstname: new_attr_dict['givenName'] = [firstname] # TODO: Validate new_attr_dict['cn'] = new_attr_dict['displayName'] = [ firstname + ' ' + user['sn'][0] ] env_dict["YNH_USER_FIRSTNAME"] = firstname if lastname: new_attr_dict['sn'] = [lastname] # TODO: Validate new_attr_dict['cn'] = new_attr_dict['displayName'] = [ user['givenName'][0] + ' ' + lastname ] env_dict["YNH_USER_LASTNAME"] = lastname if lastname and firstname: new_attr_dict['cn'] = new_attr_dict['displayName'] = [ firstname + ' ' + lastname ] # change_password is None if user_update is not called to change the password if change_password is not None: # when in the cli interface if the option to change the password is called # without a specified value, change_password will be set to the const 0. # In this case we prompt for the new password. if msettings.get('interface') == 'cli' and not change_password: change_password = msignals.prompt(m18n.n("ask_password"), True, True) # Ensure sufficiently complex password assert_password_is_strong_enough("user", change_password) new_attr_dict['userPassword'] = [_hash_user_password(change_password)] env_dict["YNH_USER_PASSWORD"] = change_password if mail: main_domain = _get_maindomain() aliases = [ 'root@' + main_domain, 'admin@' + main_domain, 'webmaster@' + main_domain, 'postmaster@' + main_domain, ] try: ldap.validate_uniqueness({'mail': mail}) except Exception as e: raise YunohostError('user_update_failed', user=username, error=e) if mail[mail.find('@') + 1:] not in domains: raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:]) if mail in aliases: raise YunohostError('mail_unavailable') del user['mail'][0] new_attr_dict['mail'] = [mail] + user['mail'] if add_mailalias: if not isinstance(add_mailalias, list): add_mailalias = [add_mailalias] for mail in add_mailalias: try: ldap.validate_uniqueness({'mail': mail}) except Exception as e: raise YunohostError('user_update_failed', user=username, error=e) if mail[mail.find('@') + 1:] not in domains: raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:]) user['mail'].append(mail) new_attr_dict['mail'] = user['mail'] if remove_mailalias: if not isinstance(remove_mailalias, list): remove_mailalias = [remove_mailalias] for mail in remove_mailalias: if len(user['mail']) > 1 and mail in user['mail'][1:]: user['mail'].remove(mail) else: raise YunohostError('mail_alias_remove_failed', mail=mail) new_attr_dict['mail'] = user['mail'] if 'mail' in new_attr_dict: env_dict["YNH_USER_MAILS"] = ','.join(new_attr_dict['mail']) if add_mailforward: if not isinstance(add_mailforward, list): add_mailforward = [add_mailforward] for mail in add_mailforward: if mail in user['maildrop'][1:]: continue user['maildrop'].append(mail) new_attr_dict['maildrop'] = user['maildrop'] if remove_mailforward: if not isinstance(remove_mailforward, list): remove_mailforward = [remove_mailforward] for mail in remove_mailforward: if len(user['maildrop']) > 1 and mail in user['maildrop'][1:]: user['maildrop'].remove(mail) else: raise YunohostError('mail_forward_remove_failed', mail=mail) new_attr_dict['maildrop'] = user['maildrop'] if 'maildrop' in new_attr_dict: env_dict["YNH_USER_MAILFORWARDS"] = ','.join(new_attr_dict['maildrop']) if mailbox_quota is not None: new_attr_dict['mailuserquota'] = [mailbox_quota] env_dict["YNH_USER_MAILQUOTA"] = mailbox_quota operation_logger.start() try: ldap.update('uid=%s,ou=users' % username, new_attr_dict) except Exception as e: raise YunohostError('user_update_failed', user=username, error=e) # Trigger post_user_update hooks hook_callback('post_user_update', env=env_dict) logger.success(m18n.n('user_updated')) app_ssowatconf() return user_info(username)
import pytest import os from .conftest import get_test_apps_dir from yunohost.utils.error import YunohostError from yunohost.app import app_install, app_remove, _normalize_domain_path from yunohost.domain import _get_maindomain, domain_url_available from yunohost.permission import _validate_and_sanitize_permission_url # Get main domain maindomain = _get_maindomain() def setup_function(function): try: app_remove("register_url_app") except: pass def teardown_function(function): try: app_remove("register_url_app") except: pass def test_normalize_domain_path():
def setup_function(function): global maindomain maindomain = _get_maindomain()
def setup_function(function): clean_user_groups_permission() global maindomain global other_domains maindomain = _get_maindomain() markers = { m.name: { 'args': m.args, 'kwargs': m.kwargs } for m in function.__dict__.get("pytestmark", []) } if "other_domains" in markers: other_domains = [ "domain_%s.dev" % string.ascii_lowercase[number] for number in range(markers['other_domains']['kwargs']['number']) ] for domain in other_domains: if domain not in domain_list()['domains']: domain_add(domain) # Dirty patch of DNS resolution. Force the DNS to 127.0.0.1 address even if dnsmasq have the public address. # Mainly used for 'can_access_webpage' function dns_cache = {(maindomain, 443, 0, 1): [(2, 1, 6, '', ('127.0.0.1', 443))]} for domain in other_domains: dns_cache[(domain, 443, 0, 1)] = [(2, 1, 6, '', ('127.0.0.1', 443))] def new_getaddrinfo(*args): try: return dns_cache[args] except KeyError: res = prv_getaddrinfo(*args) dns_cache[args] = res return res socket.getaddrinfo = new_getaddrinfo user_create("alice", "Alice", "White", maindomain, dummy_password) user_create("bob", "Bob", "Snow", maindomain, dummy_password) _permission_create_with_dummy_app( permission="wiki.main", url="/", additional_urls=['/whatever', '/idontnow'], auth_header=False, label="Wiki", show_tile=True, allowed=["all_users"], protected=False, sync_perm=False, domain=maindomain, path='/wiki') _permission_create_with_dummy_app(permission="blog.main", url="/", auth_header=True, show_tile=False, protected=False, sync_perm=False, allowed=["alice"], domain=maindomain, path='/blog') _permission_create_with_dummy_app(permission="blog.api", allowed=["visitors"], protected=True, sync_perm=True)
def user_create( operation_logger, username, firstname, lastname, domain, password, mailbox_quota="0", mail=None, ): from yunohost.domain import domain_list, _get_maindomain from yunohost.hook import hook_callback from yunohost.utils.password import assert_password_is_strong_enough from yunohost.utils.ldap import _get_ldap_interface # Ensure sufficiently complex password assert_password_is_strong_enough("user", password) if mail is not None: logger.warning( "Packagers ! Using --mail in 'yunohost user create' is deprecated ... please use --domain instead." ) domain = mail.split("@")[-1] # Validate domain used for email address/xmpp account if domain is None: if msettings.get("interface") == "api": raise YunohostValidationError( "Invalid usage, you should specify a domain argument") else: # On affiche les differents domaines possibles msignals.display(m18n.n("domains_available")) for domain in domain_list()["domains"]: msignals.display("- {}".format(domain)) maindomain = _get_maindomain() domain = msignals.prompt( m18n.n("ask_user_domain") + " (default: %s)" % maindomain) if not domain: domain = maindomain # Check that the domain exists if domain not in domain_list()["domains"]: raise YunohostValidationError("domain_name_unknown", domain=domain) mail = username + "@" + domain ldap = _get_ldap_interface() if username in user_list()["users"]: raise YunohostValidationError("user_already_exists", user=username) # Validate uniqueness of username and mail in LDAP try: ldap.validate_uniqueness({ "uid": username, "mail": mail, "cn": username }) except Exception as e: raise YunohostValidationError("user_creation_failed", user=username, error=e) # Validate uniqueness of username in system users all_existing_usernames = {x.pw_name for x in pwd.getpwall()} if username in all_existing_usernames: raise YunohostValidationError("system_username_exists") main_domain = _get_maindomain() aliases = [ "root@" + main_domain, "admin@" + main_domain, "webmaster@" + main_domain, "postmaster@" + main_domain, "abuse@" + main_domain, ] if mail in aliases: raise YunohostValidationError("mail_unavailable") operation_logger.start() # Get random UID/GID all_uid = {str(x.pw_uid) for x in pwd.getpwall()} all_gid = {str(x.gr_gid) for x in grp.getgrall()} uid_guid_found = False while not uid_guid_found: # LXC uid number is limited to 65536 by default uid = str(random.randint(1001, 65000)) uid_guid_found = uid not in all_uid and uid not in all_gid # Adapt values for LDAP fullname = "%s %s" % (firstname, lastname) attr_dict = { "objectClass": [ "mailAccount", "inetOrgPerson", "posixAccount", "userPermissionYnh", ], "givenName": [firstname], "sn": [lastname], "displayName": [fullname], "cn": [fullname], "uid": [username], "mail": mail, # NOTE: this one seems to be already a list "maildrop": [username], "mailuserquota": [mailbox_quota], "userPassword": [_hash_user_password(password)], "gidNumber": [uid], "uidNumber": [uid], "homeDirectory": ["/home/" + username], "loginShell": ["/bin/false"], } # If it is the first user, add some aliases if not ldap.search(base="ou=users,dc=yunohost,dc=org", filter="uid=*"): attr_dict["mail"] = [attr_dict["mail"]] + aliases try: ldap.add("uid=%s,ou=users" % username, attr_dict) except Exception as e: raise YunohostError("user_creation_failed", user=username, error=e) # Invalidate passwd and group to take user and group creation into account subprocess.call(["nscd", "-i", "passwd"]) subprocess.call(["nscd", "-i", "group"]) try: # Attempt to create user home folder subprocess.check_call(["mkhomedir_helper", username]) except subprocess.CalledProcessError: if not os.path.isdir("/home/{0}".format(username)): logger.warning(m18n.n("user_home_creation_failed"), exc_info=1) # Create group for user and add to group 'all_users' user_group_create(groupname=username, gid=uid, primary_group=True, sync_perm=False) user_group_update(groupname="all_users", add=username, force=True, sync_perm=True) # Trigger post_user_create hooks env_dict = { "YNH_USER_USERNAME": username, "YNH_USER_MAIL": mail, "YNH_USER_PASSWORD": password, "YNH_USER_FIRSTNAME": firstname, "YNH_USER_LASTNAME": lastname, } hook_callback("post_user_create", args=[username, mail], env=env_dict) # TODO: Send a welcome mail to user logger.success(m18n.n("user_created")) return {"fullname": fullname, "username": username, "mail": mail}
def dyndns_subscribe( operation_logger, subscribe_host="dyndns.yunohost.org", domain=None, key=None ): """ Subscribe to a DynDNS service Keyword argument: domain -- Full domain to subscribe with key -- Public DNS key subscribe_host -- Dynette HTTP API to subscribe to """ if len(glob.glob("/etc/yunohost/dyndns/*.key")) != 0 or os.path.exists( "/etc/cron.d/yunohost-dyndns" ): raise YunohostError("domain_dyndns_already_subscribed") if domain is None: domain = _get_maindomain() operation_logger.related_to.append(("domain", domain)) # Verify if domain is provided by subscribe_host if not _dyndns_provides(subscribe_host, domain): raise YunohostError( "dyndns_domain_not_provided", domain=domain, provider=subscribe_host ) # Verify if domain is available if not _dyndns_available(subscribe_host, domain): raise YunohostError("dyndns_unavailable", domain=domain) operation_logger.start() if key is None: if len(glob.glob("/etc/yunohost/dyndns/*.key")) == 0: if not os.path.exists("/etc/yunohost/dyndns"): os.makedirs("/etc/yunohost/dyndns") logger.debug(m18n.n("dyndns_key_generating")) os.system( "cd /etc/yunohost/dyndns && " "dnssec-keygen -a hmac-sha512 -b 512 -r /dev/urandom -n USER %s" % domain ) os.system( "chmod 600 /etc/yunohost/dyndns/*.key /etc/yunohost/dyndns/*.private" ) private_file = glob.glob("/etc/yunohost/dyndns/*%s*.private" % domain)[0] key_file = glob.glob("/etc/yunohost/dyndns/*%s*.key" % domain)[0] with open(key_file) as f: key = f.readline().strip().split(" ", 6)[-1] import requests # lazy loading this module for performance reasons # Send subscription try: r = requests.post( "https://%s/key/%s?key_algo=hmac-sha512" % (subscribe_host, base64.b64encode(key)), data={"subdomain": domain}, timeout=30, ) except Exception as e: os.system("rm -f %s" % private_file) os.system("rm -f %s" % key_file) raise YunohostError("dyndns_registration_failed", error=str(e)) if r.status_code != 201: os.system("rm -f %s" % private_file) os.system("rm -f %s" % key_file) try: error = json.loads(r.text)["error"] except Exception: error = 'Server error, code: %s. (Message: "%s")' % (r.status_code, r.text) raise YunohostError("dyndns_registration_failed", error=error) logger.success(m18n.n("dyndns_registered")) dyndns_installcron()