# -*- coding: utf-8 -*- """ License Copyright (C) 2013 YunoHost This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses """ """ yunohost_tools.py Specific tools """ import logging logging.warning('the module yunohost.tools has not been revisited and updated yet') import os import sys import yaml import re import getpass import subprocess import requests import json from subprocess import Popen, PIPE from domain import domain_add, domain_list from dyndns import dyndns_subscribe from backup import backup_init from app import app_ssowatconf from moulinette.helpers import YunoHostError, YunoHostLDAP, validate, colorize, get_required_args, win_msg def tools_ldapinit(password=None): """ YunoHost LDAP initialization """ with YunoHostLDAP() as yldap: with open('ldap_scheme.yml') as f: ldap_map = yaml.load(f) for rdn, attr_dict in ldap_map['parents'].items(): try: yldap.add(rdn, attr_dict) except: pass for rdn, attr_dict in ldap_map['children'].items(): try: yldap.add(rdn, attr_dict) except: pass admin_dict = { 'cn': 'admin', 'uid': 'admin', 'description': 'LDAP Administrator', 'gidNumber': '1007', 'uidNumber': '1007', 'homeDirectory': '/home/admin', 'loginShell': '/bin/bash', 'objectClass': ['organizationalRole', 'posixAccount', 'simpleSecurityObject'], 'userPassword': 'yunohost' } yldap.update('cn=admin', admin_dict) win_msg(_("LDAP has been successfully initialized")) def tools_adminpw(old_password, new_password): """ Change admin password Keyword argument: new_password old_password """ # Validate password length if len(new_password) < 4: raise YunoHostError(22, _("Password is too short")) old_password.replace('"', '\\"') old_password.replace('&', '\\&') new_password.replace('"', '\\"') new_password.replace('&', '\\&') result = os.system('ldappasswd -h localhost -D cn=admin,dc=yunohost,dc=org -w "'+ old_password +'" -a "'+ old_password +'" -s "' + new_password + '"') if result == 0: win_msg(_("Admin password has been changed")) else: raise YunoHostError(22, _("Invalid password")) def tools_maindomain(old_domain=None, new_domain=None, dyndns=False): """ Main domain change tool Keyword argument: new_domain old_domain """ if not old_domain: with open('/etc/yunohost/current_host', 'r') as f: old_domain = f.readline().rstrip() if not new_domain: return { 'current_main_domain': old_domain } validate(r'^([a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)(\.[a-zA-Z0-9]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)*(\.[a-zA-Z]{1}([a-zA-Z0-9\-]*[a-zA-Z0-9])*)$', old_domain) config_files = [ '/etc/postfix/main.cf', '/etc/metronome/metronome.cfg.lua', '/etc/dovecot/dovecot.conf', '/usr/share/yunohost/yunohost-config/others/startup', '/home/yunohost.backup/tahoe/tahoe.cfg', '/etc/amavis/conf.d/05-node_id', '/etc/amavis/conf.d/50-user' ] config_dir = [] for dir in config_dir: for file in os.listdir(dir): config_files.append(dir + '/' + file) for file in config_files: with open(file, "r") as sources: lines = sources.readlines() with open(file, "w") as sources: for line in lines: sources.write(re.sub(r''+ old_domain +'', new_domain, line)) domain_add([new_domain], main=True) os.system('rm /etc/ssl/private/yunohost_key.pem') os.system('rm /etc/ssl/certs/yunohost_crt.pem') command_list = [ 'ln -s /etc/yunohost/certs/'+ new_domain +'/key.pem /etc/ssl/private/yunohost_key.pem', 'ln -s /etc/yunohost/certs/'+ new_domain +'/crt.pem /etc/ssl/certs/yunohost_crt.pem', 'echo '+ new_domain +' > /etc/yunohost/current_host', 'service nginx restart', 'service metronome restart', 'service postfix restart', 'service dovecot restart', 'service amavis restart' ] try: with open('/etc/yunohost/light') as f: pass except IOError: command_list.append('service amavis restart') #command_list.append('service tahoe-lafs restart') for command in command_list: if os.system(command) != 0: raise YunoHostError(17, _("There were a problem during domain changing")) if dyndns: dyndns_subscribe(domain=new_domain) elif len(new_domain.split('.')) >= 3: r = requests.get('http://dyndns.yunohost.org/domains') dyndomains = json.loads(r.text) dyndomain = '.'.join(new_domain.split('.')[1:]) if dyndomain in dyndomains: dyndns_subscribe(domain=new_domain) win_msg(_("Main domain has been successfully changed")) def tools_postinstall(domain, password, dyndns=False): """ YunoHost post-install Keyword argument: domain -- YunoHost main domain dyndns -- Subscribe domain to a DynDNS service password -- YunoHost admin password """ try: with open('/etc/yunohost/installed') as f: pass except IOError: print('Installing YunoHost') else: raise YunoHostError(17, _("YunoHost is already installed")) if len(domain.split('.')) >= 3: r = requests.get('http://dyndns.yunohost.org/domains') dyndomains = json.loads(r.text) dyndomain = '.'.join(domain.split('.')[1:]) if dyndomain in dyndomains: if requests.get('http://dyndns.yunohost.org/test/'+ domain).status_code == 200: dyndns=True else: raise YunoHostError(17, _("Domain is already taken")) # Create required folders folders_to_create = [ '/etc/yunohost/apps', '/etc/yunohost/certs', '/var/cache/yunohost/repo', '/home/yunohost.backup', '/home/yunohost.app' ] for folder in folders_to_create: try: os.listdir(folder) except OSError: os.makedirs(folder) # Set hostname to avoid amavis bug if os.system('hostname -d') != 0: os.system('hostname yunohost.yunohost.org') # Create SSL CA ssl_dir = '/usr/share/yunohost/yunohost-config/ssl/yunoCA' command_list = [ 'echo "01" > '+ ssl_dir +'/serial', 'rm '+ ssl_dir +'/index.txt', 'touch '+ ssl_dir +'/index.txt', 'cp '+ ssl_dir +'/openssl.cnf '+ ssl_dir +'/openssl.ca.cnf ', 'sed -i "s/yunohost.org/'+ domain +'/g" '+ ssl_dir +'/openssl.ca.cnf ', 'openssl req -x509 -new -config '+ ssl_dir +'/openssl.ca.cnf -days 3650 -out '+ ssl_dir +'/ca/cacert.pem -keyout '+ ssl_dir +'/ca/cakey.pem -nodes -batch', 'cp '+ ssl_dir +'/ca/cacert.pem /etc/ssl/certs/ca-yunohost_crt.pem', 'update-ca-certificates' ] for command in command_list: if os.system(command) != 0: raise YunoHostError(17, _("There were a problem during CA creation")) with YunoHostLDAP(password='yunohost') as yldap: # Initialize YunoHost LDAP base tools_ldapinit(password) # Initialize backup system backup_init() # New domain config tools_maindomain(old_domain='yunohost.org', new_domain=domain, dyndns=dyndns) # Generate SSOwat configuration file app_ssowatconf() # Change LDAP admin password tools_adminpw(old_password='yunohost', new_password=password) os.system('touch /etc/yunohost/installed') os.system('service yunohost-api restart &') win_msg(_("YunoHost has been successfully configured")) def tools_update(): """ Update distribution """ process = Popen("/usr/bin/checkupdate", stdout=PIPE) stdout, stderr = process.communicate() if process.returncode == 1: win_msg( _("Not upgrade found")) elif process.returncode == 2: raise YunoHostError(17, _("Error during update")) else: return { "Update" : stdout.splitlines() } def tools_changelog(): """ Show Changelog """ if os.path.isfile('/tmp/yunohost/update_status'): with open('/tmp/yunohost/changelog', 'r') as f: read_data = f.read() return { "Changelog" : read_data.splitlines() } else: raise YunoHostError(17, _("Launch update before upgrade")) def tools_upgrade(): """ Upgrade distribution """ if os.path.isfile('/tmp/yunohost/upgrade.run'): win_msg( _("Upgrade in progress")) else: if os.path.isfile('/tmp/yunohost/upgrade_status'): with open('/tmp/yunohost/upgrade_status', 'r') as f: read_data = f.read() os.system('rm /tmp/yunohost/upgrade_status') if read_data.strip() == "OK": win_msg( _("YunoHost has been successfully upgraded")) else: raise YunoHostError(17, _("Error during upgrade")) elif os.path.isfile('/tmp/yunohost/update_status'): os.system('at now -f /usr/share/yunohost/upgrade') win_msg( _("Upgrade in progress")) else: raise YunoHostError(17, _("Launch update before upgrade")) def tools_upgradelog(): """ Show upgrade log """ if os.path.isfile('/tmp/yunohost/upgrade.run'): win_msg( _("Upgrade in progress")) else: with open('/tmp/yunohost/update_log', 'r') as f: read_data = f.read() return { "DPKG LOG" : read_data.splitlines() }