Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
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()
Ejemplo n.º 3
0
    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")
Ejemplo n.º 4
0
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)
Ejemplo n.º 5
0
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"])
Ejemplo n.º 6
0
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'))
Ejemplo n.º 7
0
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")
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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'))
Ejemplo n.º 10
0
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}
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
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():
Ejemplo n.º 13
0
def setup_function(function):
    global maindomain
    maindomain = _get_maindomain()
Ejemplo n.º 14
0
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)
Ejemplo n.º 15
0
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}
Ejemplo n.º 16
0
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()