moulinette/yunohost_tools.py

359 lines
12 KiB
Python
Raw Normal View History

2012-10-23 17:28:35 +02:00
# -*- coding: utf-8 -*-
2013-07-06 09:42:26 +02:00
""" 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
2013-07-06 10:17:16 +02:00
Specific tools
2013-07-06 09:42:26 +02:00
"""
2012-10-26 15:26:50 +02:00
import os
import sys
2012-10-23 17:28:35 +02:00
import yaml
2012-10-26 15:26:50 +02:00
import re
2012-10-27 17:06:43 +02:00
import getpass
2013-07-06 14:58:18 +02:00
import subprocess
2013-07-07 11:30:21 +02:00
import requests
2013-07-07 11:54:10 +02:00
import json
2012-10-29 16:25:40 +01:00
from yunohost import YunoHostError, YunoHostLDAP, validate, colorize, get_required_args, win_msg
2012-10-25 21:15:37 +02:00
from yunohost_domain import domain_add
2013-06-16 14:41:29 +02:00
from yunohost_dyndns import dyndns_subscribe
2013-08-05 09:31:13 +02:00
from yunohost_backup import backup_init
2012-10-27 17:06:43 +02:00
2013-10-10 12:52:21 +02:00
lemon_tmp_conf = '/tmp/tmplemonconf'
2013-07-07 09:38:18 +02:00
def tools_ldapinit(password=None):
2012-10-27 17:06:43 +02:00
"""
2013-07-06 10:17:16 +02:00
YunoHost LDAP initialization
2013-02-26 20:36:37 +01:00
2012-10-27 17:06:43 +02:00
"""
2012-11-09 18:04:15 +01:00
with YunoHostLDAP() as yldap:
2012-10-26 15:26:50 +02:00
2013-02-26 20:36:37 +01:00
with open('ldap_scheme.yml') as f:
2012-11-09 18:04:15 +01:00
ldap_map = yaml.load(f)
2012-10-23 17:28:35 +02:00
2012-11-09 18:04:15 +01:00
for rdn, attr_dict in ldap_map['parents'].items():
2013-07-06 17:27:24 +02:00
yldap.add(rdn, attr_dict)
2012-10-23 18:10:39 +02:00
2013-06-25 13:25:18 +02:00
for rdn, attr_dict in ldap_map['children'].items():
2013-07-06 17:27:24 +02:00
yldap.add(rdn, attr_dict)
2013-02-26 20:36:37 +01:00
2012-11-09 18:04:15 +01:00
admin_dict = {
'cn': 'admin',
'uid': 'admin',
'description': 'LDAP Administrator',
'gidNumber': '1007',
'uidNumber': '1007',
'homeDirectory': '/home/admin',
'loginShell': '/bin/bash',
'objectClass': ['organizationalRole', 'posixAccount', 'simpleSecurityObject']
}
2013-07-06 17:27:24 +02:00
yldap.update('cn=admin', admin_dict)
os.system('rm /etc/smbldap-tools/smbldap_bind.conf')
with open('/etc/smbldap-tools/smbldap_bind.conf', 'w') as f:
lines = [
'masterDN="cn=admin,dc=yunohost,dc=org"',
'slaveDN="cn=admin,dc=yunohost,dc=org"',
'masterPw="yunohost"',
'slavePw="yunohost"'
]
for line in lines:
f.write(line +'\n')
os.system('chmod 600 /etc/smbldap-tools/smbldap_bind.conf')
os.system('smbpasswd -w yunohost')
2013-07-07 11:42:07 +02:00
sid = subprocess.check_output(['net', 'getlocalsid', 'YUNOHOST']).strip().split(':')[1][1:]
2013-07-07 09:38:18 +02:00
os.system('echo \'SID="'+ sid +'"\' >> /etc/smbldap-tools/smbldap.conf')
if password is not None:
os.system('echo "'+ password +'\n'+ password +'" | smbldap-populate')
2012-10-23 19:55:40 +02:00
2012-10-29 16:06:46 +01:00
win_msg(_("LDAP has been successfully initialized"))
2012-10-26 15:26:50 +02:00
2012-10-27 17:06:43 +02:00
2013-02-26 20:36:37 +01:00
def tools_adminpw(old_password, new_password):
2012-10-27 17:06:43 +02:00
"""
Change admin password
2013-02-26 20:36:37 +01:00
2013-07-06 10:17:16 +02:00
Keyword argument:
old_password
new_password
2013-02-26 20:36:37 +01:00
2012-10-27 17:06:43 +02:00
"""
2012-10-26 15:26:50 +02:00
# Validate password length
if len(new_password) < 4:
2012-10-26 15:26:50 +02:00
raise YunoHostError(22, _("Password is too short"))
2013-07-06 14:58:18 +02:00
result = os.system('ldappasswd -h localhost -D cn=admin,dc=yunohost,dc=org -w "'+ old_password +'" -a "'+ old_password +'" -s "' + new_password + '"')
result2 = os.system('smbpasswd -w "'+ new_password + '"')
os.system('rm /etc/smbldap-tools/smbldap_bind.conf')
with open('/etc/smbldap-tools/smbldap_bind.conf', 'w') as f:
lines = [
'masterDN="cn=admin,dc=yunohost,dc=org"',
'slaveDN="cn=admin,dc=yunohost,dc=org"',
'masterPw="'+ new_password +'"',
'slavePw="'+ new_password +'"'
]
for line in lines:
f.write(line +'\n')
os.system('chmod 600 /etc/smbldap-tools/smbldap_bind.conf')
2012-10-27 17:06:43 +02:00
2013-07-06 14:58:18 +02:00
if result == result2 == 0:
2012-10-29 16:06:46 +01:00
win_msg(_("Admin password has been changed"))
2012-10-25 21:17:26 +02:00
else:
raise YunoHostError(22, _("Invalid password"))
2012-10-27 17:06:43 +02:00
2013-07-07 11:13:21 +02:00
def tools_maindomain(old_domain, new_domain, dyndns=False):
2012-10-27 17:06:43 +02:00
"""
2013-07-06 10:17:16 +02:00
Main domain change tool
2013-02-26 20:36:37 +01:00
2013-07-06 10:17:16 +02:00
Keyword argument:
old_domain
new_domain
2013-02-26 20:36:37 +01:00
2012-10-27 17:06:43 +02:00
"""
2013-06-08 19:46:15 +02:00
if not old_domain:
2013-04-29 11:54:57 +02:00
with open('/etc/yunohost/current_host', 'r') as f:
old_domain = f.readline().rstrip()
2012-10-27 17:06:43 +02:00
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)
2012-10-26 15:26:50 +02:00
config_files = [
2013-06-09 22:44:23 +02:00
'/etc/postfix/main.cf',
2013-06-10 22:06:02 +02:00
'/etc/metronome/metronome.cfg.lua',
2012-10-27 17:06:43 +02:00
'/etc/dovecot/dovecot.conf',
2012-10-26 15:26:50 +02:00
'/etc/lemonldap-ng/lemonldap-ng.ini',
2013-05-03 12:10:39 +02:00
'/usr/share/yunohost/yunohost-config/others/startup',
'/home/yunohost.backup/tahoe/tahoe.cfg'
2012-10-26 15:26:50 +02:00
]
2013-02-28 11:24:48 +01:00
config_dir = []
2012-10-26 15:26:50 +02:00
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))
2012-10-26 15:26:50 +02:00
2013-06-22 13:37:44 +02:00
domain_add([new_domain], raw=False, main=True)
2013-10-10 14:12:48 +02:00
tools_lemonrule('domain', new_domain) # Replace Lemon domain
tools_lemonrule('ldapBase', 'dc=yunohost,dc=org') # Set ldap basedn
tools_lemonrule('portal', 'https://'+ new_domain +'/sso/') # Set SSO url
tools_lemonrule(url=new_domain+'/ynh-admin/', value='$uid eq "admin"')
tools_lemonrule(url=new_domain+'/ynh-user/', value='$uid ne "admin"')
if old_domain is 'yunohost.org':
2013-10-10 14:12:48 +02:00
tools_lemonrule(url=old_domain+'/ynh-admin/', delete=True)
tools_lemonrule(url=old_domain+'/ynh-user/', delete=True)
2013-02-26 20:36:37 +01:00
2013-05-30 16:38:42 +02:00
os.system('rm /etc/yunohost/apache/domains/' + old_domain + '.d/*.fixed.conf') # remove SSO apache conf dir from old domain conf (fail if postinstall)
2013-06-08 20:26:23 +02:00
os.system('rm /etc/ssl/private/yunohost_key.pem')
os.system('rm /etc/ssl/certs/yunohost_crt.pem')
2013-02-26 20:36:37 +01:00
2013-02-28 12:03:51 +01:00
command_list = [
2013-05-30 16:41:42 +02:00
'cp /etc/yunohost/apache/templates/sso.fixed.conf /etc/yunohost/apache/domains/' + new_domain + '.d/sso.fixed.conf', # add SSO apache conf dir to new domain conf
'cp /etc/yunohost/apache/templates/admin.fixed.conf /etc/yunohost/apache/domains/' + new_domain + '.d/admin.fixed.conf',
2013-06-02 20:31:43 +02:00
'cp /etc/yunohost/apache/templates/user.fixed.conf /etc/yunohost/apache/domains/' + new_domain + '.d/user.fixed.conf',
2013-02-28 14:18:10 +01:00
'/usr/share/lemonldap-ng/bin/lmYnhMoulinette',
'echo "" > /tmp/tmplemonconf',
2013-06-09 15:27:17 +02:00
'cp /etc/yunohost/certs/'+ new_domain +'/key.pem /etc/metronome/certs/yunohost_key.pem',
2013-06-09 15:47:47 +02:00
'chown metronome: /etc/metronome/certs/yunohost_key.pem',
2013-06-08 19:46:15 +02:00
'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',
2013-04-29 11:54:57 +02:00
'echo '+ new_domain +' > /etc/yunohost/current_host',
2013-07-06 19:36:19 +02:00
'service apache2 restart',
2013-06-09 15:47:47 +02:00
'service metronome restart',
2013-07-06 19:36:19 +02:00
'service postfix restart',
2013-07-07 15:43:49 +02:00
'service dovecot restart',
2013-08-05 09:53:11 +02:00
'service amavis restart',
'service tahoe-lafs restart'
2013-02-28 12:03:51 +01:00
]
for command in command_list:
if os.system(command) != 0:
raise YunoHostError(17, _("There were a problem during domain changing"))
2013-07-07 11:13:21 +02:00
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)
2013-02-28 12:03:51 +01:00
win_msg(_("Main domain has been successfully changed"))
2012-10-27 17:06:43 +02:00
2012-10-26 15:26:50 +02:00
2013-06-16 14:41:29 +02:00
def tools_postinstall(domain, password, dyndns=False):
2012-10-27 17:06:43 +02:00
"""
2013-07-06 10:17:16 +02:00
YunoHost post-install
2013-02-26 20:36:37 +01:00
2013-07-06 10:17:16 +02:00
Keyword argument:
dyndns -- Subscribe domain to a DynDNS service
domain -- YunoHost main domain
2013-07-06 12:59:06 +02:00
password -- YunoHost admin password
2012-10-27 17:06:43 +02:00
"""
2012-11-09 18:04:15 +01:00
with YunoHostLDAP(password='yunohost') as yldap:
try:
2013-05-03 12:10:39 +02:00
with open('/etc/yunohost/installed') as f: pass
2012-11-09 18:04:15 +01:00
except IOError:
print('Installing YunoHost')
else:
raise YunoHostError(17, _("YunoHost is already installed"))
2012-10-25 19:50:14 +02:00
2013-07-08 14:38:26 +02:00
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"))
2013-06-08 19:46:15 +02:00
# Create required folders
folders_to_create = [
'/etc/yunohost/apps',
2013-06-13 14:20:22 +02:00
'/etc/yunohost/certs',
'/var/cache/yunohost/repo',
'/home/yunohost.samba',
2013-08-05 09:38:54 +02:00
'/home/yunohost.backup',
'/home/yunohost.app'
2013-06-08 19:46:15 +02:00
]
for folder in folders_to_create:
try: os.listdir(folder)
except OSError: os.makedirs(folder)
2013-10-06 12:13:25 +02:00
# Set hostname to avoid amavis bug
if os.system('hostname -d') != 0:
os.system('hostname yunohost.yunohost.org')
2013-06-08 19:46:15 +02:00
# 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',
2013-06-23 19:09:30 +02:00
'cp '+ ssl_dir +'/ca/cacert.pem /etc/ssl/certs/ca-yunohost_crt.pem',
'update-ca-certificates'
2013-06-08 19:46:15 +02:00
]
for command in command_list:
if os.system(command) != 0:
raise YunoHostError(17, _("There were a problem during CA creation"))
2012-11-09 18:04:15 +01:00
# Initialize YunoHost LDAP base
2013-07-07 09:38:18 +02:00
tools_ldapinit(password)
2012-10-26 15:26:50 +02:00
2013-08-05 09:53:11 +02:00
# Initialize backup system
backup_init()
2013-02-27 22:34:16 +01:00
# New domain config
2013-07-07 11:13:21 +02:00
tools_maindomain(old_domain='yunohost.org', new_domain=domain, dyndns=dyndns)
2013-02-27 22:34:16 +01:00
2012-11-09 18:04:15 +01:00
# Change LDAP admin password
tools_adminpw(old_password='yunohost', new_password=password)
2012-10-26 15:26:50 +02:00
2013-05-03 12:10:39 +02:00
os.system('touch /etc/yunohost/installed')
2013-07-06 15:39:30 +02:00
os.system('service samba restart')
2013-02-26 20:36:37 +01:00
2012-10-29 16:06:46 +01:00
win_msg(_("YunoHost has been successfully configured"))
2013-10-10 12:52:21 +02:00
def tools_lemonrule(key=None, value=None, url=None, priority=None, delete=False, apply=False):
2013-10-10 12:52:21 +02:00
"""
"""
conf_lines = []
if delete: line = "delete $tmp"
else: line = "$tmp"
# locationRule formatter
if url is not None:
2013-10-10 12:52:21 +02:00
# Remove potential "http://" or "https://"
if '://' in url:
url = url[url.index('://') + 3:]
# Split domain and path properly
if '/' in url:
domain = url[:url.index('/')]
path = url[url.index('/'):]
if path[-1:] is not '/':
path = path +'/'
else:
domain = url
path = '/'
line = line +"->{'locationRules'}->{'"+ domain +"'}"
if priority is not None:
line = line +"->{'(?#"+ priority + domain +")^"+ path +"'}"
2013-10-10 12:52:21 +02:00
else:
line = line +"->{'(?#"+ domain +"Z)^"+ path +"'}"
2013-10-10 12:52:21 +02:00
# Free key formatter from tuple
elif key is not None:
if not isinstance(key, tuple): key = (key,)
for level in key:
line = line +"->{'"+ level +"'}"
2013-10-10 13:19:26 +02:00
if line != '$tmp':
if value is None:
line = line +';'
elif isinstance(value, int):
line = line +' = '+ str(value) +';'
else:
line = line +' = \''+ value +'\';'
2013-10-10 12:52:21 +02:00
2013-10-10 13:19:26 +02:00
# Write configuration
with open(lemon_tmp_conf,'a+') as lemon_conf:
lemon_conf.write(line + '\n')
2013-10-10 12:52:21 +02:00
# Apply & reload configuration
if apply:
os.system('chown www-data '+ lemon_tmp_conf)
if os.system('/usr/share/lemonldap-ng/bin/lmYnhMoulinette') == 0:
os.system('service apache2 reload')
win_msg(_("LemonLDAP configured"))
else:
raise YunoHostError(1, _("An error occured during LemonLDAP configuration"))
2013-10-10 13:19:26 +02:00
os.system("echo '' > "+ lemon_tmp_conf)
2013-10-10 12:52:21 +02:00