diff --git a/data/actionsmap/yunohost.yml b/data/actionsmap/yunohost.yml index d05ffeb5c..95180f0f2 100644 --- a/data/actionsmap/yunohost.yml +++ b/data/actionsmap/yunohost.yml @@ -869,6 +869,26 @@ 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 + arguments: + -n: + full: --name + 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 + -k: + full: --keep + help: Save the current configuration to avoid further notifications + action: store_true + ############################# # Firewall # diff --git a/data/templates/amavis/05-domain_id b/data/templates/amavis/05-domain_id new file mode 100644 index 000000000..01a71e4b3 --- /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 000000000..ee6665436 --- /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 000000000..825e9e03c --- /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 000000000..fb8d835de --- /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.j2 b/data/templates/amavis/50-user.j2 new file mode 100644 index 000000000..129da4f25 --- /dev/null +++ b/data/templates/amavis/50-user.j2 @@ -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 = "{{ domain }}"; + +$mydomain = "{{ 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/dovecot/dovecot-ipv4.conf.j2 b/data/templates/dovecot/dovecot-ipv4.conf.j2 new file mode 100644 index 000000000..044f0b902 --- /dev/null +++ b/data/templates/dovecot/dovecot-ipv4.conf.j2 @@ -0,0 +1,71 @@ +# 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 +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.conf b/data/templates/fail2ban/jail.conf new file mode 100644 index 000000000..c1cde0264 --- /dev/null +++ b/data/templates/fail2ban/jail.conf @@ -0,0 +1,344 @@ +# 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 + +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 000000000..54d4a779f --- /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 000000000..90c29eb70 --- /dev/null +++ b/data/templates/glances/glances.default @@ -0,0 +1,2 @@ +DAEMON_ARGS="-B 127.0.0.1" +RUN="yes" diff --git a/data/templates/metronome/metronome.cfg.lua b/data/templates/metronome/metronome.cfg.lua new file mode 100644 index 000000000..240dc4e24 --- /dev/null +++ b/data/templates/metronome/metronome.cfg.lua @@ -0,0 +1,131 @@ +-- ** 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. + +-- Global settings go in this section + +-- 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. + +pidfile = "/var/run/metronome/metronome.pid" + +log = { + info = "/var/log/metronome/metronome.log"; -- Change 'info' to 'debug' for verbose logging + error = "/var/log/metronome/metronome.err"; + "*syslog"; +} + +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 + + -- Not essential, but recommended + "private"; -- Private XML storage (for room bookmarks, etc.) + "vcard"; -- Allow users to set vCards + "privacy"; -- Support privacy lists + --"compression"; -- Stream compression (Debian: requires lua-zlib module to work) + + -- Nice to have + "legacyauth"; -- Legacy authentication. Only used by some old clients and bots. + "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 + "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 + + -- Other specific functionality + "bosh"; -- Enable BOSH clients, aka "Jabber over HTTP" + --"httpserver"; -- Serve static files from a directory over HTTP + --"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 + -- 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.yunohost.org" }, + { "vjud.yunohost.org" }, + { "pubsub.yunohost.org" } +}; + +use_ipv6 = true +c2s_require_encryption = false +s2s_secure = true + +-- HTTP ports +http_ports = { 5290 } +https_ports = { 5291 } + +-- BOSH configuration (mod_bosh) +bosh_max_inactivity = 30 +consider_bosh_secure = true +cross_domain_bosh = true + +anonymous_login = false +allow_registration = false + +storage = "ldap" + +Component "localhost" "http" + modules_enabled = { "bosh" } + +Component "muc.yunohost.org" "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 = { + http_port = 5290; + show_join = true; + show_status = false; + theme = "metronome"; + } + +Component "pubsub.yunohost.org" "pubsub" + name = "YunoHost Publish/Subscribe" + unrestricted_node_creation = true + +Component "vjud.yunohost.org" "vjud" + ud_disco_name = "Jappix User Directory" + +Include "conf.d/*.cfg.lua" + + diff --git a/data/templates/metronome/metronome.init b/data/templates/metronome/metronome.init new file mode 100644 index 000000000..62c04846d --- /dev/null +++ b/data/templates/metronome/metronome.init @@ -0,0 +1,101 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: metronome +# Required-Start: $network $local_fs $remote_fs +# Required-Stop: $remote_fs +# 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 + +DAEMON=/usr/bin/metronome +PIDPATH=/var/run/metronome +PIDFILE="$PIDPATH"/metronome.pid +RUNTIME=/usr/bin/lua5.1 + +NICE= +MAXFDS= +CPUSCHED= +IOSCHED= + +test -x "$DAEMON" || exit 0 + +if [ -f /etc/default/metronome ] ; then + . /etc/default/metronome +fi + +if [ ! -d "$PIDPATH" ]; then + mkdir "$PIDPATH"; + chown metronome:adm "$PIDPATH"; +fi + +# Check that user 'metronome' exists +check_user() { + if ! getent passwd metronome >/dev/null; then + exit 1; + fi +} + +start_opts() { + test -z "$NICE" || echo -n " --nicelevel $NICE" + test -z "$CPUSCHED" || echo -n " --procsched $CPUSCHED" + test -z "$IOSCHED" || echo -n " --iosched $IOSCHED" +} + +. /lib/lsb/init-functions + +test -z "$MAXFDS" || ulimit -n "$MAXFDS" + +case "$1" in + start) + check_user + log_daemon_msg "Starting Metronome XMPP Server" "metronome" + + if start-stop-daemon --start --quiet --oknodo --pidfile "$PIDFILE" --chuid metronome $(start_opts) --exec "$RUNTIME" -- "$DAEMON"; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + stop) + log_daemon_msg "Stopping Metronome XMPP Server" "metronome" + if start-stop-daemon --stop --retry 30 --quiet --oknodo --pidfile "$PIDFILE"; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + force-reload|restart) + log_daemon_msg "Restarting Metronome XMPP Server" "metronome" + + start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile "$PIDFILE" + + check_user log_end_msg + + if start-stop-daemon --start --quiet --oknodo --pidfile "$PIDFILE" --chuid metronome $(start_opts) --exec "$RUNTIME" -- "$DAEMON"; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + reload) + log_daemon_msg "Reloading Metronome XMPP Server" "metronome" + + if start-stop-daemon --stop --quiet --pidfile "$PIDFILE" --signal 1; then + log_end_msg 0 + else + log_end_msg 1 + fi + ;; + *) + log_action_msg "Usage: /etc/init.d/metronome {start|stop|restart|reload}" + exit 1 +esac + +exit 0 + diff --git a/data/templates/metronome/metronome.logrotate b/data/templates/metronome/metronome.logrotate new file mode 100644 index 000000000..aa145429a --- /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 000000000..6774e735f --- /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 000000000..8c50a99fd --- /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 000000000..cee591c95 --- /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 000000000..17850a217 --- /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 000000000..dcbd0106a --- /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 000000000..2d4e1df2a --- /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.j2 b/data/templates/nginx/server.conf.j2 new file mode 100644 index 000000000..656a1d80e --- /dev/null +++ b/data/templates/nginx/server.conf.j2 @@ -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 000000000..c82cd40ea --- /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 000000000..0f208cb59 --- /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 000000000..736102944 --- /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 000000000..307eb4aa0 --- /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 000000000..ebf2bd65a --- /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 000000000..4d5b441d1 --- /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 000000000..b2daf777c --- /dev/null +++ b/data/templates/nslcd/nslcd.conf @@ -0,0 +1,32 @@ +root@65ba01d0c078:/usr/share/yunohost/yunohost-config/slapd# cat /etc/nslcd.conf +# /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 +#bindpw + +# The DN used for password modifications by root. +#rootpwmoddn cn=admin,dc=example,dc=com + +# SSL options +#ssl off +#tls_reqcert + +# The search scope. +#scope sub + diff --git a/data/templates/postfix/header_check b/data/templates/postfix/header_check new file mode 100644 index 000000000..bf5c3352a --- /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 000000000..bd3576dec --- /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 000000000..a9ef52cf9 --- /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 000000000..088640bfc --- /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-ipv4.j2 b/data/templates/postfix/main.cf-ipv4.j2 new file mode 100644 index 000000000..f2cf04579 --- /dev/null +++ b/data/templates/postfix/main.cf-ipv4.j2 @@ -0,0 +1,127 @@ +# 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 ESMTP $mail_name (Debian/GNU) +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 parameters +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_use_tls=yes +smtpd_tls_exclude_ciphers = aNULL, MD5, DES, ADH +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache + +# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for +# information on enabling SSL in the smtp client. + +myhostname = {{ domain }} +alias_maps = hash:/etc/aliases +alias_database = hash:/etc/aliases +mydomain = {{ domain }} +mydestination = localhost +relayhost = +mynetworks = 127.0.0.0/8 +mailbox_command = procmail -a "$EXTENSION" +mailbox_size_limit = 0 +recipient_delimiter = + +inet_interfaces = all +inet_protocols = ipv4 + +#### add yunohost #### +message_size_limit = 10240000 + +# 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 sbl-xbl.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 diff --git a/data/templates/postfix/main.cf.j2 b/data/templates/postfix/main.cf.j2 new file mode 100644 index 000000000..6c1052dc7 --- /dev/null +++ b/data/templates/postfix/main.cf.j2 @@ -0,0 +1,126 @@ +# 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 ESMTP $mail_name (Debian/GNU) +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 parameters +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_use_tls=yes +smtpd_tls_exclude_ciphers = aNULL, MD5, DES, ADH +smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache +smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache + +# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for +# information on enabling SSL in the smtp client. + +myhostname = {{ domain }} +alias_maps = hash:/etc/aliases +alias_database = hash:/etc/aliases +mydomain = {{ 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 + +#### add yunohost #### +message_size_limit = 10240000 + +# 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 sbl-xbl.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 diff --git a/data/templates/postfix/master.cf b/data/templates/postfix/master.cf new file mode 100644 index 000000000..9ced25690 --- /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/postgrey b/data/templates/postfix/postgrey new file mode 100644 index 000000000..1af70c149 --- /dev/null +++ b/data/templates/postfix/postgrey @@ -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/postfix/sender_canonical b/data/templates/postfix/sender_canonical new file mode 100644 index 000000000..caf093d16 --- /dev/null +++ b/data/templates/postfix/sender_canonical @@ -0,0 +1 @@ +/^(.*)@(.*)$/ ${1} diff --git a/data/templates/slapd/mailserver.schema b/data/templates/slapd/mailserver.schema new file mode 100644 index 000000000..55374ce42 --- /dev/null +++ b/data/templates/slapd/mailserver.schema @@ -0,0 +1,87 @@ +## 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 in kilo-bytes' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 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 000000000..3b0e3cf2e --- /dev/null +++ b/data/templates/slapd/slapd.conf @@ -0,0 +1,143 @@ +# 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 +include /etc/ldap/schema/samba.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 000000000..9cd3b2e9a --- /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=/etc/ldap/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://127.0.0.1/ ldapi://127.0.0.1/" + +# 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/spamassassin/local.cf b/data/templates/spamassassin/local.cf new file mode 100644 index 000000000..bc37b3a60 --- /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 000000000..da1b33110 --- /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 000000000..695ea0d36 --- /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/ssh/sshd_config-ipv4 b/data/templates/ssh/sshd_config-ipv4 new file mode 100644 index 000000000..1545b6079 --- /dev/null +++ b/data/templates/ssh/sshd_config-ipv4 @@ -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 +AllowUsers admin + +Match User sftpusers + ForceCommand internal-sftp + AllowTcpForwarding no + GatewayPorts no + X11Forwarding no diff --git a/data/templates/unattended/02periodic b/data/templates/unattended/02periodic new file mode 100644 index 000000000..c3ec92913 --- /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 000000000..49b600a3b --- /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/lib/yunohost/service.py b/lib/yunohost/service.py index 86a95933d..3be221b20 100644 --- a/lib/yunohost/service.py +++ b/lib/yunohost/service.py @@ -23,14 +23,27 @@ Manage services """ +import os +import time import yaml import glob import subprocess import errno -import os.path +import shutil +import jinja2 +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): """ @@ -257,9 +270,31 @@ def service_log(name, number=50): return result +def service_regenconf(auth, name=None, force=False, keep=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: + name -- Regenerate configuration for a specfic service + force -- Override the current configuration with the newly generated + one, even if it has been modified + keep -- Save the current configuration to avoid further notifications + + """ + if name is not None: + _regenerate_configuration_for(auth, name, force, keep) + + + #TODO: Raise error when force + keep + #TODO: Loop through all the services + #TODO: Win message with regenerated configurations + + 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 +306,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 +337,7 @@ def _get_services(): else: return services + def _save_services(services): """ Save managed services to files @@ -314,6 +350,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 +377,268 @@ 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(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 _safe_remove(conf_file, service=None, force=False, keep=False): + """ + Check if the specific file has been modified before removing it. + Backup the file in /home/yunohost.backup + + Keyword argument: + conf_file -- The file to write + service -- Service name of the file to delete + force -- Force file deletion + keep -- Keep the current file and save its hash + + """ + deleted = False + + if not os.path.exists(conf_file): + try: + del services[service]['conffiles'][conf_file] + except KeyError: pass + return True + + services = _get_services() + + # 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 + msignals.display(m18n.n('service_configuration_backup', conf_backup_file), + 'info') + elif keep: + services[service]['conffiles'][conf_file] = \ + previous_hash[0:32] + ', but keep ' + current_hash + msignals.display(m18n.n('service_configuration_backup', conf_backup_file), + 'info') + 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 _safe_write(conf_file, new_conf='', service=None, force=False, keep=False): + """ + Check if the specific file has been modified and display differences. + Stores the file hash in the services.yml file + + Keyword argument: + conf_file -- The file to write + new_conf -- String containing the new content + service -- Service name of the file to write + force -- Force file overriding + keep -- Keep the current file and save its hash + + """ + regenerated = False + services = _get_services() + + if os.path.exists(new_conf): + filename = new_conf + with open(filename, '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') + + # 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) + regenerated = True + new_hash = _hash(conf_file) + elif keep: + new_hash = previous_hash[0:32] + ', but keep ' + current_hash + elif len(diff) == 0: + new_hash = _hash(conf_file) + else: + new_hash = previous_hash + if os.isatty(1) and \ + (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: + os.remove(conf_backup_file) + elif os.path.exists(conf_backup_file): + msignals.display(m18n.n('service_configuration_backup', conf_backup_file), + 'info') + + services[service]['conffiles'][conf_file] = new_hash + _save_services(services) + + return regenerated + + +def _regenerate_configuration_for(auth, service, force=False, keep=False): + """ + Handle all the different services' configurations of YunoHost + + Keyword argument: + service -- Service name to take care of + force -- Force configuration overriding + keep -- Keep the current configuration and save its hash + + """ + from yunohost.domain import domain_list + + if service not in _get_services().keys() \ + or not os.path.isdir("%s/%s" % (template_dir, service)): + raise MoulinetteError(errno.EINVAL, m18n.n('service_unknown', service)) + + # Set the service's template directory as Jinja Environment in order + # to ease the template loading + env = jinja2.Environment( + loader=jinja2.FileSystemLoader("%s/%s" % (template_dir, service)) + ) + + domains = domain_list(auth)['domains'] + + with open('/etc/yunohost/current_host', 'r') as f: + main_domain = f.readline().rstrip() + + if service == 'nginx': + + need_restart = False + + # Copy plain files + for filename in [ + 'ssowat.conf', + 'yunohost_admin.conf', + 'yunohost_admin.conf.inc', + 'yunohost_api.conf.inc', + 'yunohost_panel.conf.inc', + ]: + conf_file = '/etc/nginx/conf.d/%s' % filename + new_conf = '%s/%s/%s' % (template_dir, service, filename) + _safe_write(conf_file, new_conf, service, force, keep) + + # We need one file and one folder per virtualhost + for domain in domains: + conf_file = '/etc/nginx/conf.d/%s.conf' % domain + new_conf = env.get_template('server.conf.j2').render(domain=domain) + need_restart = _safe_write(conf_file, new_conf, service, force, keep) \ + or need_restart + try: + os.makedirs('/etc/nginx/conf.d/%s.d' % domain) + except OSError: pass + + # Copy yunohost_local.conf for the main domain + filename = 'yunohost_local.conf' + conf_file = '/etc/nginx/conf.d/%s.d/%s' % (main_domain, filename) + new_conf = '%s/%s/%s' % (template_dir, service, filename) + _safe_write(conf_file, new_conf, service, force, keep) + + # Backup and remove configuration for unexisting domains + for conf_file in os.listdir('/etc/nginx/conf.d/'): + if conf_file.endswith('.conf') and len(conf_file.split('.')) > 2 \ + and conf_file.replace('.conf', '') not in domains: + _safe_remove('/etc/nginx/conf.d/'+ conf_file, service, force, keep) + + # Restart Nginx + if need_restart: + _run_service_command('restart', service) + else: + _run_service_command('reload', service) + + msignals.display(m18n.n('service_configured', service), 'success') + + if service == 'postfix': + pass