diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index 2ff4f487..9dfb4a49 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -243,6 +243,10 @@ domain: authenticate: all authenticator: ldap-anonymous arguments: + -r: + full: --raw + help: Return domains as a bash-usable list instead of JSON + action: store_true -f: full: --filter help: LDAP filter used to search @@ -260,6 +264,7 @@ domain: action_help: Create a custom domain api: POST /domains configuration: + lock: false authenticate: all arguments: domain: @@ -278,6 +283,7 @@ domain: action_help: Delete domains api: DELETE /domains/ configuration: + lock: false authenticate: all arguments: domain: @@ -913,6 +919,63 @@ service: default: 50 type: int + ### service_regenconf() + regenconf: + action_help: > + Regenerate the configuration file(s) for a service and compare the result + with the existing configuration file. + Prints the differences between files if any. + api: PUT /services/regenconf + configuration: + lock: false + arguments: + -s: + full: --service + help: Regenerate configuration for a specfic service + -f: + full: --force + help: Override the current configuration with the newly generated one, even if it has been modified + action: store_true + + ### service_safecopy() + safecopy: + action_help: > + Check if the specific file has been modified and display differences. + Stores the file hash in the services.yml file + api: PUT /services/safecopy + arguments: + new_conf_file: + help: Path to the desired conf file + conf_file: + help: Path to the targeted conf file + -s: + full: --service + help: Service name attached to the conf file + extra: + required: True + -f: + full: --force + help: Override the current configuration with the newly generated one, even if it has been modified + action: store_true + + ### service_saferemove() + saferemove: + action_help: > + Check if the specific file has been modified before removing it. + Backup the file in /home/yunohost.backup + api: PUT /services/safecopy + arguments: + conf_file: + help: Path to the targeted conf file + -s: + full: --service + help: Service name attached to the conf file + extra: + required: True + -f: + full: --force + help: Force file deletion + action: store_true ############################# # Firewall # diff --git a/data/hooks/conf_regen/01-yunohost b/data/hooks/conf_regen/01-yunohost new file mode 100644 index 00000000..30d77a5d --- /dev/null +++ b/data/hooks/conf_regen/01-yunohost @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +force=$1 + +cd /usr/share/yunohost/templates/yunohost + +sudo mkdir -p /etc/yunohost + +if [ ! -f /etc/yunohost/current_host ]; then + echo "yunohost.org" | sudo tee /etc/yunohost/current_host +fi + +if [ ! -f /etc/yunohost/firewall.yml ]; then + sudo cp firewall.yml /etc/yunohost/firewall.yml +fi + +if [ ! -f /etc/yunohost/services.yml ]; then + sudo cp services.yml /etc/yunohost/services.yml +fi + +# Allow users to access /media directory +if [ ! -d /etc/skel/media ]; then + mkdir -p /media + ln -s /media /etc/skel/ +fi diff --git a/data/hooks/conf_regen/02-ssl b/data/hooks/conf_regen/02-ssl new file mode 100644 index 00000000..64614ffa --- /dev/null +++ b/data/hooks/conf_regen/02-ssl @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [ ! -f /etc/yunohost/installed ]; then + sudo cp $1 $2 + else + if [ $force ]; then + sudo yunohost service safecopy \ + -s ssl $1 $2 --force + else + sudo yunohost service safecopy \ + -s ssl $1 $2 + fi + fi +} + +cd /usr/share/yunohost/templates/ssl +ssl_dir=/usr/share/yunohost/yunohost-config/ssl/yunoCA + +sudo mkdir -p /etc/yunohost/certs/yunohost.org +sudo mkdir -p $ssl_dir/{ca,certs,crl,newcerts} + +safe_copy openssl.cnf $ssl_dir/openssl.cnf + +[ -f $ssl_dir/serial ] \ + || (echo "00" | sudo tee $ssl_dir/serial) + +[ -f $ssl_dir/index.txt ] \ + || sudo touch $ssl_dir/index.txt + +if [ ! -f /etc/yunohost/certs/yunohost.org/ca.pem ]; then + sudo openssl req -x509 -new -config $ssl_dir/openssl.cnf \ + -days 3650 -out $ssl_dir/ca/cacert.pem \ + -keyout $ssl_dir/ca/cakey.pem -nodes -batch + sudo cp $ssl_dir/ca/cacert.pem \ + /etc/yunohost/certs/yunohost.org/ca.pem + sudo ln -sf /etc/yunohost/certs/yunohost.org/ca.pem \ + /etc/ssl/certs/ca-yunohost_crt.pem + sudo update-ca-certificates +fi + +if [ ! -f /etc/yunohost/certs/yunohost.org/crt.pem ]; then + sudo openssl req -new -config $ssl_dir/openssl.cnf \ + -days 730 -out $ssl_dir/certs/yunohost_csr.pem \ + -keyout $ssl_dir/certs/yunohost_key.pem -nodes -batch + sudo openssl ca -config $ssl_dir/openssl.cnf \ + -days 730 -in $ssl_dir/certs/yunohost_csr.pem \ + -out $ssl_dir/certs/yunohost_crt.pem -batch + + last_cert=$(ls $ssl_dir/newcerts/*.pem | sort -V | tail -n 1) + sudo chmod 640 $ssl_dir/certs/yunohost_key.pem + sudo chmod 640 $last_cert + + sudo cp $ssl_dir/certs/yunohost_key.pem \ + /etc/yunohost/certs/yunohost.org/key.pem + sudo cp $last_cert \ + /etc/yunohost/certs/yunohost.org/crt.pem + sudo ln -sf /etc/yunohost/certs/yunohost.org/crt.pem \ + /etc/ssl/certs/yunohost_crt.pem + sudo ln -sf /etc/yunohost/certs/yunohost.org/key.pem \ + /etc/ssl/private/yunohost_key.pem +fi diff --git a/data/hooks/conf_regen/03-ssh b/data/hooks/conf_regen/03-ssh new file mode 100644 index 00000000..2481bd31 --- /dev/null +++ b/data/hooks/conf_regen/03-ssh @@ -0,0 +1,31 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [ $force ]; then + sudo yunohost service safecopy \ + -s ssh \ + $1 $2 \ + --force + else + sudo yunohost service safecopy \ + -s ssh \ + $1 $2 + fi +} + +cd /usr/share/yunohost/templates/ssh + +# Only overwrite SSH configuration on an ISO installation +if [ ! -f /etc/yunohost/from_script ]; then + + # Do not listen to IPv6 if unavailable + if [ ! -f /proc/net/if_inet6 ]; then + sudo sed -i "s/ListenAddress ::/#ListenAddress ::/g" sshd_config + fi + safe_copy sshd_config /etc/ssh/sshd_config + + sudo service ssh restart +fi diff --git a/data/hooks/conf_regen/06-slapd b/data/hooks/conf_regen/06-slapd new file mode 100644 index 00000000..63cffac2 --- /dev/null +++ b/data/hooks/conf_regen/06-slapd @@ -0,0 +1,52 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [ ! -f /etc/yunohost/installed ]; then + sudo cp $1 $2 + else + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s slapd $1 $2 --force + else + sudo yunohost service safecopy \ + -s slapd $1 $2 + fi + fi +} + +cd /usr/share/yunohost/templates/slapd + +# Remove legacy configuration file +[ ! -f /etc/yunohost/installed ] \ + || sudo yunohost service saferemove -s slapd \ + /etc/ldap/slapd-yuno.conf + +safe_copy sudo.schema /etc/ldap/schema/sudo.schema +safe_copy mailserver.schema /etc/ldap/schema/mailserver.schema +safe_copy ldap.conf /etc/ldap/ldap.conf +safe_copy slapd.default /etc/default/slapd + +# Compatibility: change from HDB to MDB on Jessie +version=$(sed 's/\..*//' /etc/debian_version) +if [[ "$version" == '8' ]]; then + cat slapd.conf \ + | sed "s/hdb$/mdb/g" \ + | sed "s/back_hdb/back_mdb/g" \ + | sed "s/^dbconfig set_/#dbconfig set_/g" \ + | sudo tee slapd.conf +fi + +safe_copy slapd.conf /etc/ldap/slapd.conf +sudo chown root:openldap /etc/ldap/slapd.conf +sudo rm -Rf /etc/ldap/slapd.d +sudo mkdir /etc/ldap/slapd.d +sudo chown -R openldap:openldap /etc/ldap/schema/ +sudo chown -R openldap:openldap /etc/ldap/slapd.d/ + +sudo slaptest -f /etc/ldap/slapd.conf -F /etc/ldap/slapd.d/ +sudo chown -R openldap:openldap /etc/ldap/slapd.d/ + +sudo service slapd force-reload diff --git a/data/hooks/conf_regen/09-nslcd b/data/hooks/conf_regen/09-nslcd new file mode 100644 index 00000000..da09e6ac --- /dev/null +++ b/data/hooks/conf_regen/09-nslcd @@ -0,0 +1,27 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s nslcd \ + $1 $2 \ + --force + else + sudo yunohost service safecopy \ + -s nslcd \ + $1 $2 + fi +} + +cd /usr/share/yunohost/templates/nslcd + +safe_copy nslcd.conf /etc/nslcd.conf + +# Fix: Add a blank line at the end of the file +# to avoid nscld restart failure +echo -e "\n" | sudo tee -a /etc/nslcd.conf + +sudo service nslcd restart diff --git a/data/hooks/conf_regen/12-metronome b/data/hooks/conf_regen/12-metronome new file mode 100644 index 00000000..70fa64dd --- /dev/null +++ b/data/hooks/conf_regen/12-metronome @@ -0,0 +1,80 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s metronome \ + $1 $2 \ + --force + else + sudo yunohost service safecopy \ + -s metronome \ + $1 $2 + fi +} + +cd /usr/share/yunohost/templates/metronome + +# Copy additional modules +files="ldap.lib.lua +mod_auth_ldap2.lua +mod_legacyauth.lua +mod_storage_ldap.lua +vcard.lib.lua" + +for file in $files; do + safe_copy modules/$file /usr/lib/metronome/modules/$file +done + +# Copy configuration files +main_domain=$(cat /etc/yunohost/current_host) +cat metronome.cfg.lua.sed \ + | sed "s/{{ main_domain }}/$main_domain/g" \ + | sudo tee metronome.cfg.lua +safe_copy metronome.cfg.lua /etc/metronome/metronome.cfg.lua +safe_copy metronome.init /etc/init.d/metronome +safe_copy metronome.logrotate /etc/logrotate.d/metronome + +need_restart=False +sudo mkdir -p /etc/metronome/conf.d + +domain_list=$(sudo yunohost domain list --plain) + +# Copy a configuration file for each YunoHost domain +for domain in $domain_list; do + sanitzed_domain="$(echo $domain | sed 's/\./%2e/g')" + sudo mkdir -p /var/lib/metronome/$sanitzed_domain/pep + + cat domain.cfg.lua.sed \ + | sed "s/{{ domain }}/$domain/g" \ + | sudo tee $domain.cfg.lua + if [[ $(safe_copy $domain.cfg.lua /etc/metronome/conf.d/$domain.cfg.lua) == "True" ]]; then + need_restart=True + fi +done + +# Remove old domains files +for file in /etc/metronome/conf.d/*; do + domain=$(echo $file \ + | sed 's|/etc/metronome/conf.d/||' \ + | sed 's|.cfg.lua||') + sanitzed_domain="$(echo $domain | sed 's/\./%2e/g')" + [[ $domain_list =~ $domain ]] \ + || ($(sudo yunohost service saferemove -s metronome $file) == "True" \ + && rm -rf /var/lib/metronome/$sanitzed_domain) + +done + +# Create domain directory +sudo chown -R metronome: /var/lib/metronome/ +sudo chown -R metronome: /etc/metronome/conf.d/ + +# Restart if need be +if [[ "$need_restart" == "True" ]]; then + sudo service metronome restart +else + sudo service metronome reload +fi diff --git a/data/hooks/conf_regen/15-nginx b/data/hooks/conf_regen/15-nginx new file mode 100644 index 00000000..e5a8716b --- /dev/null +++ b/data/hooks/conf_regen/15-nginx @@ -0,0 +1,83 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [ ! -f /etc/yunohost/installed ]; then + sudo cp $1 $2 + else + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s nginx \ + $1 $2 \ + --force + else + sudo yunohost service safecopy \ + -s nginx \ + $1 $2 + fi + fi +} + +cd /usr/share/yunohost/templates/nginx + +# Copy plain single configuration files +files="ssowat.conf +yunohost_admin.conf +yunohost_admin.conf.inc +yunohost_api.conf.inc +yunohost_panel.conf.inc" + +for file in $files; do + safe_copy $file /etc/nginx/conf.d/$file +done + + +if [ -f /etc/yunohost/installed ]; then + + need_restart=False + domain_list=$(sudo yunohost domain list --plain) + + # Copy a configuration file for each YunoHost domain + for domain in $domain_list; do + sudo mkdir -p /etc/nginx/conf.d/$domain.d + cat server.conf.sed \ + | sed "s/{{ domain }}/$domain/g" \ + | sudo tee $domain.conf + [[ $(safe_copy $domain.conf /etc/nginx/conf.d/$domain.conf) == "True" ]] \ + && need_restart=True + + [ -f /etc/nginx/conf.d/$domain.d/yunohost_local.conf ] \ + && [[ $main_domain != $domain ]] \ + && sudo yunohost service saferemove -s nginx \ + /etc/nginx/conf.d/$domain.d/yunohost_local.conf + done + + + # Copy 'yunohost.local' to the main domain conf directory + main_domain=$(cat /etc/yunohost/current_host) + safe_copy yunohost_local.conf \ + /etc/nginx/conf.d/$main_domain.d/yunohost_local.conf + + + # Remove old domains files + for file in /etc/nginx/conf.d/*.*.conf; do + domain=$(echo $file \ + | sed 's|/etc/nginx/conf.d/||' \ + | sed 's|.conf||') + [[ $domain_list =~ $domain ]] \ + || ($(sudo yunohost service saferemove -s nginx $file) == "True" \ + && (rm -r /etc/nginx/conf.d/$domain.d || true)) + done + +else + [ ! -f /etc/nginx/sites-available/default ] \ + || rm -f /etc/nginx/sites-enabled/default + need_restart=True +fi + +# Restart if need be +[[ "$need_restart" == "True" ]] \ + && sudo service nginx restart \ + || sudo service nginx reload diff --git a/data/hooks/conf_regen/19-postfix b/data/hooks/conf_regen/19-postfix new file mode 100644 index 00000000..38061ee6 --- /dev/null +++ b/data/hooks/conf_regen/19-postfix @@ -0,0 +1,56 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s postfix \ + $1 $2 \ + --force + else + sudo yunohost service safecopy \ + -s postfix \ + $1 $2 + fi +} + +cd /usr/share/yunohost/templates/postfix + +# Copy plain single configuration files +files="header_check +ldap-accounts.cf +ldap-aliases.cf +ldap-domains.cf +master.cf +sender_canonical +smtp_reply_filter" + +for file in $files; do + safe_copy $file /etc/postfix/$file +done + +main_domain=$(cat /etc/yunohost/current_host) + +# Replace main domain in the main configuration file +cat main.cf.sed \ + | sed "s/{{ main_domain }}/$main_domain/g" \ + | sudo tee main.cf + +# And adapt it to IPv4-only hosts +if [ ! -f /proc/net/if_inet6 ]; then + sudo sed -i \ + 's/ \[::ffff:127.0.0.0\]\/104 \[::1\]\/128//g' \ + main.cf + + sudo sed -i \ + 's/inet_interfaces = all/inet_interfaces = all\ninet_protocols = ipv4/' \ + main.cf +fi + +if [[ $(safe_copy main.cf /etc/postfix/main.cf) == "True" ]]; then + sudo service postfix restart +else + sudo service postfix reload +fi diff --git a/data/hooks/conf_regen/22-postgrey b/data/hooks/conf_regen/22-postgrey new file mode 100644 index 00000000..b1f924a0 --- /dev/null +++ b/data/hooks/conf_regen/22-postgrey @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s postgrey \ + $1 $2 \ + --force + else + sudo yunohost service safecopy \ + -s postgrey \ + $1 $2 + fi +} + +cd /usr/share/yunohost/templates/postgrey + +if [[ "$(safe_copy postgrey.default /etc/default/postgrey)" == "True" ]]; then + sudo service nslcd restart +fi diff --git a/data/hooks/conf_regen/25-dovecot b/data/hooks/conf_regen/25-dovecot new file mode 100644 index 00000000..974fa3e0 --- /dev/null +++ b/data/hooks/conf_regen/25-dovecot @@ -0,0 +1,54 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s dovecot $1 $2 --force + else + sudo yunohost service safecopy \ + -s dovecot $1 $2 + fi +} + +cd /usr/share/yunohost/templates/dovecot + +# Create vmail user +sudo id vmail > /dev/null 2>&1 \ + || sudo adduser --system --ingroup mail --uid 500 vmail + + +# Replace main domain in the main configuration file +main_domain=$(cat /etc/yunohost/current_host) +cat dovecot.conf.sed \ + | sed "s/{{ main_domain }}/$main_domain/g" \ + | sudo tee dovecot.conf + + +# Handle IPv4 only systems +if [ ! -f /proc/net/if_inet6 ]; +then + sudo sed -i 's/^listen.*/listen = \*/' dovecot.conf +fi + + +safe_copy dovecot.conf /etc/dovecot/dovecot.conf +safe_copy dovecot-ldap.conf /etc/dovecot/dovecot-ldap.conf + + +# Setup Sieve +sudo rm -rf /etc/dovecot/global_script +sudo mkdir -p -m 0770 /etc/dovecot/global_script +safe_copy sa-learn-pipe.sh /usr/bin/sa-learn-pipe.sh +sudo chmod 755 /usr/bin/sa-learn-pipe.sh + +safe_copy dovecot.sieve /etc/dovecot/global_script/dovecot.sieve +sudo chmod 660 /etc/dovecot/global_script/dovecot.sieve > /dev/null 2>&1 \ + || safe_copy dovecot.sieve /etc/dovecot/global_script/dovecot.sieve +sudo sievec /etc/dovecot/global_script/dovecot.sieve +sudo chmod 660 /etc/dovecot/global_script/dovecot.svbin + + +sudo service dovecot restart diff --git a/data/hooks/conf_regen/28-spamassassin b/data/hooks/conf_regen/28-spamassassin new file mode 100644 index 00000000..e55f10dc --- /dev/null +++ b/data/hooks/conf_regen/28-spamassassin @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s spamassassin $1 $2 --force + else + sudo yunohost service safecopy \ + -s spamassassin $1 $2 + fi +} + +cd /usr/share/yunohost/templates/spamassassin + +safe_copy spamassassin.default /etc/default/spamassassin +safe_copy local.cf /etc/spamassassin/local.cf + +sudo service spamassassin restart diff --git a/data/hooks/conf_regen/31-amavis b/data/hooks/conf_regen/31-amavis new file mode 100644 index 00000000..f25c70fe --- /dev/null +++ b/data/hooks/conf_regen/31-amavis @@ -0,0 +1,37 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s amavis $1 $2 --force + else + sudo yunohost service safecopy \ + -s amavis $1 $2 + fi +} + +cd /usr/share/yunohost/templates/amavis + +sudo mkdir -p /etc/amavis/conf.d/ + +# Copy plain single configuration files +files="05-domain_id +05-node_id +15-content_filter_mode +20-debian_defaults" + +for file in $files; do + safe_copy $file /etc/amavis/conf.d/$file +done + +main_domain=$(cat /etc/yunohost/current_host) +cat 50-user.sed \ + | sed "s/{{ main_domain }}/$main_domain/g" \ + | sudo tee 50-user +safe_copy 50-user /etc/amavis/conf.d/50-user + + +sudo service amavis restart diff --git a/data/hooks/conf_regen/34-mysql b/data/hooks/conf_regen/34-mysql new file mode 100644 index 00000000..021e4537 --- /dev/null +++ b/data/hooks/conf_regen/34-mysql @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s mysql $1 $2 --force + else + sudo yunohost service safecopy \ + -s mysql $1 $2 + fi +} + +function randpass () { + [ "$2" == "0" ] && CHAR="[:alnum:]" || CHAR="[:graph:]" + cat /dev/urandom | tr -cd "$CHAR" | head -c ${1:-32} + echo +} + +cd /usr/share/yunohost/templates/mysql + +if [[ "$(safe_copy my.cnf /etc/mysql/my.cnf)" == "True" ]]; then + sudo service mysql restart +fi + +if [ ! -f /etc/yunohost/mysql ]; then + [[ $(/bin/ps aux | grep mysqld | grep -vc "grep") == "0" ]] \ + && sudo service mysql start + + mysql_password=$(randpass 10 0) + sudo mysqladmin -u root -pyunohost password $mysql_password + echo $mysql_password | sudo tee /etc/yunohost/mysql + sudo chmod 400 /etc/yunohost/mysql +fi diff --git a/data/hooks/conf_regen/37-avahi-daemon b/data/hooks/conf_regen/37-avahi-daemon new file mode 100644 index 00000000..31306de5 --- /dev/null +++ b/data/hooks/conf_regen/37-avahi-daemon @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s avahi-daemon $1 $2 --force + else + sudo yunohost service safecopy \ + -s avahi-daemon $1 $2 + fi +} + +cd /usr/share/yunohost/templates/avahi-daemon + +if [[ "$(safe_copy avahi-daemon.conf /etc/avahi/avahi-daemon.conf)" == "True" ]]; then + sudo service avahi-daemon restart +fi diff --git a/data/hooks/conf_regen/40-glances b/data/hooks/conf_regen/40-glances new file mode 100644 index 00000000..9f7c9c5c --- /dev/null +++ b/data/hooks/conf_regen/40-glances @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s glances $1 $2 --force + else + sudo yunohost service safecopy \ + -s glances $1 $2 + fi +} + +cd /usr/share/yunohost/templates/glances + +if [[ "$(safe_copy glances.default /etc/default/glances)" == "True" ]]; then + sudo service glances restart +fi diff --git a/data/hooks/conf_regen/43-dnsmasq b/data/hooks/conf_regen/43-dnsmasq new file mode 100644 index 00000000..821bfa39 --- /dev/null +++ b/data/hooks/conf_regen/43-dnsmasq @@ -0,0 +1,50 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s dnsmasq $1 $2 --force + else + sudo yunohost service safecopy \ + -s dnsmasq $1 $2 + fi +} + +cd /usr/share/yunohost/templates/dnsmasq + +# Get IP address +ip=$(curl ip.yunohost.org || echo '0.0.0.0') + +# Get IPv6 IP address +ipv6=$(ip route get 2000:: | grep -q "unreachable" && echo '' \ + || ip route get 2000:: | grep -v ' fe80:' | grep -v 'cache' | awk '{print $9}') + +sudo mkdir -p /etc/dnsmasq.d + +domain_list=$(sudo yunohost domain list --plain) + +# Copy a configuration file for each YunoHost domain +for domain in $domain_list; do + cat domain.sed \ + | sed "s/{{ domain }}/$domain/g" \ + | sed "s/{{ ip }}/$ip/g" \ + | sudo tee $domain + + if [[ "$ipv6" != "" ]]; then + echo "address=/$domain/$ipv6" | sudo tee -a $domain + fi + + safe_copy $domain /etc/dnsmasq.d/$domain +done + +# Remove old domains files +for file in /etc/dnsmasq.d/*.*; do + domain=$(echo $file | sed 's|/etc/dnsmasq.d/||') + [[ $domain_list =~ $domain ]] \ + || sudo yunohost service saferemove -s dnsmasq $file +done + +sudo service dnsmasq reload diff --git a/data/hooks/conf_regen/46-nsswitch b/data/hooks/conf_regen/46-nsswitch new file mode 100644 index 00000000..73535eed --- /dev/null +++ b/data/hooks/conf_regen/46-nsswitch @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s nsswitch $1 $2 --force + else + sudo yunohost service safecopy \ + -s nsswitch $1 $2 + fi +} + +cd /usr/share/yunohost/templates/nsswitch + +if [[ "$(safe_copy nsswitch.conf /etc/nsswitch.conf)" == "True" ]]; then + sudo service nscd restart +fi diff --git a/data/hooks/conf_regen/49-udisks-glue b/data/hooks/conf_regen/49-udisks-glue new file mode 100644 index 00000000..85de9182 --- /dev/null +++ b/data/hooks/conf_regen/49-udisks-glue @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s udisks-glue $1 $2 --force + else + sudo yunohost service safecopy \ + -s udisks-glue $1 $2 + fi +} + +cd /usr/share/yunohost/templates/udisks-glue + +if [[ "$(safe_copy udisks-glue.conf /etc/udisks-glue.conf)" == "True" ]]; then + sudo service udisks-glue restart +fi diff --git a/data/hooks/conf_regen/52-fail2ban b/data/hooks/conf_regen/52-fail2ban new file mode 100644 index 00000000..9c609c74 --- /dev/null +++ b/data/hooks/conf_regen/52-fail2ban @@ -0,0 +1,29 @@ +#!/bin/bash +set -e + +force=$1 + +function safe_copy () { + if [[ "$force" == "True" ]]; then + sudo yunohost service safecopy \ + -s fail2ban $1 $2 --force + else + sudo yunohost service safecopy \ + -s fail2ban $1 $2 + fi +} + +cd /usr/share/yunohost/templates/fail2ban + +sudo mkdir -p /etc/fail2ban/filter.d +safe_copy yunohost.conf /etc/fail2ban/filter.d/yunohost.conf + +# Compatibility: change from HDB to MDB on Jessie +version=$(sed 's/\..*//' /etc/debian_version) +[[ "$version" == '8' ]] \ + && sudo cp jail-jessie.conf jail.conf \ + || sudo cp jail-wheezy.conf jail.conf + +if [[ $(safe_copy jail.conf /etc/fail2ban/jail.conf) == "True" ]]; then + sudo service fail2ban restart +fi diff --git a/data/templates/amavis/05-domain_id b/data/templates/amavis/05-domain_id new file mode 100644 index 00000000..01a71e4b --- /dev/null +++ b/data/templates/amavis/05-domain_id @@ -0,0 +1,19 @@ +use strict; + +# $mydomain is used just for convenience in the config files and it is not +# used internally by amavisd-new except in the default X_HEADER_LINE (which +# Debian overrides by default anyway). + +#chomp($mydomain = `head -n 1 /etc/mailname`); + +# amavisd-new needs to know which email domains are to be considered local +# to the administrative domain. Only emails to "local" domains are subject +# to certain functionality, such as the addition of spam tags. +# +# Default local domains to $mydomain and all subdomains. Remember to +# override or redefine this if $mydomain is changed later in the config +# sequence. + +@local_domains_acl = ( ".$mydomain" ); + +1; # ensure a defined return diff --git a/data/templates/amavis/05-node_id b/data/templates/amavis/05-node_id new file mode 100644 index 00000000..ee666543 --- /dev/null +++ b/data/templates/amavis/05-node_id @@ -0,0 +1,13 @@ +use strict; + +# $myhostname is used by amavisd-new for node identification, and it is +# important to get it right (e.g. for ESMTP EHLO, loop detection, and so on). + +#chomp($myhostname = `hostname --fqdn`); + +# To manually set $myhostname, edit the following line with the correct Fully +# Qualified Domain Name (FQDN) and remove the # at the beginning of the line. +# +#$myhostname = "mail.example.com"; + +1; # ensure a defined return diff --git a/data/templates/amavis/15-content_filter_mode b/data/templates/amavis/15-content_filter_mode new file mode 100644 index 00000000..825e9e03 --- /dev/null +++ b/data/templates/amavis/15-content_filter_mode @@ -0,0 +1,23 @@ +use strict; + +# You can modify this file to re-enable SPAM checking through spamassassin +# and to re-enable antivirus checking. + +# +# Default antivirus checking mode +# Uncomment the two lines below to enable it back +# + +#@bypass_virus_checks_maps = ( +# \%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re); + + +# +# Default SPAM checking mode +# Uncomment the two lines below to enable it back +# + +@bypass_spam_checks_maps = ( + \%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re); + +1; # ensure a defined return diff --git a/data/templates/amavis/20-debian_defaults b/data/templates/amavis/20-debian_defaults new file mode 100644 index 00000000..83e553d2 --- /dev/null +++ b/data/templates/amavis/20-debian_defaults @@ -0,0 +1,216 @@ +use strict; + +# ADMINISTRATORS: +# Debian suggests that any changes you need to do that should never +# be "updated" by the Debian package should be made in another file, +# overriding the settings in this file. +# +# The package will *not* overwrite your settings, but by keeping +# them separate, you will make the task of merging changes on these +# configuration files much simpler... + +# see /usr/share/doc/amavisd-new/examples/amavisd.conf-default for +# a list of all variables with their defaults; +# see /usr/share/doc/amavisd-new/examples/amavisd.conf-sample for +# a traditional-style commented file +# [note: the above files were not converted to Debian settings!] +# +# for more details see documentation in /usr/share/doc/amavisd-new +# and at http://www.ijs.si/software/amavisd/amavisd-new-docs.html + +$QUARANTINEDIR = "$MYHOME/virusmails"; +$quarantine_subdir_levels = 1; # enable quarantine dir hashing + +$log_recip_templ = undef; # disable by-recipient level-0 log entries +$DO_SYSLOG = 1; # log via syslogd (preferred) +$syslog_ident = 'amavis'; # syslog ident tag, prepended to all messages +$syslog_facility = 'mail'; +$syslog_priority = 'debug'; # switch to info to drop debug output, etc + +$enable_db = 1; # enable use of BerkeleyDB/libdb (SNMP and nanny) +$enable_global_cache = 1; # enable use of libdb-based cache if $enable_db=1 + +$inet_socket_port = 10024; # default listening socket + +$sa_spam_subject_tag = '***SPAM*** '; +$sa_tag_level_deflt = undef; # add spam info headers if at, or above that level +$sa_tag2_level_deflt = 4.00; # add 'spam detected' headers at that level +$sa_kill_level_deflt = 20.00; # triggers spam evasive actions +$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent + +$sa_mail_body_size_limit = 200*1024; # don't waste time on SA if mail is larger +$sa_local_tests_only = 0; # only tests which do not require internet access? + +$recipient_delimiter = '+'; +@addr_extension_spam_maps = ('Junk'); + +# Quota limits to avoid bombs (like 42.zip) + +$MAXLEVELS = 14; +$MAXFILES = 1500; +$MIN_EXPANSION_QUOTA = 100*1024; # bytes +$MAX_EXPANSION_QUOTA = 300*1024*1024; # bytes + +# You should: +# Use D_DISCARD to discard data (viruses) +# Use D_BOUNCE to generate local bounces by amavisd-new +# Use D_REJECT to generate local or remote bounces by the calling MTA +# Use D_PASS to deliver the message +# +# Whatever you do, *NEVER* use D_REJECT if you have other MTAs *forwarding* +# mail to your account. Use D_BOUNCE instead, otherwise you are delegating +# the bounce work to your friendly forwarders, which might not like it at all. +# +# On dual-MTA setups, one can often D_REJECT, as this just makes your own +# MTA generate the bounce message. Test it first. +# +# Bouncing viruses is stupid, always discard them after you are sure the AV +# is working correctly. Bouncing real SPAM is also useless, if you cannot +# D_REJECT it (and don't D_REJECT mail coming from your forwarders!). + +$final_virus_destiny = D_DISCARD; # (data not lost, see virus quarantine) +$final_banned_destiny = D_BOUNCE; # D_REJECT when front-end MTA +$final_spam_destiny = D_DISCARD; +$final_bad_header_destiny = D_PASS; # False-positive prone (for spam) + +$enable_dkim_verification = 1; #disabled to prevent warning +$enable_dkim_signing =1; + +$virus_admin = "postmaster\@$mydomain"; # due to D_DISCARD default + +# Set to empty ("") to add no header +$X_HEADER_LINE = "Debian $myproduct_name at $mydomain"; + +# REMAINING IMPORTANT VARIABLES ARE LISTED HERE BECAUSE OF LONGER ASSIGNMENTS + +# +# DO NOT SEND VIRUS NOTIFICATIONS TO OUTSIDE OF YOUR DOMAIN. EVER. +# +# These days, almost all viruses fake the envelope sender and mail headers. +# Therefore, "virus notifications" became nothing but undesired, aggravating +# SPAM. This holds true even inside one's domain. We disable them all by +# default, except for the EICAR test pattern. +# + +@viruses_that_fake_sender_maps = (new_RE( + [qr'\bEICAR\b'i => 0], # av test pattern name + [qr/.*/ => 1], # true for everything else +)); + +@keep_decoded_original_maps = (new_RE( +# qr'^MAIL$', # retain full original message for virus checking (can be slow) + qr'^MAIL-UNDECIPHERABLE$', # recheck full mail if it contains undecipherables + qr'^(ASCII(?! cpio)|text|uuencoded|xxencoded|binhex)'i, +# qr'^Zip archive data', # don't trust Archive::Zip +)); + + +# for $banned_namepath_re, a new-style of banned table, see amavisd.conf-sample + +$banned_filename_re = new_RE( +# qr'^UNDECIPHERABLE$', # is or contains any undecipherable components + + # block certain double extensions anywhere in the base name + qr'\.[^./]*\.(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)\.?$'i, + + qr'\{[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\}?$'i, # Windows Class ID CLSID, strict + + qr'^application/x-msdownload$'i, # block these MIME types + qr'^application/x-msdos-program$'i, + qr'^application/hta$'i, + +# qr'^application/x-msmetafile$'i, # Windows Metafile MIME type +# qr'^\.wmf$', # Windows Metafile file(1) type + +# qr'^message/partial$'i, qr'^message/external-body$'i, # rfc2046 MIME types + +# [ qr'^\.(Z|gz|bz2)$' => 0 ], # allow any in Unix-compressed +# [ qr'^\.(rpm|cpio|tar)$' => 0 ], # allow any in Unix-type archives +# [ qr'^\.(zip|rar|arc|arj|zoo)$'=> 0 ], # allow any within such archives +# [ qr'^application/x-zip-compressed$'i => 0], # allow any within such archives + + qr'.\.(exe|vbs|pif|scr|bat|cmd|com|cpl)$'i, # banned extension - basic +# qr'.\.(ade|adp|app|bas|bat|chm|cmd|com|cpl|crt|emf|exe|fxp|grp|hlp|hta| +# inf|ins|isp|js|jse|lnk|mda|mdb|mde|mdw|mdt|mdz|msc|msi|msp|mst| +# ops|pcd|pif|prg|reg|scr|sct|shb|shs|vb|vbe|vbs| +# wmf|wsc|wsf|wsh)$'ix, # banned ext - long + +# qr'.\.(mim|b64|bhx|hqx|xxe|uu|uue)$'i, # banned extension - WinZip vulnerab. + + qr'^\.(exe-ms)$', # banned file(1) types +# qr'^\.(exe|lha|tnef|cab|dll)$', # banned file(1) types +); +# See http://support.microsoft.com/default.aspx?scid=kb;EN-US;q262631 +# and http://www.cknow.com/vtutor/vtextensions.htm + + +# ENVELOPE SENDER SOFT-WHITELISTING / SOFT-BLACKLISTING + +@score_sender_maps = ({ # a by-recipient hash lookup table, + # results from all matching recipient tables are summed + +# ## per-recipient personal tables (NOTE: positive: black, negative: white) +# 'user1@example.com' => [{'bla-mobile.press@example.com' => 10.0}], +# 'user3@example.com' => [{'.ebay.com' => -3.0}], +# 'user4@example.com' => [{'cleargreen@cleargreen.com' => -7.0, +# '.cleargreen.com' => -5.0}], + + ## site-wide opinions about senders (the '.' matches any recipient) + '.' => [ # the _first_ matching sender determines the score boost + + new_RE( # regexp-type lookup table, just happens to be all soft-blacklist + [qr'^(bulkmail|offers|cheapbenefits|earnmoney|foryou)@'i => 5.0], + [qr'^(greatcasino|investments|lose_weight_today|market\.alert)@'i=> 5.0], + [qr'^(money2you|MyGreenCard|new\.tld\.registry|opt-out|opt-in)@'i=> 5.0], + [qr'^(optin|saveonlsmoking2002k|specialoffer|specialoffers)@'i => 5.0], + [qr'^(stockalert|stopsnoring|wantsome|workathome|yesitsfree)@'i => 5.0], + [qr'^(your_friend|greatoffers)@'i => 5.0], + [qr'^(inkjetplanet|marketopt|MakeMoney)\d*@'i => 5.0], + ), + +# read_hash("/var/amavis/sender_scores_sitewide"), + +# This are some examples for whitelists, since envelope senders can be forged +# they are not enabled by default. + { # a hash-type lookup table (associative array) + #'nobody@cert.org' => -3.0, + #'cert-advisory@us-cert.gov' => -3.0, + #'owner-alert@iss.net' => -3.0, + #'slashdot@slashdot.org' => -3.0, + #'securityfocus.com' => -3.0, + #'ntbugtraq@listserv.ntbugtraq.com' => -3.0, + #'security-alerts@linuxsecurity.com' => -3.0, + #'mailman-announce-admin@python.org' => -3.0, + #'amavis-user-admin@lists.sourceforge.net'=> -3.0, + #'amavis-user-bounces@lists.sourceforge.net' => -3.0, + #'spamassassin.apache.org' => -3.0, + #'notification-return@lists.sophos.com' => -3.0, + #'owner-postfix-users@postfix.org' => -3.0, + #'owner-postfix-announce@postfix.org' => -3.0, + #'owner-sendmail-announce@lists.sendmail.org' => -3.0, + #'sendmail-announce-request@lists.sendmail.org' => -3.0, + #'donotreply@sendmail.org' => -3.0, + #'ca+envelope@sendmail.org' => -3.0, + #'noreply@freshmeat.net' => -3.0, + #'owner-technews@postel.acm.org' => -3.0, + #'ietf-123-owner@loki.ietf.org' => -3.0, + #'cvs-commits-list-admin@gnome.org' => -3.0, + #'rt-users-admin@lists.fsck.com' => -3.0, + #'clp-request@comp.nus.edu.sg' => -3.0, + #'surveys-errors@lists.nua.ie' => -3.0, + #'emailnews@genomeweb.com' => -5.0, + #'yahoo-dev-null@yahoo-inc.com' => -3.0, + #'returns.groups.yahoo.com' => -3.0, + #'clusternews@linuxnetworx.com' => -3.0, + #lc('lvs-users-admin@LinuxVirtualServer.org') => -3.0, + #lc('owner-textbreakingnews@CNNIMAIL12.CNN.COM') => -5.0, + + # soft-blacklisting (positive score) + #'sender@example.net' => 3.0, + #'.example.net' => 1.0, + + }, + ], # end of site-wide tables +}); + +1; # ensure a defined return diff --git a/data/templates/amavis/50-user.sed b/data/templates/amavis/50-user.sed new file mode 100644 index 00000000..b0e7ce14 --- /dev/null +++ b/data/templates/amavis/50-user.sed @@ -0,0 +1,30 @@ +use strict; + +# +# Place your configuration directives here. They will override those in +# earlier files. +# +# See /usr/share/doc/amavisd-new/ for documentation and examples of +# the directives you can use in this file +# + +$myhostname = "{{ main_domain }}"; + +$mydomain = "{{ main_domain }}"; + +# Enable LDAP support +$enable_ldap = 1; + +# Default LDAP settings +$default_ldap = { + hostname => "127.0.0.1", + tls => 0, + version => 3, + base => "dc=yunohost,dc=org", + scope => "sub", + query_filter => "(&(objectClass=inetOrgPerson)(mail=%m))", +}; + + +#------------ Do not modify anything below this line ------------- +1; # ensure a defined return diff --git a/data/templates/avahi-daemon/avahi-daemon.conf b/data/templates/avahi-daemon/avahi-daemon.conf new file mode 100644 index 00000000..d3542a41 --- /dev/null +++ b/data/templates/avahi-daemon/avahi-daemon.conf @@ -0,0 +1,68 @@ +# This file is part of avahi. +# +# avahi is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# avahi 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 General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with avahi; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +# See avahi-daemon.conf(5) for more information on this configuration +# file! + +[server] +host-name=yunohost +domain-name=local +#browse-domains=0pointer.de, zeroconf.org +use-ipv4=yes +use-ipv6=yes +#allow-interfaces=eth0 +#deny-interfaces=eth1 +#check-response-ttl=no +#use-iff-running=no +#enable-dbus=yes +#disallow-other-stacks=no +#allow-point-to-point=no +#cache-entries-max=4096 +#clients-max=4096 +#objects-per-client-max=1024 +#entries-per-entry-group-max=32 +ratelimit-interval-usec=1000000 +ratelimit-burst=1000 + +[wide-area] +enable-wide-area=yes + +[publish] +#disable-publishing=no +#disable-user-service-publishing=no +#add-service-cookie=no +#publish-addresses=yes +#publish-hinfo=yes +#publish-workstation=yes +#publish-domain=yes +#publish-dns-servers=192.168.50.1, 192.168.50.2 +#publish-resolv-conf-dns-servers=yes +#publish-aaaa-on-ipv4=yes +#publish-a-on-ipv6=no + +[reflector] +#enable-reflector=no +#reflect-ipv=no + +[rlimits] +#rlimit-as= +rlimit-core=0 +rlimit-data=4194304 +rlimit-fsize=0 +rlimit-nofile=768 +rlimit-stack=4194304 +rlimit-nproc=3 diff --git a/data/templates/dnsmasq/domain.sed b/data/templates/dnsmasq/domain.sed new file mode 100644 index 00000000..9966d1fd --- /dev/null +++ b/data/templates/dnsmasq/domain.sed @@ -0,0 +1,7 @@ +resolv-file= +address=/{{ domain }}/{{ ip }} +txt-record={{ domain }},"v=spf1 mx a -all" +mx-host={{ domain }},{{ domain }},5 +srv-host=_xmpp-client._tcp.{{ domain }},{{ domain }},5222,0,5 +srv-host=_xmpp-server._tcp.{{ domain }},{{ domain }},5269,0,5 +srv-host=_jabber._tcp.{{ domain }},{{ domain }},5269,0,5 diff --git a/data/templates/dovecot/dovecot-ldap.conf b/data/templates/dovecot/dovecot-ldap.conf new file mode 100644 index 00000000..221fe85c --- /dev/null +++ b/data/templates/dovecot/dovecot-ldap.conf @@ -0,0 +1,9 @@ +hosts = 127.0.0.1 +auth_bind = yes +ldap_version = 3 +base = ou=users,dc=yunohost,dc=org +user_attrs = uidNumber=500,gidNumber=8,mailuserquota=quota_rule=*:bytes=%$ +user_filter = (&(objectClass=inetOrgPerson)(uid=%n)) +pass_filter = (&(objectClass=inetOrgPerson)(uid=%n)) +default_pass_scheme = SSHA + diff --git a/data/templates/dovecot/dovecot.conf.sed b/data/templates/dovecot/dovecot.conf.sed new file mode 100644 index 00000000..6a507007 --- /dev/null +++ b/data/templates/dovecot/dovecot.conf.sed @@ -0,0 +1,92 @@ +# 2.1.7: /etc/dovecot/dovecot.conf +# OS: Linux 3.2.0-3-686-pae i686 Debian wheezy/sid ext4 +listen = *, :: +auth_mechanisms = plain login +login_greeting = Dovecot ready!! +mail_gid = 8 +mail_home = /var/mail/%n +mail_location = maildir:/var/mail/%n +mail_uid = 500 +passdb { + args = /etc/dovecot/dovecot-ldap.conf + driver = ldap +} +protocols = imap sieve +mail_plugins = $mail_plugins quota +service auth { + unix_listener /var/spool/postfix/private/auth { + group = postfix + mode = 0660 + user = postfix + } + unix_listener auth-master { + group = mail + mode = 0660 + user = vmail + } +} + +protocol sieve { +} + +ssl_ca = > /tmp/sa-learn-pipe.log ; +#echo $* > /tmp/sendmail-parms.txt ; +cat<&0 >> /tmp/sendmail-msg-$$.txt ; +/usr/bin/sa-learn $* /tmp/sendmail-msg-$$.txt ; +rm -f /tmp/sendmail-msg-$$.txt ; +echo "$$-end" >> /tmp/sa-learn-pipe.log ; +exit 0; diff --git a/data/templates/fail2ban/jail-jessie.conf b/data/templates/fail2ban/jail-jessie.conf new file mode 100644 index 00000000..59dcf51d --- /dev/null +++ b/data/templates/fail2ban/jail-jessie.conf @@ -0,0 +1,584 @@ +# Fail2Ban configuration file. +# +# This file was composed for Debian systems from the original one +# provided now under /usr/share/doc/fail2ban/examples/jail.conf +# for additional examples. +# +# Comments: use '#' for comment lines and ';' for inline comments +# +# To avoid merges during upgrades DO NOT MODIFY THIS FILE +# and rather provide your changes in /etc/fail2ban/jail.local +# + +# The DEFAULT allows a global definition of the options. They can be overridden +# in each jail afterwards. + +[DEFAULT] + +# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not +# ban a host which matches an address in this list. Several addresses can be +# defined using space separator. +ignoreip = 127.0.0.1/8 + +# External command that will take an tagged arguments to ignore, e.g. , +# and return true if the IP is to be ignored. False otherwise. +# +# ignorecommand = /path/to/command +ignorecommand = + +# "bantime" is the number of seconds that a host is banned. +bantime = 600 + +# A host is banned if it has generated "maxretry" during the last "findtime" +# seconds. +findtime = 600 +maxretry = 3 + +# "backend" specifies the backend used to get files modification. +# Available options are "pyinotify", "gamin", "polling" and "auto". +# This option can be overridden in each jail as well. +# +# pyinotify: requires pyinotify (a file alteration monitor) to be installed. +# If pyinotify is not installed, Fail2ban will use auto. +# gamin: requires Gamin (a file alteration monitor) to be installed. +# If Gamin is not installed, Fail2ban will use auto. +# polling: uses a polling algorithm which does not require external libraries. +# auto: will try to use the following backends, in order: +# pyinotify, gamin, polling. +backend = auto + +# "usedns" specifies if jails should trust hostnames in logs, +# warn when reverse DNS lookups are performed, or ignore all hostnames in logs +# +# yes: if a hostname is encountered, a reverse DNS lookup will be performed. +# warn: if a hostname is encountered, a reverse DNS lookup will be performed, +# but it will be logged as a warning. +# no: if a hostname is encountered, will not be used for banning, +# but it will be logged as info. +usedns = warn + +# +# Destination email address used solely for the interpolations in +# jail.{conf,local} configuration files. +destemail = root@localhost + +# +# Name of the sender for mta actions +sendername = Fail2Ban + +# Email address of the sender +sender = fail2ban@localhost + +# +# ACTIONS +# + +# Default banning action (e.g. iptables, iptables-new, +# iptables-multiport, shorewall, etc) It is used to define +# action_* variables. Can be overridden globally or per +# section within jail.local file +banaction = iptables-multiport + +# email action. Since 0.8.1 upstream fail2ban uses sendmail +# MTA for the mailing. Change mta configuration parameter to mail +# if you want to revert to conventional 'mail'. +mta = sendmail + +# Default protocol +protocol = tcp + +# Specify chain where jumps would need to be added in iptables-* actions +chain = INPUT + +# +# Action shortcuts. To be used to define action parameter + +# The simplest action to take: ban only +action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + +# ban & send an e-mail with whois report to the destemail. +action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s", sendername="%(sendername)s"] + +# ban & send an e-mail with whois report and relevant log lines +# to the destemail. +action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s", sendername="%(sendername)s"] + +# Choose default action. To change, just override value of 'action' with the +# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local +# globally (section [DEFAULT]) or per specific section +action = %(action_)s + +# +# JAILS +# + +# Next jails corresponds to the standard configuration in Fail2ban 0.6 which +# was shipped in Debian. Enable any defined here jail by including +# +# [SECTION_NAME] +# enabled = true + +# +# in /etc/fail2ban/jail.local. +# +# Optionally you may override any other parameter (e.g. banaction, +# action, port, logpath, etc) in that section within jail.local + +[ssh] + +enabled = true +port = ssh +filter = sshd +logpath = /var/log/auth.log +maxretry = 6 + +[dropbear] + +enabled = false +port = ssh +filter = dropbear +logpath = /var/log/auth.log +maxretry = 6 + +# Generic filter for pam. Has to be used with action which bans all ports +# such as iptables-allports, shorewall +[pam-generic] + +enabled = true +# pam-generic filter can be customized to monitor specific subset of 'tty's +filter = pam-generic +# port actually must be irrelevant but lets leave it all for some possible uses +port = all +banaction = iptables-allports +port = anyport +logpath = /var/log/auth.log +maxretry = 6 + +[xinetd-fail] + +enabled = false +filter = xinetd-fail +port = all +banaction = iptables-multiport-log +logpath = /var/log/daemon.log +maxretry = 2 + + +[ssh-ddos] + +enabled = false +port = ssh +filter = sshd-ddos +logpath = /var/log/auth.log +maxretry = 6 + + +# Here we use blackhole routes for not requiring any additional kernel support +# to store large volumes of banned IPs + +[ssh-route] + +enabled = false +filter = sshd +action = route +logpath = /var/log/sshd.log +maxretry = 6 + +# Here we use a combination of Netfilter/Iptables and IPsets +# for storing large volumes of banned IPs +# +# IPset comes in two versions. See ipset -V for which one to use +# requires the ipset package and kernel support. +[ssh-iptables-ipset4] + +enabled = false +port = ssh +filter = sshd +banaction = iptables-ipset-proto4 +logpath = /var/log/sshd.log +maxretry = 6 + +[ssh-iptables-ipset6] + +enabled = false +port = ssh +filter = sshd +banaction = iptables-ipset-proto6 +logpath = /var/log/sshd.log +maxretry = 6 + + +# +# HTTP servers +# + +[apache] + +enabled = false +port = http,https +filter = apache-auth +logpath = /var/log/apache*/*error.log +maxretry = 6 + +# default action is now multiport, so apache-multiport jail was left +# for compatibility with previous (<0.7.6-2) releases +[apache-multiport] + +enabled = false +port = http,https +filter = apache-auth +logpath = /var/log/apache*/*error.log +maxretry = 6 + +[apache-noscript] + +enabled = false +port = http,https +filter = apache-noscript +logpath = /var/log/apache*/*error.log +maxretry = 6 + +[apache-overflows] + +enabled = false +port = http,https +filter = apache-overflows +logpath = /var/log/apache*/*error.log +maxretry = 2 + +[apache-modsecurity] + +enabled = false +filter = apache-modsecurity +port = http,https +logpath = /var/log/apache*/*error.log +maxretry = 2 + +[apache-nohome] + +enabled = false +filter = apache-nohome +port = http,https +logpath = /var/log/apache*/*error.log +maxretry = 2 + +# Ban attackers that try to use PHP's URL-fopen() functionality +# through GET/POST variables. - Experimental, with more than a year +# of usage in production environments. + +[php-url-fopen] + +enabled = false +port = http,https +filter = php-url-fopen +logpath = /var/www/*/logs/access_log + +# A simple PHP-fastcgi jail which works with lighttpd. +# If you run a lighttpd server, then you probably will +# find these kinds of messages in your error_log: +# ALERT – tried to register forbidden variable ‘GLOBALS’ +# through GET variables (attacker '1.2.3.4', file '/var/www/default/htdocs/index.php') + +[lighttpd-fastcgi] + +enabled = false +port = http,https +filter = lighttpd-fastcgi +logpath = /var/log/lighttpd/error.log + +# Same as above for mod_auth +# It catches wrong authentifications + +[lighttpd-auth] + +enabled = false +port = http,https +filter = suhosin +logpath = /var/log/lighttpd/error.log + +[nginx-http-auth] + +enabled = false +filter = nginx-http-auth +port = http,https +logpath = /var/log/nginx/error.log + +# Monitor roundcube server + +[roundcube-auth] + +enabled = false +filter = roundcube-auth +port = http,https +logpath = /var/log/roundcube/userlogins + + +[sogo-auth] + +enabled = false +filter = sogo-auth +port = http, https +# without proxy this would be: +# port = 20000 +logpath = /var/log/sogo/sogo.log + + +# +# FTP servers +# + +[vsftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = vsftpd +logpath = /var/log/vsftpd.log +# or overwrite it in jails.local to be +# logpath = /var/log/auth.log +# if you want to rely on PAM failed login attempts +# vsftpd's failregex should match both of those formats +maxretry = 6 + + +[proftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = proftpd +logpath = /var/log/proftpd/proftpd.log +maxretry = 6 + + +[pure-ftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = pure-ftpd +logpath = /var/log/syslog +maxretry = 6 + + +[wuftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = wuftpd +logpath = /var/log/syslog +maxretry = 6 + + +# +# Mail servers +# + +[postfix] + +enabled = true +port = smtp,ssmtp,submission +filter = postfix +logpath = /var/log/mail.log + + +[couriersmtp] + +enabled = false +port = smtp,ssmtp,submission +filter = couriersmtp +logpath = /var/log/mail.log + + +# +# Mail servers authenticators: might be used for smtp,ftp,imap servers, so +# all relevant ports get banned +# + +[courierauth] + +enabled = false +port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s +filter = courierlogin +logpath = /var/log/mail.log + + +[sasl] + +enabled = true +port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s +filter = postfix-sasl +# You might consider monitoring /var/log/mail.warn instead if you are +# running postfix since it would provide the same log lines at the +# "warn" level but overall at the smaller filesize. +logpath = /var/log/mail.log + +[dovecot] + +enabled = true +port = smtp,ssmtp,submission,imap2,imap3,imaps,pop3,pop3s +filter = dovecot +logpath = /var/log/mail.log + +# To log wrong MySQL access attempts add to /etc/my.cnf: +# log-error=/var/log/mysqld.log +# log-warning = 2 +[mysqld-auth] + +enabled = false +filter = mysqld-auth +port = 3306 +logpath = /var/log/mysqld.log + + +# DNS Servers + + +# These jails block attacks against named (bind9). By default, logging is off +# with bind9 installation. You will need something like this: +# +# logging { +# channel security_file { +# file "/var/log/named/security.log" versions 3 size 30m; +# severity dynamic; +# print-time yes; +# }; +# category security { +# security_file; +# }; +# }; +# +# in your named.conf to provide proper logging + +# !!! WARNING !!! +# Since UDP is connection-less protocol, spoofing of IP and imitation +# of illegal actions is way too simple. Thus enabling of this filter +# might provide an easy way for implementing a DoS against a chosen +# victim. See +# http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html +# Please DO NOT USE this jail unless you know what you are doing. +#[named-refused-udp] +# +#enabled = false +#port = domain,953 +#protocol = udp +#filter = named-refused +#logpath = /var/log/named/security.log + +[named-refused-tcp] + +enabled = false +port = domain,953 +protocol = tcp +filter = named-refused +logpath = /var/log/named/security.log + +[freeswitch] + +enabled = false +filter = freeswitch +logpath = /var/log/freeswitch.log +maxretry = 10 +action = iptables-multiport[name=freeswitch-tcp, port="5060,5061,5080,5081", protocol=tcp] + iptables-multiport[name=freeswitch-udp, port="5060,5061,5080,5081", protocol=udp] + +[ejabberd-auth] + +enabled = false +filter = ejabberd-auth +port = xmpp-client +protocol = tcp +logpath = /var/log/ejabberd/ejabberd.log + + +# Multiple jails, 1 per protocol, are necessary ATM: +# see https://github.com/fail2ban/fail2ban/issues/37 +[asterisk-tcp] + +enabled = false +filter = asterisk +port = 5060,5061 +protocol = tcp +logpath = /var/log/asterisk/messages + +[asterisk-udp] + +enabled = false +filter = asterisk +port = 5060,5061 +protocol = udp +logpath = /var/log/asterisk/messages + + +# Jail for more extended banning of persistent abusers +# !!! WARNING !!! +# Make sure that your loglevel specified in fail2ban.conf/.local +# is not at DEBUG level -- which might then cause fail2ban to fall into +# an infinite loop constantly feeding itself with non-informative lines +[recidive] + +enabled = false +filter = recidive +logpath = /var/log/fail2ban.log +action = iptables-allports[name=recidive] + sendmail-whois-lines[name=recidive, logpath=/var/log/fail2ban.log] +bantime = 604800 ; 1 week +findtime = 86400 ; 1 day +maxretry = 5 + +# See the IMPORTANT note in action.d/blocklist_de.conf for when to +# use this action +# +# Report block via blocklist.de fail2ban reporting service API +# See action.d/blocklist_de.conf for more information +[ssh-blocklist] + +enabled = false +filter = sshd +action = iptables[name=SSH, port=ssh, protocol=tcp] + sendmail-whois[name=SSH, dest="%(destemail)s", sender="%(sender)s", sendername="%(sendername)s"] + blocklist_de[email="%(sender)s", apikey="xxxxxx", service="%(filter)s"] +logpath = /var/log/sshd.log +maxretry = 20 + + +# consider low maxretry and a long bantime +# nobody except your own Nagios server should ever probe nrpe +[nagios] +enabled = false +filter = nagios +action = iptables[name=Nagios, port=5666, protocol=tcp] + sendmail-whois[name=Nagios, dest="%(destemail)s", sender="%(sender)s", sendername="%(sendername)s"] +logpath = /var/log/messages ; nrpe.cfg may define a different log_facility +maxretry = 1 + +[nginx] + +enabled = true +port = http,https +filter = apache-auth +logpath = /var/log/nginx*/*error.log +maxretry = 6 + +[nginx-noscript] + +enabled = false +port = http,https +filter = apache-noscript +logpath = /var/log/nginx*/*error.log +maxretry = 6 + +[nginx-overflows] + +enabled = false +port = http,https +filter = apache-overflows +logpath = /var/log/nginx*/*error.log +maxretry = 4 + +[yunohost] + +enabled = true +port = http,https +protocol = tcp +filter = yunohost +logpath = /var/log/nginx/*.log diff --git a/data/templates/fail2ban/jail-wheezy.conf b/data/templates/fail2ban/jail-wheezy.conf new file mode 100644 index 00000000..8eb0e7a1 --- /dev/null +++ b/data/templates/fail2ban/jail-wheezy.conf @@ -0,0 +1,346 @@ +# Fail2Ban configuration file. +# +# This file was composed for Debian systems from the original one +# provided now under /usr/share/doc/fail2ban/examples/jail.conf +# for additional examples. +# +# To avoid merges during upgrades DO NOT MODIFY THIS FILE +# and rather provide your changes in /etc/fail2ban/jail.local +# +# Author: Yaroslav O. Halchenko +# +# $Revision$ +# + +# The DEFAULT allows a global definition of the options. They can be overridden +# in each jail afterwards. + +[DEFAULT] + +# "ignoreip" can be an IP address, a CIDR mask or a DNS host +ignoreip = 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 +bantime = 600 +maxretry = 3 + +# "backend" specifies the backend used to get files modification. Available +# options are "gamin", "polling" and "auto". +# yoh: For some reason Debian shipped python-gamin didn't work as expected +# This issue left ToDo, so polling is default backend for now +backend = auto + +# +# Destination email address used solely for the interpolations in +# jail.{conf,local} configuration files. +destemail = root@localhost + +# +# ACTIONS +# + +# Default banning action (e.g. iptables, iptables-new, +# iptables-multiport, shorewall, etc) It is used to define +# action_* variables. Can be overridden globally or per +# section within jail.local file +banaction = iptables-multiport + +# email action. Since 0.8.1 upstream fail2ban uses sendmail +# MTA for the mailing. Change mta configuration parameter to mail +# if you want to revert to conventional 'mail'. +mta = sendmail + +# Default protocol +protocol = tcp + +# Specify chain where jumps would need to be added in iptables-* actions +chain = INPUT + +# +# Action shortcuts. To be used to define action parameter + +# The simplest action to take: ban only +action_ = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + +# ban & send an e-mail with whois report to the destemail. +action_mw = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois[name=%(__name__)s, dest="%(destemail)s", protocol="%(protocol)s", chain="%(chain)s"] + +# ban & send an e-mail with whois report and relevant log lines +# to the destemail. +action_mwl = %(banaction)s[name=%(__name__)s, port="%(port)s", protocol="%(protocol)s", chain="%(chain)s"] + %(mta)s-whois-lines[name=%(__name__)s, dest="%(destemail)s", logpath=%(logpath)s, chain="%(chain)s"] + +# Choose default action. To change, just override value of 'action' with the +# interpolation to the chosen action shortcut (e.g. action_mw, action_mwl, etc) in jail.local +# globally (section [DEFAULT]) or per specific section +action = %(action_)s + +# +# JAILS +# + +# Next jails corresponds to the standard configuration in Fail2ban 0.6 which +# was shipped in Debian. Enable any defined here jail by including +# +# [SECTION_NAME] +# enabled = true + +# +# in /etc/fail2ban/jail.local. +# +# Optionally you may override any other parameter (e.g. banaction, +# action, port, logpath, etc) in that section within jail.local + +[ssh] + +enabled = true +port = ssh +filter = sshd +logpath = /var/log/auth.log +maxretry = 6 + +[dropbear] + +enabled = false +port = ssh +filter = sshd +logpath = /var/log/dropbear +maxretry = 6 + +# Generic filter for pam. Has to be used with action which bans all ports +# such as iptables-allports, shorewall +[pam-generic] + +enabled = false +# pam-generic filter can be customized to monitor specific subset of 'tty's +filter = pam-generic +# port actually must be irrelevant but lets leave it all for some possible uses +port = all +banaction = iptables-allports +port = anyport +logpath = /var/log/auth.log +maxretry = 6 + +[xinetd-fail] + +enabled = false +filter = xinetd-fail +port = all +banaction = iptables-multiport-log +logpath = /var/log/daemon.log +maxretry = 2 + + +[ssh-ddos] + +enabled = false +port = ssh +filter = sshd-ddos +logpath = /var/log/auth.log +maxretry = 6 + +# +# HTTP servers +# + +[apache] + +enabled = false +port = http,https +filter = apache-auth +logpath = /var/log/apache*/*error.log +maxretry = 6 + +# default action is now multiport, so apache-multiport jail was left +# for compatibility with previous (<0.7.6-2) releases +[apache-multiport] + +enabled = false +port = http,https +filter = apache-auth +logpath = /var/log/apache*/*error.log +maxretry = 6 + +[apache-noscript] + +enabled = false +port = http,https +filter = apache-noscript +logpath = /var/log/apache*/*error.log +maxretry = 6 + +[apache-overflows] + +enabled = false +port = http,https +filter = apache-overflows +logpath = /var/log/apache*/*error.log +maxretry = 2 + +# +# FTP servers +# + +[vsftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = vsftpd +logpath = /var/log/vsftpd.log +# or overwrite it in jails.local to be +# logpath = /var/log/auth.log +# if you want to rely on PAM failed login attempts +# vsftpd's failregex should match both of those formats +maxretry = 6 + + +[proftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = proftpd +logpath = /var/log/proftpd/proftpd.log +maxretry = 6 + + +[pure-ftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = pure-ftpd +logpath = /var/log/auth.log +maxretry = 6 + + +[wuftpd] + +enabled = false +port = ftp,ftp-data,ftps,ftps-data +filter = wuftpd +logpath = /var/log/auth.log +maxretry = 6 + + +# +# Mail servers +# + +[postfix] + +enabled = true +port = smtp,ssmtp +filter = postfix +logpath = /var/log/mail.log + +[couriersmtp] + +enabled = false +port = smtp,ssmtp +filter = couriersmtp +logpath = /var/log/mail.log + + +# +# Mail servers authenticators: might be used for smtp,ftp,imap servers, so +# all relevant ports get banned +# + +[courierauth] + +enabled = false +port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s +filter = courierlogin +logpath = /var/log/mail.log + + +[sasl] + +enabled = true +port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s +filter = sasl +# You might consider monitoring /var/log/mail.warn instead if you are +# running postfix since it would provide the same log lines at the +# "warn" level but overall at the smaller filesize. +logpath = /var/log/mail.log + +[dovecot] + +enabled = true +port = smtp,ssmtp,imap2,imap3,imaps,pop3,pop3s +filter = dovecot +logpath = /var/log/mail.log + + +# DNS Servers + + +# These jails block attacks against named (bind9). By default, logging is off +# with bind9 installation. You will need something like this: +# +# logging { +# channel security_file { +# file "/var/log/named/security.log" versions 3 size 30m; +# severity dynamic; +# print-time yes; +# }; +# category security { +# security_file; +# }; +# }; +# +# in your named.conf to provide proper logging + +# !!! WARNING !!! +# Since UDP is connection-less protocol, spoofing of IP and imitation +# of illegal actions is way too simple. Thus enabling of this filter +# might provide an easy way for implementing a DoS against a chosen +# victim. See +# http://nion.modprobe.de/blog/archives/690-fail2ban-+-dns-fail.html +# Please DO NOT USE this jail unless you know what you are doing. +#[named-refused-udp] +# +#enabled = false +#port = domain,953 +#protocol = udp +#filter = named-refused +#logpath = /var/log/named/security.log + +[named-refused-tcp] + +enabled = false +port = domain,953 +protocol = tcp +filter = named-refused +logpath = /var/log/named/security.log + +[nginx] + +enabled = true +port = http,https +filter = apache-auth +logpath = /var/log/nginx*/*error.log +maxretry = 6 + +[nginx-noscript] + +enabled = false +port = http,https +filter = apache-noscript +logpath = /var/log/nginx*/*error.log +maxretry = 6 + +[nginx-overflows] + +enabled = false +port = http,https +filter = apache-overflows +logpath = /var/log/nginx*/*error.log +maxretry = 4 + +[yunohost] + +enabled = true +port = http,https +protocol = tcp +filter = yunohost +logpath = /var/log/nginx/*.log +maxretry = 6 diff --git a/data/templates/fail2ban/yunohost.conf b/data/templates/fail2ban/yunohost.conf new file mode 100644 index 00000000..54d4a779 --- /dev/null +++ b/data/templates/fail2ban/yunohost.conf @@ -0,0 +1,24 @@ +# Fail2Ban configuration file +# +# Author: Adrien Beudin +# +# $Revision: 2 $ +# + +[Definition] + +# Option: failregex +# Notes.: regex to match the password failure messages in the logfile. The +# host must be matched by a group named "host". The tag "" can +# be used for standard IP/hostname matching and is only an alias for +# (?:::f{4,6}:)?(?P[\w\-.^_]+) +# Values: TEXT +# +failregex = access.lua:[1-9]+: authenticate\(\): Connection failed for: .*, client: + ^ -.*\"POST /yunohost/api/login HTTP/1.1\" 401 22 + +# Option: ignoreregex +# Notes.: regex to ignore. If this regex matches, the line is ignored. +# Values: TEXT +# +ignoreregex = diff --git a/data/templates/glances/glances.default b/data/templates/glances/glances.default new file mode 100644 index 00000000..22337a0d --- /dev/null +++ b/data/templates/glances/glances.default @@ -0,0 +1,5 @@ +# Default is to launch glances with '-s' option. +DAEMON_ARGS="-s -B 127.0.0.1" + +# Change to 'true' to have glances running at startup +RUN="true" diff --git a/data/templates/metronome/domain.cfg.lua.sed b/data/templates/metronome/domain.cfg.lua.sed new file mode 100644 index 00000000..2c7fd748 --- /dev/null +++ b/data/templates/metronome/domain.cfg.lua.sed @@ -0,0 +1,15 @@ +VirtualHost "{{ domain }}" + ssl = { + key = "/etc/yunohost/certs/{{ domain }}/key.pem"; + certificate = "/etc/yunohost/certs/{{ domain }}/crt.pem"; + } + authentication = "ldap2" + ldap = { + hostname = "localhost", + user = { + basedn = "ou=users,dc=yunohost,dc=org", + filter = "(&(objectClass=posixAccount)(mail=*@{{ domain }}))", + usernamefield = "mail", + namefield = "cn", + }, + } diff --git a/data/templates/metronome/metronome.cfg.lua.sed b/data/templates/metronome/metronome.cfg.lua.sed new file mode 100644 index 00000000..9fce19a8 --- /dev/null +++ b/data/templates/metronome/metronome.cfg.lua.sed @@ -0,0 +1,193 @@ +-- ** Metronome's config file example ** +-- +-- The format is exactly equal to Prosody's: +-- +-- Lists are written { "like", "this", "one" } +-- Lists can also be of { 1, 2, 3 } numbers, etc. +-- Either commas, or semi-colons; may be used as seperators. +-- +-- A table is a list of values, except each value has a name. An +-- example would be: +-- +-- ssl = { key = "keyfile.key", certificate = "certificate.crt" } +-- +-- Tip: You can check that the syntax of this file is correct when you have finished +-- by running: luac -p metronome.cfg.lua +-- If there are any errors, it will let you know what and where they are, otherwise it +-- will keep quiet. + +---------- Server-wide settings ---------- +-- Settings in this section apply to the whole server and are the default settings +-- for any virtual hosts + +-- Server PID +pidfile = "/var/run/metronome/metronome.pid" + +-- HTTP server +http_ports = { 5290 } +http_interfaces = { "127.0.0.1", "::1" } + +--https_ports = { 5291 } +--https_interfaces = { "127.0.0.1", "::1" } + +-- Enable IPv6 +use_ipv6 = true + +-- This is the list of modules Metronome will load on startup. +-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too. +modules_enabled = { + + -- Generally required + "roster"; -- Allow users to have a roster. Recommended ;) + "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in. + "tls"; -- Add support for secure TLS on c2s/s2s connections + "dialback"; -- s2s dialback support + "disco"; -- Service discovery + --"discoitems"; -- Service discovery items + --"extdisco"; -- External Service Discovery + + -- Not essential, but recommended + "private"; -- Private XML storage (for room bookmarks, etc.) + "vcard"; -- Allow users to set vCards + "privacy"; -- Support privacy lists + + -- These are commented by default as they have a performance impact + --"compression"; -- Stream compression (Debian: requires lua-zlib module to work) + + -- Nice to have + "version"; -- Replies to server version requests + "uptime"; -- Report how long server has been running + "time"; -- Let others know the time here on this server + "ping"; -- Replies to XMPP pings with pongs + "pep"; -- Enables users to publish their mood, activity, playing music and more + "message_carbons"; -- Allow clients to keep in sync with messages send on other resources + "register"; -- Allow users to register on this server using a client and change passwords + "adhoc"; -- Support for "ad-hoc commands" that can be executed with an XMPP client + + -- Admin interfaces + "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands + "admin_telnet"; -- Opens telnet console interface on localhost port 5582 + + -- HTTP modules + "bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" + --"websockets"; -- Enable WebSocket clients + --"http_files"; -- Serve static files from a directory over HTTP + + -- Other specific functionality +-- "bidi"; -- Bidirectional Streams for S2S connections +-- "stream_management"; -- Stream Management support + --"groups"; -- Shared roster support + --"announce"; -- Send announcement to all online users + --"welcome"; -- Welcome users who register accounts + --"watchregistrations"; -- Alert admins of registrations + --"motd"; -- Send a message to users when they log in + "mam"; -- Nice archive management + --"legacyauth"; -- Legacy authentication. Only used by some old clients and bots. + "offline"; -- Store offline messages + "c2s"; -- Handle client connections + "s2s"; -- Handle server-to-server connections + + -- Debian: do not remove this module, or you lose syslog + -- support + "posix"; -- POSIX functionality, sends server to background, enables syslog, etc. +}; + +-- Discovery items +disco_items = { + { "muc.{{ main_domain }}" }, + { "pubsub.{{ main_domain }}" }, + { "vjud.{{ main_domain }}" } +}; + +-- BOSH configuration (mod_bosh) +bosh_max_inactivity = 30 +consider_bosh_secure = true +cross_domain_bosh = true + +-- Disable account creation by default, for security +allow_registration = false + +-- SSL/TLS configuration +ssl = { + options = { + "no_sslv2", + "no_sslv3", + "no_ticket", + "no_compression", + "cipher_server_preference" + }; +} + +-- Force clients to use encrypted connections? This option will +-- prevent clients from authenticating unless they are using encryption. +c2s_require_encryption = true + +-- Force servers to use encrypted connections? This option will +-- prevent servers from connecting unless they are using encryption. +s2s_require_encryption = true + +-- Allow servers to use an unauthenticated encryption channel +s2s_allow_encryption = true + +allow_unencrypted_plain_auth = false; + +s2s_secure = true +s2s_secure_auth = false + +--anonymous_login = false + +-- Use LDAP storage backend for all stores +storage = "ldap" + +-- Logging configuration +log = { + info = "/var/log/metronome/metronome.log"; -- Change 'info' to 'debug' for verbose logging + error = "/var/log/metronome/metronome.err"; + -- "*syslog"; -- Uncomment this for logging to syslog + -- "*console"; -- Log to the console, useful for debugging with daemonize=false +} + + +------ Components ------ +-- You can specify components to add hosts that provide special services, +-- like multi-user conferences, and transports. + +---Set up a local BOSH service +Component "localhost" "http" + modules_enabled = { "bosh" } + +---Set up a MUC (multi-user chat) room server +Component "muc.{{ main_domain }}" "muc" + name = "YunoHost Chatrooms" + + modules_enabled = { + "muc_limits"; + "muc_log"; + "muc_log_http"; + } + + muc_event_rate = 0.5 + muc_burst_factor = 10 + + muc_log_http_config = { + url_base = "logs"; + theme = "metronome"; + } + +---Set up a PubSub server +Component "pubsub.{{ main_domain }}" "pubsub" + name = "YunoHost Publish/Subscribe" + + unrestricted_node_creation = true -- Anyone can create a PubSub node (from any server) + +---Set up a VJUD service +Component "vjud.{{ main_domain }}" "vjud" + ud_disco_name = "Jappix User Directory" + + +----------- Virtual hosts ----------- +-- You need to add a VirtualHost entry for each domain you wish Metronome to serve. +-- Settings under each VirtualHost entry apply *only* to that host. + +Include "conf.d/*.cfg.lua" + diff --git a/data/templates/metronome/metronome.init b/data/templates/metronome/metronome.init new file mode 100644 index 00000000..5f6f2ed4 --- /dev/null +++ b/data/templates/metronome/metronome.init @@ -0,0 +1,119 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: metronome +# Required-Start: $network $local_fs $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Metronome XMPP Server +### END INIT INFO + +set -e + +# /etc/init.d/metronome: start and stop Metronome XMPP server + +NAME=metronome +USER=metronome +DAEMON=/usr/bin/metronome +PIDPATH=/var/run/metronome +PIDFILE="$PIDPATH"/metronome.pid + +NICE= +MAXFDS= +CPUSCHED= +IOSCHED= + +test -x "$DAEMON" || exit 0 + +. /lib/lsb/init-functions + +if [ -f /etc/default/metronome ] ; then + . /etc/default/metronome +fi + +start_opts() { + test -z "$NICE" || echo -n " --nicelevel $NICE" + test -z "$CPUSCHED" || echo -n " --procsched $CPUSCHED" + test -z "$IOSCHED" || echo -n " --iosched $IOSCHED" +} + +start_metronome () { + mkdir -p `dirname $PIDFILE` + chown metronome:adm `dirname $PIDFILE` + if start-stop-daemon --start --quiet --pidfile "$PIDFILE" \ + --chuid "$USER" --oknodo --user "$USER" --name lua5.1 \ + $(start_opts) --startas "$DAEMON"; + then + return 0 + else + return 1 + fi +} + +stop_metronome () { + if start-stop-daemon --stop --quiet --retry 30 \ + --oknodo --pidfile "$PIDFILE" --user "$USER" --name lua5.1; + then + return 0 + else + return 1 + fi +} + +signal_metronome () { + if start-stop-daemon --stop --quiet --pidfile "$PIDFILE" \ + --user "$USER" --name lua5.1 --oknodo --signal $1; + then + return 0 + else + return 1 + fi +} + +case "$1" in + start) + log_daemon_msg "Starting Metronome XMPP Server" "metronome" + if start_metronome; then + log_end_msg 0; + else + log_end_msg 1; + fi + ;; + stop) + log_daemon_msg "Stopping Metronome XMPP Server" "metronome" + if stop_metronome; then + log_end_msg 0; + else + log_end_msg 1; + fi + ;; + force-reload|restart) + log_daemon_msg "Restarting Metronome XMPP Server" "metronome" + + stop_metronome + + if start_metronome; then + log_end_msg 0; + else + log_end_msg 1; + fi + ;; + reload) + log_daemon_msg "Reloading Metronome XMPP Server" "metronome" + + if signal_metronome 1; then + log_end_msg 0; + else + log_end_msg 1; + fi + ;; + status) + status_of_proc -p $PIDFILE $DAEMON $NAME + ;; + *) + log_action_msg "Usage: /etc/init.d/metronome {start|stop|restart|reload|status}" + exit 1 +esac + +exit 0 diff --git a/data/templates/metronome/metronome.logrotate b/data/templates/metronome/metronome.logrotate new file mode 100644 index 00000000..ccdc2feb --- /dev/null +++ b/data/templates/metronome/metronome.logrotate @@ -0,0 +1,11 @@ +/var/log/metronome/metronome.log /var/log/metronome/metronome.err { + daily + rotate 14 + compress + create 640 metronome adm + postrotate + /etc/init.d/metronome reload > /dev/null + endscript + sharedscripts + missingok +} diff --git a/data/templates/metronome/modules/ldap.lib.lua b/data/templates/metronome/modules/ldap.lib.lua new file mode 100644 index 00000000..6774e735 --- /dev/null +++ b/data/templates/metronome/modules/ldap.lib.lua @@ -0,0 +1,270 @@ +-- vim:sts=4 sw=4 + +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- Copyright (C) 2012 Rob Hoelz +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +local ldap; +local connection; +local params = module:get_option("ldap"); +local format = string.format; +local tconcat = table.concat; + +local _M = {}; + +local config_params = { + hostname = 'string', + user = { + basedn = 'string', + namefield = 'string', + filter = 'string', + usernamefield = 'string', + }, + groups = { + basedn = 'string', + namefield = 'string', + memberfield = 'string', + + _member = { + name = 'string', + admin = 'boolean?', + }, + }, + admin = { + _optional = true, + basedn = 'string', + namefield = 'string', + filter = 'string', + } +} + +local function run_validation(params, config, prefix) + prefix = prefix or ''; + + -- verify that every required member of config is present in params + for k, v in pairs(config) do + if type(k) == 'string' and k:sub(1, 1) ~= '_' then + local is_optional; + if type(v) == 'table' then + is_optional = v._optional; + else + is_optional = v:sub(-1) == '?'; + end + + if not is_optional and params[k] == nil then + return nil, prefix .. k .. ' is required'; + end + end + end + + for k, v in pairs(params) do + local expected_type = config[k]; + + local ok, err = true; + + if type(k) == 'string' then + -- verify that this key is present in config + if k:sub(1, 1) == '_' or expected_type == nil then + return nil, 'invalid parameter ' .. prefix .. k; + end + + -- type validation + if type(expected_type) == 'string' then + if expected_type:sub(-1) == '?' then + expected_type = expected_type:sub(1, -2); + end + + if type(v) ~= expected_type then + return nil, 'invalid type for parameter ' .. prefix .. k; + end + else -- it's a table (or had better be) + if type(v) ~= 'table' then + return nil, 'invalid type for parameter ' .. prefix .. k; + end + + -- recurse into child + ok, err = run_validation(v, expected_type, prefix .. k .. '.'); + end + else -- it's an integer (or had better be) + if not config._member then + return nil, 'invalid parameter ' .. prefix .. tostring(k); + end + ok, err = run_validation(v, config._member, prefix .. tostring(k) .. '.'); + end + + if not ok then + return ok, err; + end + end + + return true; +end + +local function validate_config() + if true then + return true; -- XXX for now + end + + -- this is almost too clever (I mean that in a bad + -- maintainability sort of way) + -- + -- basically this allows a free pass for a key in group members + -- equal to params.groups.namefield + setmetatable(config_params.groups._member, { + __index = function(_, k) + if k == params.groups.namefield then + return 'string'; + end + end + }); + + local ok, err = run_validation(params, config_params); + + setmetatable(config_params.groups._member, nil); + + if ok then + -- a little extra validation that doesn't fit into + -- my recursive checker + local group_namefield = params.groups.namefield; + for i, group in ipairs(params.groups) do + if not group[group_namefield] then + return nil, format('groups.%d.%s is required', i, group_namefield); + end + end + + -- fill in params.admin if you can + if not params.admin and params.groups then + local admingroup; + + for _, groupconfig in ipairs(params.groups) do + if groupconfig.admin then + admingroup = groupconfig; + break; + end + end + + if admingroup then + params.admin = { + basedn = params.groups.basedn, + namefield = params.groups.memberfield, + filter = group_namefield .. '=' .. admingroup[group_namefield], + }; + end + end + end + + return ok, err; +end + +-- what to do if connection isn't available? +local function connect() + return ldap.open_simple(params.hostname, params.bind_dn, params.bind_password, params.use_tls); +end + +-- this is abstracted so we can maintain persistent connections at a later time +function _M.getconnection() + return connect(); +end + +function _M.getparams() + return params; +end + +-- XXX consider renaming this...it doesn't bind the current connection +function _M.bind(username, password) + local conn = _M.getconnection(); + local filter = format('%s=%s', params.user.usernamefield, username); + if params.user.usernamefield == 'mail' then + filter = format('mail=%s@*', username); + end + + if filter then + filter = _M.filter.combine_and(filter, params.user.filter); + end + + local who = _M.singlematch { + attrs = params.user.usernamefield, + base = params.user.basedn, + filter = filter, + }; + + if who then + who = who.dn; + module:log('debug', '_M.bind - who: %s', who); + else + module:log('debug', '_M.bind - no DN found for username = %s', username); + return nil, format('no DN found for username = %s', username); + end + + local conn, err = ldap.open_simple(params.hostname, who, password, params.use_tls); + + if conn then + conn:close(); + return true; + end + + return conn, err; +end + +function _M.singlematch(query) + local ld = _M.getconnection(); + + query.sizelimit = 1; + query.scope = 'subtree'; + + for dn, attribs in ld:search(query) do + attribs.dn = dn; + return attribs; + end +end + +_M.filter = {}; + +function _M.filter.combine_and(...) + local parts = { '(&' }; + + local arg = { ... }; + + for _, filter in ipairs(arg) do + if filter:sub(1, 1) ~= '(' and filter:sub(-1) ~= ')' then + filter = '(' .. filter .. ')' + end + parts[#parts + 1] = filter; + end + + parts[#parts + 1] = ')'; + + return tconcat(parts, ''); +end + +do + local ok, err; + + metronome.unlock_globals(); + ok, ldap = pcall(require, 'lualdap'); + metronome.lock_globals(); + if not ok then + module:log("error", "Failed to load the LuaLDAP library for accessing LDAP: %s", ldap); + module:log("error", "More information on install LuaLDAP can be found at http://www.keplerproject.org/lualdap"); + return; + end + + if not params then + module:log("error", "LDAP configuration required to use the LDAP storage module"); + return; + end + + ok, err = validate_config(); + + if not ok then + module:log("error", "LDAP configuration is invalid: %s", tostring(err)); + return; + end +end + +return _M; diff --git a/data/templates/metronome/modules/mod_auth_ldap2.lua b/data/templates/metronome/modules/mod_auth_ldap2.lua new file mode 100644 index 00000000..8c50a99f --- /dev/null +++ b/data/templates/metronome/modules/mod_auth_ldap2.lua @@ -0,0 +1,81 @@ +-- vim:sts=4 sw=4 + +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- Copyright (C) 2012 Rob Hoelz +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- +-- http://code.google.com/p/prosody-modules/source/browse/mod_auth_ldap/mod_auth_ldap.lua +-- adapted to use common LDAP store + +local ldap = module:require 'ldap'; +local new_sasl = require 'util.sasl'.new; +local jsplit = require 'util.jid'.split; + +if not ldap then + return; +end + +local provider = {} + +function provider.test_password(username, password) + return ldap.bind(username, password); +end + +function provider.user_exists(username) + local params = ldap.getparams() + + local filter = ldap.filter.combine_and(params.user.filter, params.user.usernamefield .. '=' .. username); + if params.user.usernamefield == 'mail' then + filter = ldap.filter.combine_and(params.user.filter, 'mail=' .. username .. '@*'); + end + + return ldap.singlematch { + base = params.user.basedn, + filter = filter, + }; +end + +function provider.get_password(username) + return nil, "Passwords unavailable for LDAP."; +end + +function provider.set_password(username, password) + return nil, "Passwords unavailable for LDAP."; +end + +function provider.create_user(username, password) + return nil, "Account creation/modification not available with LDAP."; +end + +function provider.get_sasl_handler() + local testpass_authentication_profile = { + plain_test = function(sasl, username, password, realm) + return provider.test_password(username, password), true; + end, + mechanisms = { PLAIN = true }, + }; + return new_sasl(module.host, testpass_authentication_profile); +end + +function provider.is_admin(jid) + local admin_config = ldap.getparams().admin; + + if not admin_config then + return; + end + + local ld = ldap:getconnection(); + local username = jsplit(jid); + local filter = ldap.filter.combine_and(admin_config.filter, admin_config.namefield .. '=' .. username); + + return ldap.singlematch { + base = admin_config.basedn, + filter = filter, + }; +end + +module:provides("auth", provider); diff --git a/data/templates/metronome/modules/mod_legacyauth.lua b/data/templates/metronome/modules/mod_legacyauth.lua new file mode 100644 index 00000000..3ee8b978 --- /dev/null +++ b/data/templates/metronome/modules/mod_legacyauth.lua @@ -0,0 +1,87 @@ +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + + + +local st = require "util.stanza"; +local t_concat = table.concat; + +local secure_auth_only = module:get_option("c2s_require_encryption") + or module:get_option("require_encryption") + or not(module:get_option("allow_unencrypted_plain_auth")); + +local sessionmanager = require "core.sessionmanager"; +local usermanager = require "core.usermanager"; +local nodeprep = require "util.encodings".stringprep.nodeprep; +local resourceprep = require "util.encodings".stringprep.resourceprep; + +module:add_feature("jabber:iq:auth"); +module:hook("stream-features", function(event) + local origin, features = event.origin, event.features; + if secure_auth_only and not origin.secure then + -- Sorry, not offering to insecure streams! + return; + elseif not origin.username then + features:tag("auth", {xmlns='http://jabber.org/features/iq-auth'}):up(); + end +end); + +module:hook("stanza/iq/jabber:iq:auth:query", function(event) + local session, stanza = event.origin, event.stanza; + + if session.type ~= "c2s_unauthed" then + (session.sends2s or session.send)(st.error_reply(stanza, "cancel", "service-unavailable", "Legacy authentication is only allowed for unauthenticated client connections.")); + return true; + end + + if secure_auth_only and not session.secure then + session.send(st.error_reply(stanza, "modify", "not-acceptable", "Encryption (SSL or TLS) is required to connect to this server")); + return true; + end + + local username = stanza.tags[1]:child_with_name("username"); + local password = stanza.tags[1]:child_with_name("password"); + local resource = stanza.tags[1]:child_with_name("resource"); + if not (username and password and resource) then + local reply = st.reply(stanza); + session.send(reply:query("jabber:iq:auth") + :tag("username"):up() + :tag("password"):up() + :tag("resource"):up()); + else + username, password, resource = t_concat(username), t_concat(password), t_concat(resource); + username = nodeprep(username); + resource = resourceprep(resource) + if not (username and resource) then + session.send(st.error_reply(stanza, "modify", "bad-request")); + return true; + end + if usermanager.test_password(username, session.host, password) then + -- Authentication successful! + local success, err = sessionmanager.make_authenticated(session, username); + if success then + local err_type, err_msg; + success, err_type, err, err_msg = sessionmanager.bind_resource(session, resource); + if not success then + session.send(st.error_reply(stanza, err_type, err, err_msg)); + session.username, session.type = nil, "c2s_unauthed"; -- FIXME should this be placed in sessionmanager? + return true; + elseif resource ~= session.resource then -- server changed resource, not supported by legacy auth + session.send(st.error_reply(stanza, "cancel", "conflict", "The requested resource could not be assigned to this session.")); + session:close(); -- FIXME undo resource bind and auth instead of closing the session? + return true; + end + end + session.send(st.reply(stanza)); + else + session.send(st.error_reply(stanza, "auth", "not-authorized")); + end + end + return true; +end); + diff --git a/data/templates/metronome/modules/mod_storage_ldap.lua b/data/templates/metronome/modules/mod_storage_ldap.lua new file mode 100644 index 00000000..17850a21 --- /dev/null +++ b/data/templates/metronome/modules/mod_storage_ldap.lua @@ -0,0 +1,180 @@ +-- vim:sts=4 sw=4 + +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- Copyright (C) 2012 Rob Hoelz +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +---------------------------------------- +-- Constants and such -- +---------------------------------------- + +local setmetatable = setmetatable; +local ldap = module:require 'ldap'; +local vcardlib = module:require 'vcard'; +local st = require 'util.stanza'; +local gettime = require 'socket'.gettime; + +if not ldap then + return; +end + +local CACHE_EXPIRY = 300; +local params = module:get_option('ldap'); + +---------------------------------------- +-- Utility Functions -- +---------------------------------------- + +local function ldap_record_to_vcard(record) + return vcardlib.create { + record = record, + format = params.vcard_format, + } +end + +local get_alias_for_user; + +do + local user_cache; + local last_fetch_time; + + local function populate_user_cache() + local ld = ldap.getconnection(); + + local usernamefield = params.user.usernamefield; + local namefield = params.user.namefield; + + user_cache = {}; + + for _, attrs in ld:search { base = params.user.basedn, scope = 'onelevel', filter = params.user.filter } do + user_cache[attrs[usernamefield]] = attrs[namefield]; + end + last_fetch_time = gettime(); + end + + function get_alias_for_user(user) + if last_fetch_time and last_fetch_time + CACHE_EXPIRY < gettime() then + user_cache = nil; + end + if not user_cache then + populate_user_cache(); + end + return user_cache[user]; + end +end + +---------------------------------------- +-- General Setup -- +---------------------------------------- + +local ldap_store = {}; +ldap_store.__index = ldap_store; + +local adapters = { + roster = {}, + vcard = {}, +} + +for k, v in pairs(adapters) do + setmetatable(v, ldap_store); + v.__index = v; + v.name = k; +end + +function ldap_store:get(username) + return nil, "get method unimplemented on store '" .. tostring(self.name) .. "'" +end + +function ldap_store:set(username, data) + return nil, "LDAP storage is currently read-only"; +end + +---------------------------------------- +-- Roster Storage Implementation -- +---------------------------------------- + +function adapters.roster:get(username) + local ld = ldap.getconnection(); + local contacts = {}; + + local memberfield = params.groups.memberfield; + local namefield = params.groups.namefield; + local filter = memberfield .. '=' .. tostring(username); + + local groups = {}; + for _, config in ipairs(params.groups) do + groups[ config[namefield] ] = config.name; + end + + -- XXX this kind of relies on the way we do groups at INOC + for _, attrs in ld:search { base = params.groups.basedn, scope = 'onelevel', filter = filter } do + if groups[ attrs[namefield] ] then + local members = attrs[memberfield]; + + for _, user in ipairs(members) do + if user ~= username then + local jid = user .. '@' .. module.host; + local record = contacts[jid]; + + if not record then + record = { + subscription = 'both', + groups = {}, + name = get_alias_for_user(user), + }; + contacts[jid] = record; + end + + record.groups[ groups[ attrs[namefield] ] ] = true; + end + end + end + end + + return contacts; +end + +---------------------------------------- +-- vCard Storage Implementation -- +---------------------------------------- + +function adapters.vcard:get(username) + if not params.vcard_format then + return nil, ''; + end + + local ld = ldap.getconnection(); + local filter = params.user.usernamefield .. '=' .. tostring(username); + + local match = ldap.singlematch { + base = params.user.basedn, + filter = filter, + }; + if match then + match.jid = username .. '@' .. module.host + return st.preserialize(ldap_record_to_vcard(match)); + else + return nil, 'not found'; + end +end + +---------------------------------------- +-- Driver Definition -- +---------------------------------------- + +local driver = {}; + +function driver:open(store, typ) + local adapter = adapters[store]; + + if adapter and not typ then + return adapter; + end + return nil, "unsupported-store"; +end +module:provides("storage", driver); diff --git a/data/templates/metronome/modules/vcard.lib.lua b/data/templates/metronome/modules/vcard.lib.lua new file mode 100644 index 00000000..dcbd0106 --- /dev/null +++ b/data/templates/metronome/modules/vcard.lib.lua @@ -0,0 +1,162 @@ +-- vim:sts=4 sw=4 + +-- Prosody IM +-- Copyright (C) 2008-2010 Matthew Wild +-- Copyright (C) 2008-2010 Waqas Hussain +-- Copyright (C) 2012 Rob Hoelz +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +local st = require 'util.stanza'; + +local VCARD_NS = 'vcard-temp'; + +local builder_methods = {}; + +local base64_encode = require('util.encodings').base64.encode; + +function builder_methods:addvalue(key, value) + self.vcard:tag(key):text(value):up(); +end + +function builder_methods:addphotofield(tagname, format_section) + local record = self.record; + local format = self.format; + local vcard = self.vcard; + local config = format[format_section]; + + if not config then + return; + end + + if config.extval then + if record[config.extval] then + local tag = vcard:tag(tagname); + tag:tag('EXTVAL'):text(record[config.extval]):up(); + end + elseif config.type and config.binval then + if record[config.binval] then + local tag = vcard:tag(tagname); + tag:tag('TYPE'):text(config.type):up(); + tag:tag('BINVAL'):text(base64_encode(record[config.binval])):up(); + end + else + module:log('error', 'You have an invalid %s config section', tagname); + return; + end + + vcard:up(); +end + +function builder_methods:addregularfield(tagname, format_section) + local record = self.record; + local format = self.format; + local vcard = self.vcard; + + if not format[format_section] then + return; + end + + local tag = vcard:tag(tagname); + + for k, v in pairs(format[format_section]) do + tag:tag(string.upper(k)):text(record[v]):up(); + end + + vcard:up(); +end + +function builder_methods:addmultisectionedfield(tagname, format_section) + local record = self.record; + local format = self.format; + local vcard = self.vcard; + + if not format[format_section] then + return; + end + + for k, v in pairs(format[format_section]) do + local tag = vcard:tag(tagname); + + if type(k) == 'string' then + tag:tag(string.upper(k)):up(); + end + + for k2, v2 in pairs(v) do + if type(v2) == 'boolean' then + tag:tag(string.upper(k2)):up(); + else + tag:tag(string.upper(k2)):text(record[v2]):up(); + end + end + + vcard:up(); + end +end + +function builder_methods:build() + local record = self.record; + local format = self.format; + + self:addvalue( 'VERSION', '2.0'); + self:addvalue( 'FN', record[format.displayname]); + self:addregularfield( 'N', 'name'); + self:addvalue( 'NICKNAME', record[format.nickname]); + self:addphotofield( 'PHOTO', 'photo'); + self:addvalue( 'BDAY', record[format.birthday]); + self:addmultisectionedfield('ADR', 'address'); + self:addvalue( 'LABEL', nil); -- we don't support LABEL...yet. + self:addmultisectionedfield('TEL', 'telephone'); + self:addmultisectionedfield('EMAIL', 'email'); + self:addvalue( 'JABBERID', record.jid); + self:addvalue( 'MAILER', record[format.mailer]); + self:addvalue( 'TZ', record[format.timezone]); + self:addregularfield( 'GEO', 'geo'); + self:addvalue( 'TITLE', record[format.title]); + self:addvalue( 'ROLE', record[format.role]); + self:addphotofield( 'LOGO', 'logo'); + self:addvalue( 'AGENT', nil); -- we don't support AGENT...yet. + self:addregularfield( 'ORG', 'org'); + self:addvalue( 'CATEGORIES', nil); -- we don't support CATEGORIES...yet. + self:addvalue( 'NOTE', record[format.note]); + self:addvalue( 'PRODID', nil); -- we don't support PRODID...yet. + self:addvalue( 'REV', record[format.rev]); + self:addvalue( 'SORT-STRING', record[format.sortstring]); + self:addregularfield( 'SOUND', 'sound'); + self:addvalue( 'UID', record[format.uid]); + self:addvalue( 'URL', record[format.url]); + self:addvalue( 'CLASS', nil); -- we don't support CLASS...yet. + self:addregularfield( 'KEY', 'key'); + self:addvalue( 'DESC', record[format.description]); + + return self.vcard; +end + +local function new_builder(params) + local vcard_tag = st.stanza('vCard', { xmlns = VCARD_NS }); + + local object = { + vcard = vcard_tag, + __index = builder_methods, + }; + + for k, v in pairs(params) do + object[k] = v; + end + + setmetatable(object, object); + + return object; +end + +local _M = {}; + +function _M.create(params) + local builder = new_builder(params); + + return builder:build(); +end + +return _M; diff --git a/data/templates/mysql/my.cnf b/data/templates/mysql/my.cnf new file mode 100644 index 00000000..2d4e1df2 --- /dev/null +++ b/data/templates/mysql/my.cnf @@ -0,0 +1,89 @@ +# Example MySQL config file for small systems. +# +# This is for a system with little memory (<= 64M) where MySQL is only used +# from time to time and it's important that the mysqld daemon +# doesn't use much resources. +# +# MySQL programs look for option files in a set of +# locations which depend on the deployment platform. +# You can copy this option file to one of those +# locations. For information about these locations, see: +# http://dev.mysql.com/doc/mysql/en/option-files.html +# +# In this file, you can use all long options that a program supports. +# If you want to know which options a program supports, run the program +# with the "--help" option. + +# The following options will be passed to all MySQL clients +[client] +#password = your_password +port = 3306 +socket = /var/run/mysqld/mysqld.sock + +# Here follows entries for some specific programs + +# The MySQL server +[mysqld] +port = 3306 +socket = /var/run/mysqld/mysqld.sock +skip-external-locking +key_buffer_size = 16K +max_allowed_packet = 1M +table_open_cache = 4 +sort_buffer_size = 64K +read_buffer_size = 256K +read_rnd_buffer_size = 256K +net_buffer_length = 2K +thread_stack = 128K + +# Don't listen on a TCP/IP port at all. This can be a security enhancement, +# if all processes that need to connect to mysqld run on the same host. +# All interaction with mysqld must be made via Unix sockets or named pipes. +# Note that using this option without enabling named pipes on Windows +# (using the "enable-named-pipe" option) will render mysqld useless! +# +#skip-networking +server-id = 1 + +# Uncomment the following if you want to log updates +#log-bin=mysql-bin + +# binary logging format - mixed recommended +#binlog_format=mixed + +# Causes updates to non-transactional engines using statement format to be +# written directly to binary log. Before using this option make sure that +# there are no dependencies between transactional and non-transactional +# tables such as in the statement INSERT INTO t_myisam SELECT * FROM +# t_innodb; otherwise, slaves may diverge from the master. +#binlog_direct_non_transactional_updates=TRUE + +# Uncomment the following if you are using InnoDB tables +#innodb_data_home_dir = /var/lib/mysql +#innodb_data_file_path = ibdata1:10M:autoextend +#innodb_log_group_home_dir = /var/lib/mysql +# You can set .._buffer_pool_size up to 50 - 80 % +# of RAM but beware of setting memory usage too high +#innodb_buffer_pool_size = 16M +#innodb_additional_mem_pool_size = 2M +# Set .._log_file_size to 25 % of buffer pool size +#innodb_log_file_size = 5M +#innodb_log_buffer_size = 8M +#innodb_flush_log_at_trx_commit = 1 +#innodb_lock_wait_timeout = 50 + +[mysqldump] +quick +max_allowed_packet = 16M + +[mysql] +no-auto-rehash +# Remove the next comment character if you are not familiar with SQL +#safe-updates + +[myisamchk] +key_buffer_size = 8M +sort_buffer_size = 8M + +[mysqlhotcopy] +interactive-timeout diff --git a/data/templates/nginx/server.conf.sed b/data/templates/nginx/server.conf.sed new file mode 100644 index 00000000..656a1d80 --- /dev/null +++ b/data/templates/nginx/server.conf.sed @@ -0,0 +1,46 @@ +server { + listen 80; + listen [::]:80; + server_name {{ domain }}; + + access_by_lua_file /usr/share/ssowat/access.lua; + + include conf.d/{{ domain }}.d/*.conf; + + location /yunohost/admin { + rewrite ^ https://$http_host$request_uri? permanent; + } + + access_log /var/log/nginx/{{ domain }}-access.log; + error_log /var/log/nginx/{{ domain }}-error.log; +} + +server { + listen 443 ssl; + listen [::]:443 ssl; + server_name {{ domain }}; + ssl_certificate /etc/yunohost/certs/{{ domain }}/crt.pem; + ssl_certificate_key /etc/yunohost/certs/{{ domain }}/key.pem; + + ssl_session_timeout 5m; + ssl_session_cache shared:SSL:50m; + ssl_prefer_server_ciphers on; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers ALL:!aNULL:!eNULL:!LOW:!EXP:!RC4:!3DES:+HIGH:+MEDIUM; + add_header Strict-Transport-Security "max-age=31536000;"; + + # Uncomment the following directive after DH generation + # > openssl dhparam -out /etc/ssl/private/dh2048.pem -outform PEM -2 2048 + + #ssl_dhparam /etc/ssl/private/dh2048.pem; + + access_by_lua_file /usr/share/ssowat/access.lua; + + include conf.d/{{ domain }}.d/*.conf; + + include conf.d/yunohost_admin.conf.inc; + include conf.d/yunohost_api.conf.inc; + + access_log /var/log/nginx/{{ domain }}-access.log; + error_log /var/log/nginx/{{ domain }}-error.log; +} diff --git a/data/templates/nginx/ssowat.conf b/data/templates/nginx/ssowat.conf new file mode 100644 index 00000000..c82cd40e --- /dev/null +++ b/data/templates/nginx/ssowat.conf @@ -0,0 +1,3 @@ +lua_shared_dict cache 10m; +init_by_lua_file /usr/share/ssowat/init.lua; +server_names_hash_bucket_size 64; diff --git a/data/templates/nginx/yunohost_admin.conf b/data/templates/nginx/yunohost_admin.conf new file mode 100644 index 00000000..0f208cb5 --- /dev/null +++ b/data/templates/nginx/yunohost_admin.conf @@ -0,0 +1,35 @@ +server { + listen 80 default_server; + listen [::]:80 default_server; + location / { + rewrite ^ https://$http_host/yunohost/admin permanent; + } + location /yunohost/admin { + rewrite ^ https://$http_host$request_uri? permanent; + } +} +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + ssl_certificate /etc/yunohost/certs/yunohost.org/crt.pem; + ssl_certificate_key /etc/yunohost/certs/yunohost.org/key.pem; + ssl_session_timeout 5m; + ssl_session_cache shared:SSL:50m; + ssl_prefer_server_ciphers on; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers ALL:!aNULL:!eNULL:!LOW:!EXP:!RC4:!3DES:+HIGH:+MEDIUM; + add_header Strict-Transport-Security "max-age=31536000;"; + + location / { + rewrite ^ https://$http_host/yunohost/admin permanent; + } + + # Block crawlers bot + location /yunohost { + if ($http_user_agent ~ (crawl|Googlebot|Slurp|spider|bingbot|tracker|click|parser|spider|facebookexternalhit) ) { + return 403; + } + } + include conf.d/yunohost_admin.conf.inc; + include conf.d/yunohost_api.conf.inc; +} diff --git a/data/templates/nginx/yunohost_admin.conf.inc b/data/templates/nginx/yunohost_admin.conf.inc new file mode 100644 index 00000000..73610294 --- /dev/null +++ b/data/templates/nginx/yunohost_admin.conf.inc @@ -0,0 +1,5 @@ +location /yunohost/admin { + alias /usr/share/yunohost/admin/; + default_type text/html; + index index.html; +} diff --git a/data/templates/nginx/yunohost_api.conf.inc b/data/templates/nginx/yunohost_api.conf.inc new file mode 100644 index 00000000..307eb4aa --- /dev/null +++ b/data/templates/nginx/yunohost_api.conf.inc @@ -0,0 +1,7 @@ +location /yunohost/api/ { + proxy_read_timeout 3600s; + proxy_pass http://127.0.0.1:6787/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; +} diff --git a/data/templates/nginx/yunohost_local.conf b/data/templates/nginx/yunohost_local.conf new file mode 100644 index 00000000..ebf2bd65 --- /dev/null +++ b/data/templates/nginx/yunohost_local.conf @@ -0,0 +1 @@ +server_name $server_name yunohost.local; diff --git a/data/templates/nginx/yunohost_panel.conf.inc b/data/templates/nginx/yunohost_panel.conf.inc new file mode 100644 index 00000000..4d5b441d --- /dev/null +++ b/data/templates/nginx/yunohost_panel.conf.inc @@ -0,0 +1,2 @@ +sub_filter ''; +sub_filter_once on; diff --git a/data/templates/nslcd/nslcd.conf b/data/templates/nslcd/nslcd.conf new file mode 100644 index 00000000..c927b5f3 --- /dev/null +++ b/data/templates/nslcd/nslcd.conf @@ -0,0 +1,38 @@ +# /etc/nslcd.conf +# nslcd configuration file. See nslcd.conf(5) +# for details. + +# The user and group nslcd should run as. +uid nslcd +gid nslcd + +# The location at which the LDAP server(s) should be reachable. +uri ldap://localhost/ + +# The search base that will be used for all queries. +base dc=yunohost,dc=org + +# The LDAP protocol version to use. +#ldap_version 3 + +# The DN to bind with for normal lookups. +#binddn cn=annonymous,dc=example,dc=net +#bindpw secret + +# The DN used for password modifications by root. +#rootpwmoddn cn=admin,dc=example,dc=com + +# SSL options +#ssl off +#tls_reqcert never +tls_cacertfile /etc/ssl/certs/ca-certificates.crt + +# The search scope. +#scope sub + + + + + + + diff --git a/data/templates/nsswitch/nsswitch.conf b/data/templates/nsswitch/nsswitch.conf new file mode 100644 index 00000000..cf5b4525 --- /dev/null +++ b/data/templates/nsswitch/nsswitch.conf @@ -0,0 +1,21 @@ +# /etc/nsswitch.conf +# +# Example configuration of GNU Name Service Switch functionality. +# If you have the `glibc-doc-reference' and `info' packages installed, try: +# `info libc "Name Service Switch"' for information about this file. + +passwd: compat ldap +group: compat ldap +shadow: compat ldap +gshadow: files + +hosts: files mdns4_minimal [NOTFOUND=return] dns +networks: files + +protocols: db files +services: db files +ethers: db files +rpc: db files + +netgroup: nis +sudoers: files ldap diff --git a/data/templates/postfix/header_check b/data/templates/postfix/header_check new file mode 100644 index 00000000..bf5c3352 --- /dev/null +++ b/data/templates/postfix/header_check @@ -0,0 +1,4 @@ +/^X-Originating-IP:/ IGNORE +/^Received:/ IGNORE +/^User-Agent:/ IGNORE +/^X-Mailer:/ IGNORE diff --git a/data/templates/postfix/ldap-accounts.cf b/data/templates/postfix/ldap-accounts.cf new file mode 100644 index 00000000..bd3576de --- /dev/null +++ b/data/templates/postfix/ldap-accounts.cf @@ -0,0 +1,5 @@ +server_host = localhost +server_port = 389 +search_base = dc=yunohost,dc=org +query_filter = (&(objectClass=mailAccount)(mail=%s)) +result_attribute = uid diff --git a/data/templates/postfix/ldap-aliases.cf b/data/templates/postfix/ldap-aliases.cf new file mode 100644 index 00000000..a9ef52cf --- /dev/null +++ b/data/templates/postfix/ldap-aliases.cf @@ -0,0 +1,5 @@ +server_host = localhost +server_port = 389 +search_base = dc=yunohost,dc=org +query_filter = (&(objectClass=mailAccount)(mail=%s)) +result_attribute = maildrop diff --git a/data/templates/postfix/ldap-domains.cf b/data/templates/postfix/ldap-domains.cf new file mode 100644 index 00000000..088640bf --- /dev/null +++ b/data/templates/postfix/ldap-domains.cf @@ -0,0 +1,5 @@ +server_host = localhost +server_port = 389 +search_base = ou=domains,dc=yunohost,dc=org +query_filter = (&(objectClass=mailDomain)(virtualdomain=%s)) +result_attribute = virtualdomain diff --git a/data/templates/postfix/main.cf.sed b/data/templates/postfix/main.cf.sed new file mode 100644 index 00000000..fd81ae64 --- /dev/null +++ b/data/templates/postfix/main.cf.sed @@ -0,0 +1,145 @@ +# See /usr/share/postfix/main.cf.dist for a commented, more complete version + + +# Debian specific: Specifying a file name will cause the first +# line of that file to be used as the name. The Debian default +# is /etc/mailname. +#myorigin = /etc/mailname + +smtpd_banner = $myhostname Service ready +biff = no + +# appending .domain is the MUA's job. +append_dot_mydomain = no + +# Uncomment the next line to generate "delayed mail" warnings +#delay_warning_time = 4h + +readme_directory = no + +# -- TLS for incoming connections +# By default, TLS is disabled in the Postfix SMTP server, so no difference to +# plain Postfix is visible. Explicitly switch it on with "smtpd_tls_security_level = may". +smtpd_tls_security_level=may + +# Sending AUTH data over an unencrypted channel poses a security risk. +# When TLS layer encryption is optional ("smtpd_tls_security_level = may"), it +# may however still be useful to only offer AUTH when TLS is active. To maintain +# compatibility with non-TLS clients, the default is to accept AUTH without +# encryption. In order to change this behavior, we set "smtpd_tls_auth_only = yes". +smtpd_tls_auth_only=yes +smtpd_tls_cert_file=/etc/ssl/certs/yunohost_crt.pem +smtpd_tls_key_file=/etc/ssl/private/yunohost_key.pem +smtpd_tls_CAfile = /etc/ssl/certs/ca-yunohost_crt.pem +smtpd_tls_exclude_ciphers = aNULL, MD5, DES, ADH, RC4 +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtpd_tls_loglevel=1 +smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3 +smtpd_tls_mandatory_ciphers=high + +# -- TLS for outgoing connections +# Use TLS if this is supported by the remote SMTP server, otherwise use plaintext. +smtp_tls_security_level=may +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache +smtp_tls_loglevel=1 + +# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for +# information on enabling SSL in the smtp client. + +myhostname = {{ main_domain }} +alias_maps = hash:/etc/aliases +alias_database = hash:/etc/aliases +mydomain = {{ main_domain }} +mydestination = localhost +relayhost = +mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 +mailbox_command = procmail -a "$EXTENSION" +mailbox_size_limit = 0 +recipient_delimiter = + +inet_interfaces = all + +#### Fit to the maximum message size allowed by GMail or Yahoo #### +message_size_limit = 26214400 + +# Virtual Domains Control +virtual_mailbox_domains = ldap:/etc/postfix/ldap-domains.cf +virtual_mailbox_maps = ldap:/etc/postfix/ldap-accounts.cf +virtual_mailbox_base = +virtual_alias_maps = ldap:/etc/postfix/ldap-aliases.cf +virtual_alias_domains = +virtual_minimum_uid = 100 +virtual_uid_maps = static:vmail +virtual_gid_maps = static:mail + +# Dovecot LDA +virtual_transport = dovecot +dovecot_destination_recipient_limit = 1 + +# Enable SASL authentication for the smtpd daemon +smtpd_sasl_auth_enable = yes +smtpd_sasl_type = dovecot +smtpd_sasl_path = private/auth +# Fix some outlook's bugs +broken_sasl_auth_clients = yes +# Reject anonymous connections +smtpd_sasl_security_options = noanonymous +smtpd_sasl_local_domain = + + +# Use AMaVis +content_filter = amavis:[127.0.0.1]:10024 + +# Wait until the RCPT TO command before evaluating restrictions +smtpd_delay_reject = yes + +# Basics Restrictions +smtpd_helo_required = yes +strict_rfc821_envelopes = yes + +# Requirements for the connecting server +smtpd_client_restrictions = + permit_mynetworks, + permit_sasl_authenticated, + reject_rbl_client bl.spamcop.net, + reject_rbl_client cbl.abuseat.org, + reject_rbl_client zen.spamhaus.org, + permit + +# Requirements for the HELO statement +smtpd_helo_restrictions = + permit_mynetworks, + permit_sasl_authenticated, + reject_non_fqdn_hostname, + reject_invalid_hostname, + permit + +# Requirements for the sender address +smtpd_sender_restrictions = + permit_mynetworks, + permit_sasl_authenticated, + reject_non_fqdn_sender, + reject_unknown_sender_domain, + permit + +# Requirement for the recipient address +smtpd_recipient_restrictions = + permit_mynetworks, + permit_sasl_authenticated, + reject_non_fqdn_recipient, + reject_unknown_recipient_domain, + reject_unauth_destination, + check_policy_service unix:private/policy-spf + check_policy_service inet:127.0.0.1:10023 + permit + +# Use SPF +policy-spf_time_limit = 3600s + +# SRS +sender_canonical_maps = regexp:/etc/postfix/sender_canonical +sender_canonical_classes = envelope_sender + +# Ignore some headers +smtp_header_checks = regexp:/etc/postfix/header_checks + +smtp_reply_filter = pcre:/etc/postfix/smtp_reply_filter diff --git a/data/templates/postfix/master.cf b/data/templates/postfix/master.cf new file mode 100644 index 00000000..cf7fd626 --- /dev/null +++ b/data/templates/postfix/master.cf @@ -0,0 +1,147 @@ +# +# Postfix master process configuration file. For details on the format +# of the file, see the master(5) manual page (command: "man 5 master"). +# +# Do not forget to execute "postfix reload" after editing this file. +# +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (yes) (never) (100) +# ========================================================================== +smtp inet n - - - - smtpd +submission inet n - - - - smtpd + -o smtpd_tls_security_level=encrypt + -o smtpd_sasl_auth_enable=yes + -o smtpd_client_restrictions=permit_sasl_authenticated,reject +# -o milter_macro_daemon_name=ORIGINATING +smtps inet n - - - - smtpd + -o header_checks=pcre:/etc/postfix/header_checks + -o smtpd_tls_wrappermode=yes + -o smtpd_sasl_auth_enable=yes +# -o smtpd_client_restrictions=permit_sasl_authenticated,reject +# -o milter_macro_daemon_name=ORIGINATING +#628 inet n - - - - qmqpd +pickup fifo n - - 60 1 pickup +cleanup unix n - - - 0 cleanup +qmgr fifo n - n 300 1 qmgr +#qmgr fifo n - - 300 1 oqmgr +tlsmgr unix - - - 1000? 1 tlsmgr +rewrite unix - - - - - trivial-rewrite +bounce unix - - - - 0 bounce +defer unix - - - - 0 bounce +trace unix - - - - 0 bounce +verify unix - - - - 1 verify +flush unix n - - 1000? 0 flush +proxymap unix - - n - - proxymap +proxywrite unix - - n - 1 proxymap +smtp unix - - - - - smtp +# When relaying mail as backup MX, disable fallback_relay to avoid MX loops +relay unix - - - - - smtp + -o smtp_fallback_relay= +# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 +showq unix n - - - - showq +error unix - - - - - error +retry unix - - - - - error +discard unix - - - - - discard +local unix - n n - - local +virtual unix - n n - - virtual +lmtp unix - - - - - lmtp +anvil unix - - - - 1 anvil +scache unix - - - - 1 scache +# +# ==================================================================== +# Interfaces to non-Postfix software. Be sure to examine the manual +# pages of the non-Postfix software to find out what options it wants. +# +# Many of the following services use the Postfix pipe(8) delivery +# agent. See the pipe(8) man page for information about ${recipient} +# and other message envelope options. +# ==================================================================== +# +# maildrop. See the Postfix MAILDROP_README file for details. +# Also specify in main.cf: maildrop_destination_recipient_limit=1 +# +maildrop unix - n n - - pipe + flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient} +# +# ==================================================================== +# +# Recent Cyrus versions can use the existing "lmtp" master.cf entry. +# +# Specify in cyrus.conf: +# lmtp cmd="lmtpd -a" listen="localhost:lmtp" proto=tcp4 +# +# Specify in main.cf one or more of the following: +# mailbox_transport = lmtp:inet:localhost +# virtual_transport = lmtp:inet:localhost +# +# ==================================================================== +# +# Cyrus 2.1.5 (Amos Gouaux) +# Also specify in main.cf: cyrus_destination_recipient_limit=1 +# +#cyrus unix - n n - - pipe +# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user} +# +# ==================================================================== +# Old example of delivery via Cyrus. +# +#old-cyrus unix - n n - - pipe +# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user} +# +# ==================================================================== +# +# See the Postfix UUCP_README file for configuration details. +# +uucp unix - n n - - pipe + flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient) +# +# Other external delivery methods. +# +ifmail unix - n n - - pipe + flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient) +bsmtp unix - n n - - pipe + flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient +scalemail-backend unix - n n - 2 pipe + flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension} +mailman unix - n n - - pipe + flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py + ${nexthop} ${user} + +# Dovecot LDA +dovecot unix - n n - - pipe + flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop} -m ${extension} +# ========================================================================== +# service type private unpriv chroot wakeup maxproc command + args +# (yes) (yes) (yes) (never) (100) +# ========================================================================== +# Added using postfix-add-filter script: +amavis unix - - - - 2 smtp + -o smtp_data_done_timeout=1200 + -o smtp_send_xforward_command=yes + -o smtp_tls_note_starttls_offer=no + +policy-spf unix - n n - - spawn + user=nobody argv=/usr/bin/perl /usr/sbin/postfix-policyd-spf-perl + +127.0.0.1:10025 inet n - - - - smtpd + -o content_filter= + -o smtpd_delay_reject=no + -o smtpd_client_restrictions=permit_mynetworks,reject + -o smtpd_helo_restrictions= + -o smtpd_sender_restrictions= + -o smtpd_recipient_restrictions=permit_mynetworks,reject + -o smtpd_data_restrictions=reject_unauth_pipelining + -o smtpd_end_of_data_restrictions= + -o smtpd_restriction_classes= + -o mynetworks=127.0.0.0/8 + -o smtpd_error_sleep_time=0 + -o smtpd_soft_error_limit=1001 + -o smtpd_hard_error_limit=1000 + -o smtpd_client_connection_count_limit=0 + -o smtpd_client_connection_rate_limit=0 + -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters + -o local_header_rewrite_clients= + -o smtpd_milters= + -o local_recipient_maps= + -o relay_recipient_maps= diff --git a/data/templates/postfix/sender_canonical b/data/templates/postfix/sender_canonical new file mode 100644 index 00000000..caf093d1 --- /dev/null +++ b/data/templates/postfix/sender_canonical @@ -0,0 +1 @@ +/^(.*)@(.*)$/ ${1} diff --git a/data/templates/postfix/smtp_reply_filter b/data/templates/postfix/smtp_reply_filter new file mode 100644 index 00000000..5f15648f --- /dev/null +++ b/data/templates/postfix/smtp_reply_filter @@ -0,0 +1,8 @@ +# Google Mail bounces email sent via IPv6, while this works ok with IPv4. +# +# Convert Google Mail IPv6 complaint permanent error into a temporary error. +# Turn 550 error containing gsmtp in the message into 450 error. +# This way Postfix will attempt to deliver this e-mail using another MX +# (via IPv4). +# +/^5(\d\d )5(.*information. \S+ - gsmtp.*)/ 4${1}4$2 diff --git a/data/templates/postgrey/postgrey.default b/data/templates/postgrey/postgrey.default new file mode 100644 index 00000000..1af70c14 --- /dev/null +++ b/data/templates/postgrey/postgrey.default @@ -0,0 +1,12 @@ +# postgrey startup options, created for Debian + +# you may want to set +# --delay=N how long to greylist, seconds (default: 300) +# --max-age=N delete old entries after N days (default: 35) +# see also the postgrey(8) manpage + +POSTGREY_OPTS="--inet=10023 --delay=30" + +# the --greylist-text commandline argument can not be easily passed through +# POSTGREY_OPTS when it contains spaces. So, insert your text here: +#POSTGREY_TEXT="Your customized rejection message here" diff --git a/data/templates/slapd/ldap.conf b/data/templates/slapd/ldap.conf new file mode 100644 index 00000000..406b5c17 --- /dev/null +++ b/data/templates/slapd/ldap.conf @@ -0,0 +1,18 @@ +# +# LDAP Defaults +# + +# See ldap.conf(5) for details +# This file should be world readable but not world writable. + +#BASE dc=example,dc=com +#URI ldap://ldap.example.com ldap://ldap-master.example.com:666 + +#SIZELIMIT 12 +#TIMELIMIT 15 +#DEREF never + +# TLS certificates (needed for GnuTLS) +TLS_CACERT /etc/ssl/certs/ca-certificates.crt + +sudoers_base ou=sudo,dc=yunohost,dc=org diff --git a/data/templates/slapd/mailserver.schema b/data/templates/slapd/mailserver.schema new file mode 100644 index 00000000..23d0d24b --- /dev/null +++ b/data/templates/slapd/mailserver.schema @@ -0,0 +1,88 @@ +## LDAP Schema Yunohost EMAIL +## Version 0.1 +## Adrien Beudin + +# Attributes +attributetype ( 1.3.6.1.4.1.40328.1.20.2.1 + NAME 'maildrop' + DESC 'Mail addresses where mails are forwarded -- ie forwards' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512}) + +attributetype ( 1.3.6.1.4.1.40328.1.20.2.2 + NAME 'mailalias' + DESC 'Mail addresses accepted by this account -- ie aliases' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512}) + +attributetype ( 1.3.6.1.4.1.40328.1.20.2.3 + NAME 'mailenable' + DESC 'Mail Account validity' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{8}) + +attributetype ( 1.3.6.1.4.1.40328.1.20.2.4 + NAME 'mailbox' + DESC 'Mailbox path where mails are delivered' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512}) + +attributetype ( 1.3.6.1.4.1.40328.1.20.2.5 + NAME 'virtualdomain' + DESC 'A mail domain name' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512}) + +attributetype ( 1.3.6.1.4.1.40328.1.20.2.6 + NAME 'virtualdomaindescription' + DESC 'Virtual domain description' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{512}) + +attributetype ( 1.3.6.1.4.1.40328.1.20.2.7 + NAME 'mailuserquota' + DESC 'Mailbox quota for a user' + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{16} SINGLE-VALUE ) + +# Mail Account Objectclass +objectclass ( 1.3.6.1.4.1.40328.1.1.2.1 + NAME 'mailAccount' + DESC 'Mail Account' + SUP top + AUXILIARY + MUST ( + mail + ) + MAY ( + mailalias $ maildrop $ mailenable $ mailbox $ mailuserquota + ) + ) + +# Mail Domain Objectclass +objectclass ( 1.3.6.1.4.1.40328.1.1.2.2 + NAME 'mailDomain' + DESC 'Domain mail entry' + SUP top + STRUCTURAL + MUST ( + virtualdomain + ) + MAY ( + virtualdomaindescription $ mailuserquota + ) + ) + +# Mail Group Objectclass +objectclass ( 1.3.6.1.4.1.40328.1.1.2.3 + NAME 'mailGroup' SUP top AUXILIARY + DESC 'Mail Group' + MUST ( mail ) + ) diff --git a/data/templates/slapd/slapd.conf b/data/templates/slapd/slapd.conf new file mode 100644 index 00000000..f47e6761 --- /dev/null +++ b/data/templates/slapd/slapd.conf @@ -0,0 +1,142 @@ +# This is the main slapd configuration file. See slapd.conf(5) for more +# info on the configuration options. + +####################################################################### +# Global Directives: + +# Features to permit +#allow bind_v2 + +# Schema and objectClass definitions +include /etc/ldap/schema/core.schema +include /etc/ldap/schema/cosine.schema +include /etc/ldap/schema/nis.schema +include /etc/ldap/schema/inetorgperson.schema +include /etc/ldap/schema/mailserver.schema +include /etc/ldap/schema/sudo.schema + +# Where the pid file is put. The init.d script +# will not stop the server if you change this. +pidfile /var/run/slapd/slapd.pid + +# List of arguments that were passed to the server +argsfile /var/run/slapd/slapd.args + +password-hash {SSHA} + +# Read slapd.conf(5) for possible values +loglevel 256 + +# Where the dynamically loaded modules are stored +modulepath /usr/lib/ldap +moduleload back_hdb +moduleload memberof + +# The maximum number of entries that is returned for a search operation +sizelimit 500 + +# The tool-threads parameter sets the actual amount of cpu's that is used +# for indexing. +tool-threads 1 + +####################################################################### +# Specific Backend Directives for hdb: +# Backend specific directives apply to this backend until another +# 'backend' directive occurs +backend hdb + +####################################################################### +# Specific Backend Directives for 'other': +# Backend specific directives apply to this backend until another +# 'backend' directive occurs +#backend + +####################################################################### +# Specific Directives for database #1, of type hdb: +# Database specific directives apply to this databasse until another +# 'database' directive occurs +database hdb + +# The base of your directory in database #1 +suffix "dc=yunohost,dc=org" + +directory "/var/lib/ldap" + +# The dbconfig settings are used to generate a DB_CONFIG file the first +# time slapd starts. They do NOT override existing an existing DB_CONFIG +# file. You should therefore change these settings in DB_CONFIG directly +# or remove DB_CONFIG and restart slapd for changes to take effect. + +# For the Debian package we use 2MB as default but be sure to update this +# value if you have plenty of RAM +dbconfig set_cachesize 0 2097152 0 + +# Sven Hartge reported that he had to set this value incredibly high +# to get slapd running at all. See http://bugs.debian.org/303057 for more +# information. + +# Number of objects that can be locked at the same time. +dbconfig set_lk_max_objects 1500 +# Number of locks (both requested and granted) +dbconfig set_lk_max_locks 1500 +# Number of lockers +dbconfig set_lk_max_lockers 1500 + +# Indexing options for database #1 +index objectClass eq +index uid eq,sub +index entryCSN,entryUUID eq + +# Save the time that the entry gets modified, for database #1 +lastmod on + +# Checkpoint the BerkeleyDB database periodically in case of system +# failure and to speed slapd shutdown. +checkpoint 512 30 + +# Where to store the replica logs for database #1 +# replogfile /var/lib/ldap/replog + +# The userPassword by default can be changed +# by the entry owning it if they are authenticated. +# Others should not be able to see it, except the +# admin entry below +# These access lines apply to database #1 only +access to attrs=userPassword + by dn="cn=admin,dc=yunohost,dc=org" write + by anonymous auth + by self write + by * none + +access to attrs=cn,gecos,givenName,mail,maildrop,displayName,sn + by dn="cn=admin,dc=yunohost,dc=org" write + by self write + by * read + + +# Ensure read access to the base for things like +# supportedSASLMechanisms. Without this you may +# have problems with SASL not knowing what +# mechanisms are available and the like. +# Note that this is covered by the 'access to *' +# ACL below too but if you change that as people +# are wont to do you'll still need this if you +# want SASL (and possible other things) to work +# happily. +access to dn.base="" by * read + +# The admin dn has full write access, everyone else +# can read everything. +access to * + by dn="cn=admin,dc=yunohost,dc=org" write + by group/groupOfNames/Member="cn=admin,ou=groups,dc=yunohost,dc=org" write + by * read + +####################################################################### +# Specific Directives for database #2, of type 'other' (can be hdb too): +# Database specific directives apply to this databasse until another +# 'database' directive occurs +#database + +# The base of your directory for database #2 +#suffix "dc=debian,dc=org" diff --git a/data/templates/slapd/slapd.default b/data/templates/slapd/slapd.default new file mode 100644 index 00000000..372b8f4a --- /dev/null +++ b/data/templates/slapd/slapd.default @@ -0,0 +1,45 @@ +# Default location of the slapd.conf file or slapd.d cn=config directory. If +# empty, use the compiled-in default (/etc/ldap/slapd.d with a fallback to +# /etc/ldap/slapd.conf). +SLAPD_CONF= + +# System account to run the slapd server under. If empty the server +# will run as root. +SLAPD_USER="openldap" + +# System group to run the slapd server under. If empty the server will +# run in the primary group of its user. +SLAPD_GROUP="openldap" + +# Path to the pid file of the slapd server. If not set the init.d script +# will try to figure it out from $SLAPD_CONF (/etc/ldap/slapd.conf by +# default) +SLAPD_PIDFILE= + +# slapd normally serves ldap only on all TCP-ports 389. slapd can also +# service requests on TCP-port 636 (ldaps) and requests via unix +# sockets. +# Example usage: +# SLAPD_SERVICES="ldap://127.0.0.1:389/ ldaps:/// ldapi:///" +SLAPD_SERVICES="ldap:/// ldapi:///" + +# If SLAPD_NO_START is set, the init script will not start or restart +# slapd (but stop will still work). Uncomment this if you are +# starting slapd via some other means or if you don't want slapd normally +# started at boot. +#SLAPD_NO_START=1 + +# If SLAPD_SENTINEL_FILE is set to path to a file and that file exists, +# the init script will not start or restart slapd (but stop will still +# work). Use this for temporarily disabling startup of slapd (when doing +# maintenance, for example, or through a configuration management system) +# when you don't want to edit a configuration file. +SLAPD_SENTINEL_FILE=/etc/ldap/noslapd + +# For Kerberos authentication (via SASL), slapd by default uses the system +# keytab file (/etc/krb5.keytab). To use a different keytab file, +# uncomment this line and change the path. +#export KRB5_KTNAME=/etc/krb5.keytab + +# Additional options to pass to slapd +SLAPD_OPTIONS="" diff --git a/data/templates/slapd/sudo.schema b/data/templates/slapd/sudo.schema new file mode 100644 index 00000000..d3e95e00 --- /dev/null +++ b/data/templates/slapd/sudo.schema @@ -0,0 +1,76 @@ +# +# OpenLDAP schema file for Sudo +# Save as /etc/openldap/schema/sudo.schema +# + +attributetype ( 1.3.6.1.4.1.15953.9.1.1 + NAME 'sudoUser' + DESC 'User(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.2 + NAME 'sudoHost' + DESC 'Host(s) who may run sudo' + EQUALITY caseExactIA5Match + SUBSTR caseExactIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.3 + NAME 'sudoCommand' + DESC 'Command(s) to be executed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.4 + NAME 'sudoRunAs' + DESC 'User(s) impersonated by sudo (deprecated)' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.5 + NAME 'sudoOption' + DESC 'Options(s) followed by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.6 + NAME 'sudoRunAsUser' + DESC 'User(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.7 + NAME 'sudoRunAsGroup' + DESC 'Group(s) impersonated by sudo' + EQUALITY caseExactIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.8 + NAME 'sudoNotBefore' + DESC 'Start of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +attributetype ( 1.3.6.1.4.1.15953.9.1.9 + NAME 'sudoNotAfter' + DESC 'End of time interval for which the entry is valid' + EQUALITY generalizedTimeMatch + ORDERING generalizedTimeOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 ) + +attributeTypes ( 1.3.6.1.4.1.15953.9.1.10 + NAME 'sudoOrder' + DESC 'an integer to order the sudoRole entries' + EQUALITY integerMatch + ORDERING integerOrderingMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +objectclass ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL + DESC 'Sudoer Entries' + MUST ( cn ) + MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ sudoOrder $ sudoNotBefore $ sudoNotAfter $ + description ) + ) diff --git a/data/templates/spamassassin/local.cf b/data/templates/spamassassin/local.cf new file mode 100644 index 00000000..bc37b3a6 --- /dev/null +++ b/data/templates/spamassassin/local.cf @@ -0,0 +1,94 @@ +# This is the right place to customize your installation of SpamAssassin. +report_safe 0 +lock_method flock + +# Bayes-related operations +use_bayes 1 +use_bayes_rules 1 +bayes_auto_learn 1 +bayes_auto_expire 1 +bayes_path /var/lib/amavis/.spamassassin/bayes +bayes_file_mode 0777 + +# External network tests +dns_available yes +skip_rbl_checks 0 +use_razor2 1 +use_pyzor 1 + +# Use URIBL (http://www.uribl.com/about.shtml) +urirhssub URIBL_BLACK multi.uribl.com. A 2 +body URIBL_BLACK eval:check_uridnsbl('URIBL_BLACK') +describe URIBL_BLACK Contains an URL listed in the URIBL blacklist +tflags URIBL_BLACK net +score URIBL_BLACK 3.0 + +urirhssub URIBL_GREY multi.uribl.com. A 4 +body URIBL_GREY eval:check_uridnsbl('URIBL_GREY') +describe URIBL_GREY Contains an URL listed in the URIBL greylist +tflags URIBL_GREY net +score URIBL_GREY 0.25 + +# Use SURBL (http://www.surbl.org/) +urirhssub URIBL_JP_SURBL multi.surbl.org. A 64 +body URIBL_JP_SURBL eval:check_uridnsbl('URIBL_JP_SURBL') +describe URIBL_JP_SURBL Has URI in JP at http://www.surbl.org/lists.html +tflags URIBL_JP_SURBL net +score URIBL_JP_SURBL 3.0 + + +score SPF_FAIL 10.000 +score SPF_HELO_FAIL 10.000 +score RAZOR2_CHECK 2.500 +score RAZOR2_CF_RANGE_51_100 3.500 +# +# See 'perldoc Mail::SpamAssassin::Conf' for details of what can be +# tweaked. +# +# Only a small subset of options are listed below +# +########################################################################### + +# Add *****SPAM***** to the Subject header of spam e-mails +# +# rewrite_header Subject *****SPAM***** + + +# Save spam messages as a message/rfc822 MIME attachment instead of +# modifying the original message (0: off, 2: use text/plain instead) +# +# report_safe 1 + + +# Set which networks or hosts are considered 'trusted' by your mail +# server (i.e. not spammers) +# +# trusted_networks 212.17.35. + + +# Set file-locking method (flock is not safe over NFS, but is faster) +# +# lock_method flock + + +# Set the threshold at which a message is considered spam (default: 5.0) +# +# required_score 5.0 + + +# Use Bayesian classifier (default: 1) +# +# use_bayes 1 + + +# Bayesian classifier auto-learning (default: 1) +# +# bayes_auto_learn 1 + + +# Set headers which may provide inappropriate cues to the Bayesian +# classifier +# +# bayes_ignore_header X-Bogosity +# bayes_ignore_header X-Spam-Flag +# bayes_ignore_header X-Spam-Status diff --git a/data/templates/spamassassin/spamassassin.default b/data/templates/spamassassin/spamassassin.default new file mode 100644 index 00000000..da1b3311 --- /dev/null +++ b/data/templates/spamassassin/spamassassin.default @@ -0,0 +1,31 @@ +# /etc/default/spamassassin +# Duncan Findlay + +# WARNING: please read README.spamd before using. +# There may be security risks. + +# Change to one to enable spamd +ENABLED=0 + +# Options +# See man spamd for possible options. The -d option is automatically added. + +# SpamAssassin uses a preforking model, so be careful! You need to +# make sure --max-children is not set to anything higher than 5, +# unless you know what you're doing. + +OPTIONS="--create-prefs --max-children 5 --helper-home-dir" + +# Pid file +# Where should spamd write its PID to file? If you use the -u or +# --username option above, this needs to be writable by that user. +# Otherwise, the init script will not be able to shut spamd down. +PIDFILE="/var/run/spamd.pid" + +# Set nice level of spamd +#NICE="--nicelevel 15" + +# Cronjob +# Set to anything but 0 to enable the cron job to automatically update +# spamassassin's rules on a nightly basis +CRON=1 diff --git a/data/templates/ssh/sshd_config b/data/templates/ssh/sshd_config new file mode 100644 index 00000000..695ea0d3 --- /dev/null +++ b/data/templates/ssh/sshd_config @@ -0,0 +1,93 @@ +# Package generated configuration file +# See the sshd_config(5) manpage for details + +# What ports, IPs and protocols we listen for +Port 22 +# Use these options to restrict which interfaces/protocols sshd will bind to +ListenAddress :: +ListenAddress 0.0.0.0 +Protocol 2 +# HostKeys for protocol version 2 +HostKey /etc/ssh/ssh_host_rsa_key +HostKey /etc/ssh/ssh_host_dsa_key +#Privilege Separation is turned on for security +UsePrivilegeSeparation yes + +# Lifetime and size of ephemeral version 1 server key +KeyRegenerationInterval 3600 +ServerKeyBits 768 + +# Logging +SyslogFacility AUTH +LogLevel INFO + +# Authentication: +LoginGraceTime 120 +PermitRootLogin no +StrictModes yes + +RSAAuthentication yes +PubkeyAuthentication yes +#AuthorizedKeysFile %h/.ssh/authorized_keys + +# Don't read the user's ~/.rhosts and ~/.shosts files +IgnoreRhosts yes +# For this to work you will also need host keys in /etc/ssh_known_hosts +RhostsRSAAuthentication no +# similar for protocol version 2 +HostbasedAuthentication no +# Uncomment if you don't trust ~/.ssh/known_hosts for RhostsRSAAuthentication +#IgnoreUserKnownHosts yes + +# To enable empty passwords, change to yes (NOT RECOMMENDED) +PermitEmptyPasswords no + +# Change to yes to enable challenge-response passwords (beware issues with +# some PAM modules and threads) +ChallengeResponseAuthentication no + +# Change to no to disable tunnelled clear text passwords +#PasswordAuthentication yes + +# Kerberos options +#KerberosAuthentication no +#KerberosGetAFSToken no +#KerberosOrLocalPasswd yes +#KerberosTicketCleanup yes + +# GSSAPI options +#GSSAPIAuthentication no +#GSSAPICleanupCredentials yes + +X11Forwarding yes +X11DisplayOffset 10 +PrintMotd no +PrintLastLog yes +TCPKeepAlive yes +#UseLogin no + +#MaxStartups 10:30:60 +Banner /etc/issue.net + +# Allow client to pass locale environment variables +AcceptEnv LANG LC_* + +Subsystem sftp internal-sftp + +# Set this to 'yes' to enable PAM authentication, account processing, +# and session processing. If this is enabled, PAM authentication will +# be allowed through the ChallengeResponseAuthentication and +# PasswordAuthentication. Depending on your PAM configuration, +# PAM authentication via ChallengeResponseAuthentication may bypass +# the setting of "PermitRootLogin without-password". +# If you just want the PAM account and session checks to run without +# PAM authentication, then enable this but set PasswordAuthentication +# and ChallengeResponseAuthentication to 'no'. +UsePAM yes + +Match User sftpusers + ForceCommand internal-sftp + ChrootDirectory /home/%u + AllowTcpForwarding no + GatewayPorts no + X11Forwarding no diff --git a/data/templates/ssl/openssl.cnf b/data/templates/ssl/openssl.cnf new file mode 100644 index 00000000..fa5d19fa --- /dev/null +++ b/data/templates/ssl/openssl.cnf @@ -0,0 +1,293 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = /usr/share/yunohost/yunohost-config/ssl +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = Yunohost # The default ca section + +#################################################################### +[ Yunohost ] + +dir = /usr/share/yunohost/yunohost-config/ssl/yunoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/ca/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +#crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/ca/cakey.pem # The private key +RANDFILE = $dir/ca/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 3650 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha256 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 2048 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +commonName = Common Name (eg, YOUR name) +commonName_max = 64 +commonName_default = yunohost.org + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +subjectAltName=DNS:yunohost.org,DNS:www.yunohost.org,DNS:ns.yunohost.org + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff --git a/data/templates/udisks-glue/udisks-glue.conf b/data/templates/udisks-glue/udisks-glue.conf new file mode 100644 index 00000000..f97de948 --- /dev/null +++ b/data/templates/udisks-glue/udisks-glue.conf @@ -0,0 +1,9 @@ +filter disks { + optical = false + partition_table = false + usage = filesystem +} +match disks { + automount=true + automount_options= { sync, noatime, "dmask=0", "fmask=0" } +} diff --git a/data/templates/unattended/02periodic b/data/templates/unattended/02periodic new file mode 100644 index 00000000..c3ec9291 --- /dev/null +++ b/data/templates/unattended/02periodic @@ -0,0 +1,6 @@ +02periodic 50unattended-upgrades +root@65ba01d0c078:/usr/share/yunohost/yunohost-config/unattended# cat 02periodic +APT::Periodic::Enable "1"; +APT::Periodic::Update-Package-Lists "1"; +APT::Periodic::Unattended-Upgrade "1"; +APT::Periodic::Verbose "1"; diff --git a/data/templates/unattended/50unattended-upgrades b/data/templates/unattended/50unattended-upgrades new file mode 100644 index 00000000..49b600a3 --- /dev/null +++ b/data/templates/unattended/50unattended-upgrades @@ -0,0 +1,36 @@ +// Automatically upgrade packages from these (origin, archive) pairs +Unattended-Upgrade::Allowed-Origins { + "${distro_id} stable"; + "${distro_id} testing"; + "Depot-Debian testing"; + "${distro_id} ${distro_codename}-security"; + "${distro_id} ${distro_codename}-updates"; +// "${distro_id} ${distro_codename}-proposed-updates"; +}; + +// List of packages to not update +Unattended-Upgrade::Package-Blacklist { +// "vim"; +// "libc6"; +// "libc6-dev"; +// "libc6-i686"; +}; + +// Send email to this address for problems or packages upgrades +// If empty or unset then no email is sent, make sure that you +// have a working mail setup on your system. The package 'mailx' +// must be installed or anything that provides /usr/bin/mail. +//Unattended-Upgrade::Mail "root@localhost"; + +// Do automatic removal of new unused dependencies after the upgrade +// (equivalent to apt-get autoremove) +Unattended-Upgrade::Remove-Unused-Dependencies "true"; + +// Automatically reboot *WITHOUT CONFIRMATION* if a +// the file /var/run/reboot-required is found after the upgrade +Unattended-Upgrade::Automatic-Reboot "false"; + + +// Use apt bandwidth limit feature, this example limits the download +// speed to 70kb/sec +//Acquire::http::Dl-Limit "70"; diff --git a/data/other/firewall.yml b/data/templates/yunohost/firewall.yml similarity index 100% rename from data/other/firewall.yml rename to data/templates/yunohost/firewall.yml diff --git a/data/other/services.yml b/data/templates/yunohost/services.yml similarity index 83% rename from data/other/services.yml rename to data/templates/yunohost/services.yml index c183be54..c015c8cd 100644 --- a/data/other/services.yml +++ b/data/templates/yunohost/services.yml @@ -39,3 +39,13 @@ postgrey: amavis: status: service log: /var/log/mail.log +nslcd: + status: service + log: /var/log/syslog +nsswitch: + status: service +spamassassin: + status: service + log: /var/log/mail.log +udisks-glue: + status: service diff --git a/debian/control b/debian/control index 89149ef8..3926f72f 100644 --- a/debian/control +++ b/debian/control @@ -1,14 +1,15 @@ -Source: moulinette-yunohost -Section: net +Source: yunohost +Section: utils Priority: extra -Maintainer: Jérôme Lebleu -Build-Depends: debhelper (>=8.0.0) -Standards-Version: 3.9.4 +Maintainer: YunoHost Contributors +Build-Depends: debhelper (>=9), dh-systemd +Standards-Version: 3.9.6 Homepage: https://yunohost.org/ -Package: moulinette-yunohost +Package: yunohost Architecture: all -Depends: moulinette (>= 2.2.1), +Depends: ${misc:Depends}, ${shlibs:Depends}, + moulinette (>= 2.2.1), python-psutil, python-requests, glances, @@ -25,6 +26,23 @@ Depends: moulinette (>= 2.2.1), git-core, curl, mariadb-server | mysql-server, php5-mysql | php5-mysqlnd + slapd, ldap-utils, sudo-ldap, libnss-ldapd, + postfix-ldap, postfix-policyd-spf-perl, postfix-pcre, postgrey, + dovecot-ldap, dovecot-lmtpd, dovecot-managesieved, + amavisd-new, razor, pyzor, dovecot-antispam, spamassassin, fail2ban, + nginx-extras (>=1.6.2), php5-fpm, php5-ldap, php5-intl, + dnsmasq, openssl, avahi-daemon, + ssowat, metronome +Recommends: yunohost-admin, + bash-completion, rsyslog, ntp, openssh-server, + php5-gd, php5-curl, php-gettext, php5-mcrypt, + udisks-glue, unattended-upgrades, + libdbd-ldap-perl, libnet-dns-perl +Suggests: htop, vim, rsync, acpi-support-base Conflicts: iptables-persistent -Description: YunoHost Python scripts - Python functions to manage a YunoHost instance +Description: YunoHost installation package + YunoHost aims to make self-hosting accessible to everyone. + . + This package contains YunoHost scripts and binaries to be used by the + moulinette. It allows to manage the server with a command-line tool and + an API. diff --git a/debian/copyright b/debian/copyright index d159169d..8dd627ca 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,339 +1,678 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Source: https://github.com/YunoHost/moulinette-yunohost - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +Files: * +Copyright: 2015 YUNOHOST.ORG +License: AGPL-3 + +License: AGPL-3 + OPA is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License, version 3, as published by + the Free Software Foundation. + . + OPA 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. + . + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + . + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 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 General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. + . + Preamble + . + The GNU Affero General Public License is a free, copyleft license for + software and other kinds of works, specifically designed to ensure + cooperation with the community in the case of network server software. + . + The licenses for most software and other practical works are designed + to take away your freedom to share and change the works. By contrast, + our General Public Licenses are intended to guarantee your freedom to + share and change all versions of a program--to make sure it remains free + software for all its users. + . + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + them if you wish), that you receive source code or can get it if you + want it, that you can change the software or use pieces of it in new + free programs, and that you know you can do these things. + . + Developers that use our General Public Licenses protect your rights + with two steps: (1) assert copyright on the software, and (2) offer + you this License which gives you legal permission to copy, distribute + and/or modify the software. + . + A secondary benefit of defending all users' freedom is that + improvements made in alternate versions of the program, if they + receive widespread use, become available for other developers to + incorporate. Many developers of free software are heartened and + encouraged by the resulting cooperation. However, in the case of + software used on network servers, this result may fail to come about. + The GNU General Public License permits making a modified version and + letting the public access it on a server without ever releasing its + source code to the public. + . + The GNU Affero General Public License is designed specifically to + ensure that, in such cases, the modified source code becomes available + to the community. It requires the operator of a network server to + provide the source code of the modified version running there to the + users of that server. Therefore, public use of a modified version, on + a publicly accessible server, gives the public access to the source + code of the modified version. + . + An older license, called the Affero General Public License and + published by Affero, was designed to accomplish similar goals. This is + a different license, not a version of the Affero GPL, but Affero has + released a new version of the Affero GPL which permits relicensing under + this license. + . + The precise terms and conditions for copying, distribution and + modification follow. + . + TERMS AND CONDITIONS + . + 0. Definitions. + . + "This License" refers to version 3 of the GNU Affero General Public License. + . + "Copyright" also means copyright-like laws that apply to other kinds of + works, such as semiconductor masks. + . + "The Program" refers to any copyrightable work licensed under this + License. Each licensee is addressed as "you". "Licensees" and + "recipients" may be individuals or organizations. + . + To "modify" a work means to copy from or adapt all or part of the work + in a fashion requiring copyright permission, other than the making of an + exact copy. The resulting work is called a "modified version" of the + earlier work or a work "based on" the earlier work. + . + A "covered work" means either the unmodified Program or a work based + on the Program. + . + To "propagate" a work means to do anything with it that, without + permission, would make you directly or secondarily liable for + infringement under applicable copyright law, except executing it on a + computer or modifying a private copy. Propagation includes copying, + distribution (with or without modification), making available to the + public, and in some countries other activities as well. + . + To "convey" a work means any kind of propagation that enables other + parties to make or receive copies. Mere interaction with a user through + a computer network, with no transfer of a copy, is not conveying. + . + An interactive user interface displays "Appropriate Legal Notices" + to the extent that it includes a convenient and prominently visible + feature that (1) displays an appropriate copyright notice, and (2) + tells the user that there is no warranty for the work (except to the + extent that warranties are provided), that licensees may convey the + work under this License, and how to view a copy of this License. If + the interface presents a list of user commands or options, such as a + menu, a prominent item in the list meets this criterion. + . + 1. Source Code. + . + The "source code" for a work means the preferred form of the work + for making modifications to it. "Object code" means any non-source + form of a work. + . + A "Standard Interface" means an interface that either is an official + standard defined by a recognized standards body, or, in the case of + interfaces specified for a particular programming language, one that + is widely used among developers working in that language. + . + The "System Libraries" of an executable work include anything, other + than the work as a whole, that (a) is included in the normal form of + packaging a Major Component, but which is not part of that Major + Component, and (b) serves only to enable use of the work with that + Major Component, or to implement a Standard Interface for which an + implementation is available to the public in source code form. A + "Major Component", in this context, means a major essential component + (kernel, window system, and so on) of the specific operating system + (if any) on which the executable work runs, or a compiler used to + produce the work, or an object code interpreter used to run it. + . + The "Corresponding Source" for a work in object code form means all + the source code needed to generate, install, and (for an executable + work) run the object code and to modify the work, including scripts to + control those activities. However, it does not include the work's + System Libraries, or general-purpose tools or generally available free + programs which are used unmodified in performing those activities but + which are not part of the work. For example, Corresponding Source + includes interface definition files associated with source files for + the work, and the source code for shared libraries and dynamically + linked subprograms that the work is specifically designed to require, + such as by intimate data communication or control flow between those + subprograms and other parts of the work. + . + The Corresponding Source need not include anything that users + can regenerate automatically from other parts of the Corresponding + Source. + . + The Corresponding Source for a work in source code form is that + same work. + . + 2. Basic Permissions. + . + All rights granted under this License are granted for the term of + copyright on the Program, and are irrevocable provided the stated + conditions are met. This License explicitly affirms your unlimited + permission to run the unmodified Program. The output from running a + covered work is covered by this License only if the output, given its + content, constitutes a covered work. This License acknowledges your + rights of fair use or other equivalent, as provided by copyright law. + . + You may make, run and propagate covered works that you do not + convey, without conditions so long as your license otherwise remains + in force. You may convey covered works to others for the sole purpose + of having them make modifications exclusively for you, or provide you + with facilities for running those works, provided that you comply with + the terms of this License in conveying all material for which you do + not control copyright. Those thus making or running the covered works + for you must do so exclusively on your behalf, under your direction + and control, on terms that prohibit them from making any copies of + your copyrighted material outside their relationship with you. + . + Conveying under any other circumstances is permitted solely under + the conditions stated below. Sublicensing is not allowed; section 10 + makes it unnecessary. + . + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + . + No covered work shall be deemed part of an effective technological + measure under any applicable law fulfilling obligations under article + 11 of the WIPO copyright treaty adopted on 20 December 1996, or + similar laws prohibiting or restricting circumvention of such + measures. + . + When you convey a covered work, you waive any legal power to forbid + circumvention of technological measures to the extent such circumvention + is effected by exercising rights under this License with respect to + the covered work, and you disclaim any intention to limit operation or + modification of the work as a means of enforcing, against the work's + users, your or third parties' legal rights to forbid circumvention of + technological measures. + . + 4. Conveying Verbatim Copies. + . + You may convey verbatim copies of the Program's source code as you + receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice; + keep intact all notices stating that this License and any + non-permissive terms added in accord with section 7 apply to the code; + keep intact all notices of the absence of any warranty; and give all + recipients a copy of this License along with the Program. + . + You may charge any price or no price for each copy that you convey, + and you may offer support or warranty protection for a fee. + . + 5. Conveying Modified Source Versions. + . + You may convey a work based on the Program, or the modifications to + produce it from the Program, in the form of source code under the + terms of section 4, provided that you also meet all of these conditions: + . + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + . + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + . + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + . + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + . + A compilation of a covered work with other separate and independent + works, which are not by their nature extensions of the covered work, + and which are not combined with it such as to form a larger program, + in or on a volume of a storage or distribution medium, is called an + "aggregate" if the compilation and its resulting copyright are not + used to limit the access or legal rights of the compilation's users + beyond what the individual works permit. Inclusion of a covered work + in an aggregate does not cause this License to apply to the other + parts of the aggregate. + . + 6. Conveying Non-Source Forms. + . + You may convey a covered work in object code form under the terms + of sections 4 and 5, provided that you also convey the + machine-readable Corresponding Source under the terms of this License, + in one of these ways: + . + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + . + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + . + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + . + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + . + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + . + A separable portion of the object code, whose source code is excluded + from the Corresponding Source as a System Library, need not be + included in conveying the object code work. + . + A "User Product" is either (1) a "consumer product", which means any + tangible personal property which is normally used for personal, family, + or household purposes, or (2) anything designed or sold for incorporation + into a dwelling. In determining whether a product is a consumer product, + doubtful cases shall be resolved in favor of coverage. For a particular + product received by a particular user, "normally used" refers to a + typical or common use of that class of product, regardless of the status + of the particular user or of the way in which the particular user + actually uses, or expects or is expected to use, the product. A product + is a consumer product regardless of whether the product has substantial + commercial, industrial or non-consumer uses, unless such uses represent + the only significant mode of use of the product. + . + "Installation Information" for a User Product means any methods, + procedures, authorization keys, or other information required to install + and execute modified versions of a covered work in that User Product from + a modified version of its Corresponding Source. The information must + suffice to ensure that the continued functioning of the modified object + code is in no case prevented or interfered with solely because + modification has been made. + . + If you convey an object code work under this section in, or with, or + specifically for use in, a User Product, and the conveying occurs as + part of a transaction in which the right of possession and use of the + User Product is transferred to the recipient in perpetuity or for a + fixed term (regardless of how the transaction is characterized), the + Corresponding Source conveyed under this section must be accompanied + by the Installation Information. But this requirement does not apply + if neither you nor any third party retains the ability to install + modified object code on the User Product (for example, the work has + been installed in ROM). + . + The requirement to provide Installation Information does not include a + requirement to continue to provide support service, warranty, or updates + for a work that has been modified or installed by the recipient, or for + the User Product in which it has been modified or installed. Access to a + network may be denied when the modification itself materially and + adversely affects the operation of the network or violates the rules and + protocols for communication across the network. + . + Corresponding Source conveyed, and Installation Information provided, + in accord with this section must be in a format that is publicly + documented (and with an implementation available to the public in + source code form), and must require no special password or key for + unpacking, reading or copying. + . + 7. Additional Terms. + . + "Additional permissions" are terms that supplement the terms of this + License by making exceptions from one or more of its conditions. + Additional permissions that are applicable to the entire Program shall + be treated as though they were included in this License, to the extent + that they are valid under applicable law. If additional permissions + apply only to part of the Program, that part may be used separately + under those permissions, but the entire Program remains governed by + this License without regard to the additional permissions. + . + When you convey a copy of a covered work, you may at your option + remove any additional permissions from that copy, or from any part of + it. (Additional permissions may be written to require their own + removal in certain cases when you modify the work.) You may place + additional permissions on material, added by you to a covered work, + for which you have or can give appropriate copyright permission. + . + Notwithstanding any other provision of this License, for material you + add to a covered work, you may (if authorized by the copyright holders of + that material) supplement the terms of this License with terms: + . + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + . + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + . + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + . + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + . + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + . + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + . + All other non-permissive additional terms are considered "further + restrictions" within the meaning of section 10. If the Program as you + received it, or any part of it, contains a notice stating that it is + governed by this License along with a term that is a further + restriction, you may remove that term. If a license document contains + a further restriction but permits relicensing or conveying under this + License, you may add to a covered work material governed by the terms + of that license document, provided that the further restriction does + not survive such relicensing or conveying. + . + If you add terms to a covered work in accord with this section, you + must place, in the relevant source files, a statement of the + additional terms that apply to those files, or a notice indicating + where to find the applicable terms. + . + Additional terms, permissive or non-permissive, may be stated in the + form of a separately written license, or stated as exceptions; + the above requirements apply either way. + . + 8. Termination. + . + You may not propagate or modify a covered work except as expressly + provided under this License. Any attempt otherwise to propagate or + modify it is void, and will automatically terminate your rights under + this License (including any patent licenses granted under the third + paragraph of section 11). + . + However, if you cease all violation of this License, then your + license from a particular copyright holder is reinstated (a) + provisionally, unless and until the copyright holder explicitly and + finally terminates your license, and (b) permanently, if the copyright + holder fails to notify you of the violation by some reasonable means + prior to 60 days after the cessation. + . + Moreover, your license from a particular copyright holder is + reinstated permanently if the copyright holder notifies you of the + violation by some reasonable means, this is the first time you have + received notice of violation of this License (for any work) from that + copyright holder, and you cure the violation prior to 30 days after + your receipt of the notice. + . + Termination of your rights under this section does not terminate the + licenses of parties who have received copies or rights from you under + this License. If your rights have been terminated and not permanently + reinstated, you do not qualify to receive new licenses for the same + material under section 10. + . + 9. Acceptance Not Required for Having Copies. + . + You are not required to accept this License in order to receive or + run a copy of the Program. Ancillary propagation of a covered work + occurring solely as a consequence of using peer-to-peer transmission + to receive a copy likewise does not require acceptance. However, + nothing other than this License grants you permission to propagate or + modify any covered work. These actions infringe copyright if you do + not accept this License. Therefore, by modifying or propagating a + covered work, you indicate your acceptance of this License to do so. + . + 10. Automatic Licensing of Downstream Recipients. + . + Each time you convey a covered work, the recipient automatically + receives a license from the original licensors, to run, modify and + propagate that work, subject to this License. You are not responsible + for enforcing compliance by third parties with this License. + . + An "entity transaction" is a transaction transferring control of an + organization, or substantially all assets of one, or subdividing an + organization, or merging organizations. If propagation of a covered + work results from an entity transaction, each party to that + transaction who receives a copy of the work also receives whatever + licenses to the work the party's predecessor in interest had or could + give under the previous paragraph, plus a right to possession of the + Corresponding Source of the work from the predecessor in interest, if + the predecessor has it or can get it with reasonable efforts. + . + You may not impose any further restrictions on the exercise of the + rights granted or affirmed under this License. For example, you may + not impose a license fee, royalty, or other charge for exercise of + rights granted under this License, and you may not initiate litigation + (including a cross-claim or counterclaim in a lawsuit) alleging that + any patent claim is infringed by making, using, selling, offering for + sale, or importing the Program or any portion of it. + . + 11. Patents. + . + A "contributor" is a copyright holder who authorizes use under this + License of the Program or a work on which the Program is based. The + work thus licensed is called the contributor's "contributor version". + . + A contributor's "essential patent claims" are all patent claims + owned or controlled by the contributor, whether already acquired or + hereafter acquired, that would be infringed by some manner, permitted + by this License, of making, using, or selling its contributor version, + but do not include claims that would be infringed only as a + consequence of further modification of the contributor version. For + purposes of this definition, "control" includes the right to grant + patent sublicenses in a manner consistent with the requirements of + this License. + . + Each contributor grants you a non-exclusive, worldwide, royalty-free + patent license under the contributor's essential patent claims, to + make, use, sell, offer for sale, import and otherwise run, modify and + propagate the contents of its contributor version. + . + In the following three paragraphs, a "patent license" is any express + agreement or commitment, however denominated, not to enforce a patent + (such as an express permission to practice a patent or covenant not to + sue for patent infringement). To "grant" such a patent license to a + party means to make such an agreement or commitment not to enforce a + patent against the party. + . + If you convey a covered work, knowingly relying on a patent license, + and the Corresponding Source of the work is not available for anyone + to copy, free of charge and under the terms of this License, through a + publicly available network server or other readily accessible means, + then you must either (1) cause the Corresponding Source to be so + available, or (2) arrange to deprive yourself of the benefit of the + patent license for this particular work, or (3) arrange, in a manner + consistent with the requirements of this License, to extend the patent + license to downstream recipients. "Knowingly relying" means you have + actual knowledge that, but for the patent license, your conveying the + covered work in a country, or your recipient's use of the covered work + in a country, would infringe one or more identifiable patents in that + country that you have reason to believe are valid. + . + If, pursuant to or in connection with a single transaction or + arrangement, you convey, or propagate by procuring conveyance of, a + covered work, and grant a patent license to some of the parties + receiving the covered work authorizing them to use, propagate, modify + or convey a specific copy of the covered work, then the patent license + you grant is automatically extended to all recipients of the covered + work and works based on it. + . + A patent license is "discriminatory" if it does not include within + the scope of its coverage, prohibits the exercise of, or is + conditioned on the non-exercise of one or more of the rights that are + specifically granted under this License. You may not convey a covered + work if you are a party to an arrangement with a third party that is + in the business of distributing software, under which you make payment + to the third party based on the extent of your activity of conveying + the work, and under which the third party grants, to any of the + parties who would receive the covered work from you, a discriminatory + patent license (a) in connection with copies of the covered work + conveyed by you (or copies made from those copies), or (b) primarily + for and in connection with specific products or compilations that + contain the covered work, unless you entered into that arrangement, + or that patent license was granted, prior to 28 March 2007. + . + Nothing in this License shall be construed as excluding or limiting + any implied license or other defenses to infringement that may + otherwise be available to you under applicable patent law. + . + 12. No Surrender of Others' Freedom. + . + If conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot convey a + covered work so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you may + not convey it at all. For example, if you agree to terms that obligate you + to collect a royalty for further conveying from those to whom you convey + the Program, the only way you could satisfy both those terms and this + License would be to refrain entirely from conveying the Program. + . + 13. Remote Network Interaction; Use with the GNU General Public License. + . + Notwithstanding any other provision of this License, if you modify the + Program, your modified version must prominently offer all users + interacting with it remotely through a computer network (if your version + supports such interaction) an opportunity to receive the Corresponding + Source of your version by providing access to the Corresponding Source + from a network server at no charge, through some standard or customary + means of facilitating copying of software. This Corresponding Source + shall include the Corresponding Source for any work covered by version 3 + of the GNU General Public License that is incorporated pursuant to the + following paragraph. + . + Notwithstanding any other provision of this License, you have + permission to link or combine any covered work with a work licensed + under version 3 of the GNU General Public License into a single + combined work, and to convey the resulting work. The terms of this + License will continue to apply to the part which is the covered work, + but the work with which it is combined will remain governed by version + 3 of the GNU General Public License. + . + 14. Revised Versions of this License. + . + The Free Software Foundation may publish revised and/or new versions of + the GNU Affero General Public License from time to time. Such new versions + will be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + . + Each version is given a distinguishing version number. If the + Program specifies that a certain numbered version of the GNU Affero General + Public License "or any later version" applies to it, you have the + option of following the terms and conditions either of that numbered + version or of any later version published by the Free Software + Foundation. If the Program does not specify a version number of the + GNU Affero General Public License, you may choose any version ever published + by the Free Software Foundation. + . + If the Program specifies that a proxy can decide which future + versions of the GNU Affero General Public License can be used, that proxy's + public statement of acceptance of a version permanently authorizes you + to choose that version for the Program. + . + Later license versions may give you additional or different + permissions. However, no additional obligations are imposed on any + author or copyright holder as a result of your choosing to follow a + later version. + . + 15. Disclaimer of Warranty. + . + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY + APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT + HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY + OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM + IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF + ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + . + 16. Limitation of Liability. + . + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS + THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY + GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE + USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF + DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD + PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), + EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF + SUCH DAMAGES. + . + 17. Interpretation of Sections 15 and 16. + . + If the disclaimer of warranty and limitation of liability provided + above cannot be given local legal effect according to their terms, + reviewing courts shall apply local law that most closely approximates + an absolute waiver of all civil liability in connection with the + Program, unless a warranty or assumption of liability accompanies a + copy of the Program in return for a fee. + . + END OF TERMS AND CONDITIONS + . + How to Apply These Terms to Your New Programs + . + If you develop a new program, and you want it to be of the greatest + possible use to the public, the best way to achieve this is to make it + free software which everyone can redistribute and change under these terms. + . + To do so, attach the following notices to the program. It is safest + to attach them to the start of each source file to most effectively + state the exclusion of warranty; and each file should have at least + the "copyright" line and a pointer to where the full notice is found. + . + + Copyright (C) + . + 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 . + . + Also add information on how to contact you by electronic and paper mail. + . + If your software can interact with users remotely through a computer + network, you should also make sure that it provides a way for users to + get its source. For example, if your program is a web application, its + interface could display a "Source" link that leads users to an archive + of the code. There are many ways you could offer source, and different + solutions will be better for different programs; see section 13 for the + specific requirements. + . + You should also get your employer (if you work as a programmer) or school, + if any, to sign a "copyright disclaimer" for the program, if necessary. + For more information on this, and how to apply and follow the GNU AGPL, see + . diff --git a/debian/install b/debian/install index 4c91fbd4..772027be 100644 --- a/debian/install +++ b/debian/install @@ -2,6 +2,7 @@ bin/* /usr/bin/ data/actionsmap/* /usr/share/moulinette/actionsmap/ data/hooks/* /usr/share/yunohost/hooks/ data/other/* /usr/share/yunohost/yunohost-config/moulinette/ +data/templates/* /usr/share/yunohost/templates/ data/apps/* /usr/share/yunohost/apps/ lib/yunohost/*.py /usr/lib/moulinette/yunohost/ locales/* /usr/lib/moulinette/yunohost/locales/ diff --git a/debian/postinst b/debian/postinst index 3106cfed..2a13c8e8 100644 --- a/debian/postinst +++ b/debian/postinst @@ -3,62 +3,16 @@ set -e do_configure() { - TMP=/usr/share/yunohost/yunohost-config/moulinette - - if [ ! -d /etc/yunohost ]; - then - mkdir -p /etc/yunohost - fi - - # Allow users to access /media directory - if [ ! -d /etc/skel/media ]; - then - mkdir -p /media - ln -s /media /etc/skel/ - fi - - #Firewall - grep -q "UPNP:" /etc/yunohost/firewall.yml > /dev/null 2>&1 - if [[ $? -eq 0 ]] || [ ! -f /etc/yunohost/firewall.yml ]; - then - cp $TMP/firewall.yml /etc/yunohost/ - fi - - # App fetchlist - if [ -f /etc/cron.d/yunohost-applist-yunohost ]; - then - sed -i "s/--no-ldap //g" /etc/cron.d/yunohost-applist-yunohost - fi - - # Service list - if [ ! -f /etc/yunohost/services.yml ]; - then - cp $TMP/services.yml /etc/yunohost/ - fi - - # Stop old API - ps aux | grep "yunohost.tac" | grep -qv grep - if [[ $? -eq 0 ]]; - then - killall twistd - fi - rm -rf /var/cache/moulinette/* - update-rc.d yunohost-api defaults > /dev/null service yunohost-api restart - # Firewall - update-rc.d yunohost-firewall defaults > /dev/null - - # Reload SSOwat conf if obsolete - if [ -f /etc/yunohost/installed ]; - then - yunohost firewall upnp | grep -qi "true" - if [[ $? -eq 0 ]]; - then - yunohost firewall upnp enable - fi - yunohost app ssowatconf + if [ ! -f /etc/yunohost/installed ]; then + bash /usr/share/yunohost/hooks/conf_regen/01-yunohost + bash /usr/share/yunohost/hooks/conf_regen/02-ssl + bash /usr/share/yunohost/hooks/conf_regen/06-slapd + bash /usr/share/yunohost/hooks/conf_regen/15-nginx + else + yunohost service regenconf fi } diff --git a/debian/preinst b/debian/preinst deleted file mode 100644 index 43850db1..00000000 --- a/debian/preinst +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -set -e - -if [ -f /etc/init.d/yunohost-api ]; then - service yunohost-api stop -# nc -zv 127.0.0.1 6787 < /dev/null 2> /dev/null -# if [[ ! $? -eq 0 ]]; -# then -# exit 1 -# fi -fi diff --git a/debian/rules b/debian/rules index 794068d8..5de55b6d 100755 --- a/debian/rules +++ b/debian/rules @@ -5,7 +5,7 @@ #export DH_VERBOSE=1 %: - dh $@ + dh ${@} --with=systemd override_dh_installinit: dh_installinit --name=yunohost-api diff --git a/debian/yunohost-api.init b/debian/yunohost-api.init index 3e75e159..0a27554d 100755 --- a/debian/yunohost-api.init +++ b/debian/yunohost-api.init @@ -1,75 +1,127 @@ -#! /bin/bash +#! /bin/sh + ### BEGIN INIT INFO # Provides: yunohost-api # Required-Start: $local_fs $remote_fs $network $syslog # Required-Stop: $local_fs $remote_fs $network $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 -# Short-Description: Start/stop YunoHost API -# Description: Start/stop YunoHost API +# Short-Description: Manage YunoHost API Server +# Description: Manage YunoHost API Server ### END INIT INFO -DAEMON=/usr/bin/yunohost-api +set -e + +DESC="YunoHost API Server" +NAME="yunohost-api" +DAEMON=/usr/bin/$NAME DAEMON_OPTS="" +PATH=/sbin:/usr/sbin:/bin:/usr/bin +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME +LOGFILE=/var/log/$NAME.log -test -x $DAEMON || exit 0 +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. . /lib/lsb/init-functions -logger "YunoHost API: Start script executed" +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --background --make-pidfile --quiet --no-close \ + --pidfile $PIDFILE --exec $DAEMON -- \ + $DAEMON_ARGS >>$LOGFILE 2>&1 \ + || return 2 +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --oknodo --pidfile $PIDFILE + RETVAL="$?" + + sleep 1 + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # Send a SIGHUP to reload the daemon. + start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME + return 0 +} case "$1" in start) - logger "YunoHost API: Starting" - log_daemon_msg "Starting API: YunoHost" - if [[ -f /etc/nginx/conf.d/openresty.conf ]]; - then - DAEMON_OPTS="--no-websocket" - fi - start-stop-daemon --start --background --pidfile /var/run/yunohost-api.pid --make-pidfile \ - --exec /bin/bash -- -c "$DAEMON $DAEMON_OPTS >> /var/log/yunohost.log 2>&1" - log_end_msg $? - ;; + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; stop) - logger "YunoHost API: Stopping" - log_daemon_msg "Stopping API: YunoHost" - if [ -f /var/run/yunohost-api.pid ]; then - kill `cat /var/run/yunohost-api.pid` > /dev/null 2>&1 - rm -f /var/run/yunohost-api.pid - fi - kill `ps aux | grep 'python /usr/bin/yunohost-api' | grep -v grep | awk '{print $2}'` > /dev/null 2>&1 - kill `ps aux | grep 'yunohost-api' | grep -v grep | grep -v stop | awk '{print $2}'` > /dev/null 2>&1 - log_end_msg 0 - ;; - restart|force-reload) - logger "YunoHost API: Restarting" - log_daemon_msg "Restarting API: YunoHost" - if [ -f /var/run/yunohost-api.pid ]; then - kill `cat /var/run/yunohost-api.pid` > /dev/null 2>&1 - rm -f /var/run/yunohost-api.pid - fi - kill `ps aux | grep 'python /usr/bin/yunohost-api' | grep -v grep | awk '{print $2}'` > /dev/null 2>&1 - kill `ps aux | grep 'yunohost-api' | grep -v grep | grep -v restart | awk '{print $2}'` > /dev/null 2>&1 - kill `ps aux | grep 'yunohost.tac' | grep -v grep | awk '{print $2}'` > /dev/null 2>&1 - if [[ -f /etc/nginx/conf.d/openresty.conf ]]; - then - DAEMON_OPTS="--no-websocket" - fi - start-stop-daemon --start --background --pidfile /var/run/yunohost-api.pid --make-pidfile \ - --exec /bin/bash -- -c "$DAEMON $DAEMON_OPTS >> /var/log/yunohost.log 2>&1" - log_end_msg $? - ;; + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; status) - logger "YunoHost API: Running" - log_daemon_msg "YunoHost API: Running" - cat /var/run/yunohost-api.pid > /dev/null 2>&1 - log_end_msg $? - ;; + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + reload) + log_daemon_msg "Reloading $DESC" "$NAME" + do_reload + log_end_msg $? + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; *) - logger "YunoHost API: Invalid usage" - echo "Usage: /etc/init.d/yunohost-api {start|stop|restart|force-reload|status}" >&2 - exit 1 - ;; + echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload}" >&2 + exit 3 + ;; esac -exit 0 +: diff --git a/debian/yunohost-api.service b/debian/yunohost-api.service new file mode 100644 index 00000000..c7a913b6 --- /dev/null +++ b/debian/yunohost-api.service @@ -0,0 +1,13 @@ +[Unit] +Description=YunoHost API Server +After=network.target + +[Service] +Type=simple +ExecStart=/usr/bin/yunohost-api +ExecReload=/bin/kill -HUP $MAINPID +Restart=always +RestartSec=1 + +[Install] +WantedBy=multi-user.target diff --git a/lib/yunohost/app.py b/lib/yunohost/app.py index 3376a7aa..454ad50b 100644 --- a/lib/yunohost/app.py +++ b/lib/yunohost/app.py @@ -70,7 +70,7 @@ def app_fetchlist(url=None, name=None): Keyword argument: name -- Name of the list (default yunohost) - url -- URL of remote JSON list (default https://app.yunohost.org/list.json) + url -- URL of remote JSON list (default https://yunohost.org/list.json) """ # Create app path if not exists @@ -78,7 +78,7 @@ def app_fetchlist(url=None, name=None): except OSError: os.makedirs(repo_path) if url is None: - url = 'https://app.yunohost.org/list.json' + url = 'https://yunohost.org/list.json' name = 'yunohost' else: if name is None: diff --git a/lib/yunohost/domain.py b/lib/yunohost/domain.py index d8880554..ee53bb39 100644 --- a/lib/yunohost/domain.py +++ b/lib/yunohost/domain.py @@ -36,11 +36,12 @@ from urllib import urlopen from moulinette.core import MoulinetteError -def domain_list(auth, filter=None, limit=None, offset=None): +def domain_list(auth, raw=False, filter=None, limit=None, offset=None): """ List domains Keyword argument: + raw -- Return domains as a bash-usable list instead of JSON filter -- LDAP filter used to search offset -- Starting number for domain fetching limit -- Maximum number of domain fetched @@ -61,7 +62,12 @@ def domain_list(auth, filter=None, limit=None, offset=None): if len(result) > offset and limit > 0: for domain in result[offset:offset+limit]: result_list.append(domain['virtualdomain'][0]) - return { 'domains': result_list } + + if raw: + for domain in result_list: + print domain + else: + return { 'domains': result_list } def domain_add(auth, domain, dyndns=False): @@ -73,6 +79,8 @@ def domain_add(auth, domain, dyndns=False): dyndns -- Subscribe to DynDNS """ + from yunohost.service import service_regenconf + attr_dict = { 'objectClass' : ['mailDomain', 'top'] } try: ip = str(urlopen('http://ip.yunohost.org').read()) @@ -148,76 +156,16 @@ def domain_add(auth, domain, dyndns=False): attr_dict['virtualdomain'] = domain - dnsmasq_config_path='/etc/dnsmasq.d' - try: - os.listdir(dnsmasq_config_path) - except OSError: - msignals.display(m18n.n('dnsmasq_isnt_installed'), - 'warning') - os.makedirs(dnsmasq_config_path) - - try: - with open('%s/%s' % (dnsmasq_config_path, domain)) as f: pass - except IOError as e: - zone_lines = [ - 'resolv-file=', - 'address=/%s/%s' % (domain, ip), - 'txt-record=%s,"v=spf1 mx a -all"' % domain, - 'mx-host=%s,%s,5' % (domain, domain), - 'srv-host=_xmpp-client._tcp.%s,%s,5222,0,5' % (domain, domain), - 'srv-host=_xmpp-server._tcp.%s,%s,5269,0,5' % (domain, domain), - 'srv-host=_jabber._tcp.%s,%s,5269,0,5' % (domain, domain), - ] - with open('%s/%s' % (dnsmasq_config_path, domain), 'w') as zone: - for line in zone_lines: - zone.write(line + '\n') - os.system('service dnsmasq restart') - - else: - msignals.display(m18n.n('domain_zone_exists'), - 'warning') - - # XMPP - try: - with open('/etc/metronome/conf.d/%s.cfg.lua' % domain) as f: pass - except IOError as e: - conf_lines = [ - 'VirtualHost "%s"' % domain, - ' ssl = {', - ' key = "%s/key.pem";' % ssl_domain_path, - ' certificate = "%s/crt.pem";' % ssl_domain_path, - ' }', - ' authentication = "ldap2"', - ' ldap = {', - ' hostname = "localhost",', - ' user = {', - ' basedn = "ou=users,dc=yunohost,dc=org",', - ' filter = "(&(objectClass=posixAccount)(mail=*@%s))",' % domain, - ' usernamefield = "mail",', - ' namefield = "cn",', - ' },', - ' }', - ] - with open('/etc/metronome/conf.d/%s.cfg.lua' % domain, 'w') as conf: - for line in conf_lines: - conf.write(line + '\n') - - os.system('mkdir -p /var/lib/metronome/%s/pep' % domain.replace('.', '%2e')) - os.system('chown -R metronome: /var/lib/metronome/') - os.system('chown -R metronome: /etc/metronome/conf.d/') - os.system('service metronome restart') - - - # Nginx - os.system('cp /usr/share/yunohost/yunohost-config/nginx/template.conf /etc/nginx/conf.d/%s.conf' % domain) - os.system('mkdir /etc/nginx/conf.d/%s.d/' % domain) - os.system('sed -i s/yunohost.org/%s/g /etc/nginx/conf.d/%s.conf' % (domain, domain)) - os.system('service nginx reload') - if not auth.add('virtualdomain=%s,ou=domains' % domain, attr_dict): raise MoulinetteError(errno.EIO, m18n.n('domain_creation_failed')) - os.system('yunohost app ssowatconf > /dev/null 2>&1') + try: + with open('/etc/yunohost/installed', 'r') as f: + service_regenconf(service='nginx') + service_regenconf(service='metronome') + service_regenconf(service='dnsmasq') + os.system('yunohost app ssowatconf > /dev/null 2>&1') + except IOError: pass except: # Force domain removal silently try: domain_remove(auth, domain, True) @@ -236,6 +184,8 @@ def domain_remove(auth, domain, force=False): force -- Force the domain removal """ + from yunohost.service import service_regenconf + if not force and domain not in domain_list(auth)['domains']: raise MoulinetteError(errno.EINVAL, m18n.n('domain_unknown')) @@ -252,24 +202,13 @@ def domain_remove(auth, domain, force=False): m18n.n('domain_uninstall_app_first')) if auth.remove('virtualdomain=' + domain + ',ou=domains') or force: - command_list = [ - 'rm -rf /etc/yunohost/certs/%s' % domain, - 'rm -f /etc/dnsmasq.d/%s' % domain, - 'rm -rf /var/lib/metronome/%s' % domain.replace('.', '%2e'), - 'rm -f /etc/metronome/conf.d/%s.cfg.lua' % domain, - 'rm -rf /etc/nginx/conf.d/%s.d' % domain, - 'rm -f /etc/nginx/conf.d/%s.conf' % domain, - ] - for command in command_list: - if os.system(command) != 0: - msignals.display(m18n.n('path_removal_failed', command[7:]), - 'warning') + os.system('rm -rf /etc/yunohost/certs/%s' % domain) else: raise MoulinetteError(errno.EIO, m18n.n('domain_deletion_failed')) + service_regenconf(service='nginx') + service_regenconf(service='metronome') + service_regenconf(service='dnsmasq') os.system('yunohost app ssowatconf > /dev/null 2>&1') - os.system('service nginx reload') - os.system('service dnsmasq restart') - os.system('service metronome restart') msignals.display(m18n.n('domain_deleted'), 'success') diff --git a/lib/yunohost/hook.py b/lib/yunohost/hook.py index bb0518f6..96ffff35 100644 --- a/lib/yunohost/hook.py +++ b/lib/yunohost/hook.py @@ -184,8 +184,19 @@ def hook_callback(action, hooks=[], args=None): else: hooks_names = hook_list(action, list_by='name', show_info=True)['hooks'] - # Iterate over given hooks names list + + # Add similar hooks to the list + # For example: Having a 16-postfix hook in the list will execute a + # xx-postfix_dkim as well + all_hooks = [] for n in hooks: + for key in hooks_names.keys(): + if key == n or key.startswith("%s_" % n) \ + and key not in all_hooks: + all_hooks.append(key) + + # Iterate over given hooks names list + for n in all_hooks: try: hl = hooks_names[n] except KeyError: diff --git a/lib/yunohost/service.py b/lib/yunohost/service.py index 86a95933..2a69b4d2 100644 --- a/lib/yunohost/service.py +++ b/lib/yunohost/service.py @@ -23,14 +23,26 @@ Manage services """ +import os +import time import yaml import glob import subprocess import errno -import os.path +import shutil +import difflib +import hashlib from moulinette.core import MoulinetteError +template_dir = os.getenv( + 'YUNOHOST_TEMPLATE_DIR', + '/usr/share/yunohost/templates' +) +conf_backup_dir = os.getenv( + 'YUNOHOST_CONF_BACKUP_DIR', + '/home/yunohost.backup/conffiles' +) def service_add(name, status=None, log=None, runlevel=None): """ @@ -187,7 +199,8 @@ def service_status(names=[]): m18n.n('service_unknown', name)) status = None - if services[name]['status'] == 'service': + if 'status' not in services[name] or \ + services[name]['status'] == 'service': status = 'service %s status' % name else: status = str(services[name]['status']) @@ -257,9 +270,30 @@ def service_log(name, number=50): return result +def service_regenconf(service=None, force=False): + """ + Regenerate the configuration file(s) for a service and compare the result + with the existing configuration file. + Prints the differences between files if any. + + Keyword argument: + service -- Regenerate configuration for a specfic service + force -- Override the current configuration with the newly generated + one, even if it has been modified + + """ + from yunohost.hook import hook_callback + + if service is not None: + hook_callback('conf_regen', [service], args=[force]) + else: + hook_callback('conf_regen', args=[force]) + msignals.display(m18n.n('services_configured'), 'success') + + def _run_service_command(action, service): """ - Run services management command (start, stop, enable, disable) + Run services management command (start, stop, enable, disable, restart, reload) Keyword argument: action -- Action to perform @@ -271,7 +305,7 @@ def _run_service_command(action, service): service)) cmd = None - if action in ['start', 'stop']: + if action in ['start', 'stop', 'restart', 'reload']: cmd = 'service %s %s' % (service, action) elif action in ['enable', 'disable']: arg = 'defaults' if action == 'enable' else 'remove' @@ -302,6 +336,7 @@ def _get_services(): else: return services + def _save_services(services): """ Save managed services to files @@ -314,6 +349,7 @@ def _save_services(services): with open('/etc/yunohost/services.yml', 'w') as f: yaml.safe_dump(services, f, default_flow_style=False) + def _tail(file, n, offset=None): """ Reads a n lines from f with an offset of offset lines. The return @@ -340,3 +376,185 @@ def _tail(file, n, offset=None): avg_line_length *= 1.3 except IOError: return [] + + +def _get_diff(string, filename): + """ + Show differences between a string and a file's content + + Keyword argument: + string -- The string + filename -- The file to compare with + + """ + try: + with open(filename, 'r') as f: + file_lines = f.readlines() + + string = string + '\n' + new_lines = string.splitlines(True) + while '\n' == file_lines[-1]: + del file_lines[-1] + return difflib.unified_diff(file_lines, new_lines) + except IOError: return [] + + +def _hash(filename): + """ + Calculate a MD5 hash of a file + + Keyword argument: + filename -- The file to hash + + """ + hasher = hashlib.md5() + try: + with open(filename, 'rb') as f: + buf = f.read() + hasher.update(buf) + + return hasher.hexdigest() + except IOError: + return 'no hash yet' + + +def service_saferemove(service, conf_file, force=False): + """ + Check if the specific file has been modified before removing it. + Backup the file in /home/yunohost.backup + + Keyword argument: + service -- Service name of the file to delete + conf_file -- The file to write + force -- Force file deletion + + """ + deleted = False + services = _get_services() + + if not os.path.exists(conf_file): + try: + del services[service]['conffiles'][conf_file] + except KeyError: pass + return True + + # Backup existing file + date = time.strftime("%Y%m%d.%H%M%S") + conf_backup_file = conf_backup_dir + conf_file +'-'+ date + process = subprocess.Popen( + ['install', '-D', conf_file, conf_backup_file] + ) + process.wait() + + # Retrieve hashes + if not 'conffiles' in services[service]: + services[service]['conffiles'] = {} + + if conf_file in services[service]['conffiles']: + previous_hash = services[service]['conffiles'][conf_file] + else: + previous_hash = 'no hash yet' + + current_hash = _hash(conf_file) + + # Handle conflicts + if force or previous_hash == current_hash: + os.remove(conf_file) + try: + del services[service]['conffiles'][conf_file] + except KeyError: pass + deleted = True + else: + services[service]['conffiles'][conf_file] = previous_hash + os.remove(conf_backup_file) + if os.isatty(1) and \ + (len(previous_hash) == 32 or previous_hash[-32:] != current_hash): + msignals.display( + m18n.n('service_configuration_changed', conf_file), + 'warning' + ) + + _save_services(services) + + return deleted + + +def service_safecopy(service, new_conf_file, conf_file, force=False): + """ + Check if the specific file has been modified and display differences. + Stores the file hash in the services.yml file + + Keyword argument: + service -- Service name attached to the conf file + new_conf_file -- Path to the desired conf file + conf_file -- Path to the targeted conf file + force -- Force file overriding + + """ + regenerated = False + services = _get_services() + + if not os.path.exists(new_conf_file): + raise MoulinetteError(errno.EIO, m18n.n('no_such_conf_file', new_conf_file)) + + with open(new_conf_file, 'r') as f: + new_conf = ''.join(f.readlines()).rstrip() + + # Backup existing file + date = time.strftime("%Y%m%d.%H%M%S") + conf_backup_file = conf_backup_dir + conf_file +'-'+ date + if os.path.exists(conf_file): + process = subprocess.Popen( + ['install', '-D', conf_file, conf_backup_file] + ) + process.wait() + else: + msignals.display(m18n.n('service_add_configuration', conf_file), + 'info') + + # Add the service if it does not exist + if service not in services.keys(): + services[service] = {} + + # Retrieve hashes + if not 'conffiles' in services[service]: + services[service]['conffiles'] = {} + + if conf_file in services[service]['conffiles']: + previous_hash = services[service]['conffiles'][conf_file] + else: + previous_hash = 'no hash yet' + + current_hash = _hash(conf_file) + diff = list(_get_diff(new_conf, conf_file)) + + # Handle conflicts + if force or previous_hash == current_hash: + with open(conf_file, 'w') as f: f.write(new_conf) + new_hash = _hash(conf_file) + if previous_hash != new_hash: + regenerated = True + elif len(diff) == 0: + new_hash = _hash(conf_file) + else: + new_hash = previous_hash + if (len(previous_hash) == 32 or previous_hash[-32:] != current_hash): + msignals.display( + m18n.n('service_configuration_conflict', conf_file), + 'warning' + ) + print('\n' + conf_file) + for line in diff: + print(line.strip()) + print('') + + # Remove the backup file if the configuration has not changed + if new_hash == previous_hash: + try: + os.remove(conf_backup_file) + except OSError: pass + + services[service]['conffiles'][conf_file] = new_hash + _save_services(services) + + return regenerated diff --git a/lib/yunohost/tools.py b/lib/yunohost/tools.py index 95fbe8f8..867fc775 100644 --- a/lib/yunohost/tools.py +++ b/lib/yunohost/tools.py @@ -106,6 +106,7 @@ def tools_maindomain(auth, old_domain=None, new_domain=None, dyndns=False): """ from yunohost.domain import domain_add, domain_list from yunohost.dyndns import dyndns_subscribe + from yunohost.service import service_regenconf if not old_domain: with open('/etc/yunohost/current_host', 'r') as f: @@ -119,71 +120,13 @@ def tools_maindomain(auth, old_domain=None, new_domain=None, dyndns=False): if new_domain not in domain_list(auth)['domains']: domain_add(auth, new_domain) - config_files = [ - '/etc/postfix/main.cf', - '/etc/metronome/metronome.cfg.lua', - '/etc/dovecot/dovecot.conf', - '/usr/share/yunohost/yunohost-config/others/startup', - '/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)) - - ## Update DNS zone file for old and new domains - main_subdomains = ['pubsub', 'muc', 'vjud'] - try: - with open('/var/lib/bind/%s.zone' % old_domain, 'r') as f: - old_zone = f.read() - except IOError: - pass - else: - # Remove unneeded subdomains entries - for sub in main_subdomains: - old_zone = re.sub( - r'^({sub}.{domain}.|{sub})[\ \t]+(IN).*$[\n]?'.format( - sub=sub, domain=old_domain), - '', old_zone, 1, re.MULTILINE) - with open('/var/lib/bind/%s.zone' % old_domain, 'w') as f: - f.write(old_zone) - try: - with open('/var/lib/bind/%s.zone' % new_domain, 'r') as f: - new_zone = f.read() - except IOError: - msignals.display(m18n.n('domain_zone_not_found', new_domain), 'warning') - else: - # Add main subdomains entries - for sub in main_subdomains: - new_zone += '{sub} IN CNAME {domain}.\n'.format( - sub=sub, domain=new_domain) - with open('/var/lib/bind/%s.zone' % new_domain, 'w') as f: - f.write(new_zone) - os.system('rm /etc/ssl/private/yunohost_key.pem') os.system('rm /etc/ssl/certs/yunohost_crt.pem') command_list = [ - 'rm -f /etc/nginx/conf.d/%s.d/yunohost_local.conf' % old_domain, - 'cp /usr/share/yunohost/yunohost-config/nginx/yunohost_local.conf /etc/nginx/conf.d/%s.d/' % new_domain, 'ln -s /etc/yunohost/certs/%s/key.pem /etc/ssl/private/yunohost_key.pem' % new_domain, 'ln -s /etc/yunohost/certs/%s/crt.pem /etc/ssl/certs/yunohost_crt.pem' % new_domain, 'echo %s > /etc/yunohost/current_host' % new_domain, - 'service metronome restart', - 'service postfix restart', - 'service dovecot restart', - 'service amavis restart', - 'service nginx restart', ] for command in command_list: @@ -202,6 +145,11 @@ def tools_maindomain(auth, old_domain=None, new_domain=None, dyndns=False): if dyndomain in dyndomains: dyndns_subscribe(domain=new_domain) + try: + with open('/etc/yunohost/installed', 'r') as f: + service_regenconf() + except IOError: pass + msignals.display(m18n.n('maindomain_changed'), 'success') @@ -219,6 +167,7 @@ def tools_postinstall(domain, password, ignore_dyndns=False): from yunohost.app import app_ssowatconf from yunohost.firewall import firewall_upnp, firewall_reload + from yunohost.service import service_regenconf dyndns = not ignore_dyndns @@ -327,6 +276,8 @@ def tools_postinstall(domain, password, ignore_dyndns=False): os.system('touch /etc/yunohost/installed') + service_regenconf(force=True) + msignals.display(m18n.n('yunohost_configured'), 'success')