source: trunk/src/update_domains.sh @ 905

Revision 905, 15.3 KB checked in by nahuel, 7 years ago (diff)

Correction du bug 530.
Le select utilisait INNER JOIN qui ne selectionne pas la ligne si une ligne n'a pas de correspondance. Remplacé par un LEFT JOIN qui met null dans la cellule s'il n'y a
pas de correspondance, donc lors de la suppression d'un domaine sans compte cela fonctionnera.

  • Property svn:executable set to *
Line 
1#!/bin/sh
2#
3# $Id: do_domaines.sh,v 1.31 2005/08/29 19:21:31 anarcat Exp $
4# ----------------------------------------------------------------------
5# AlternC - Web Hosting System
6# Copyright (C) 2002 by the AlternC Development Team.
7# http://alternc.org/
8# ----------------------------------------------------------------------
9# Based on:
10# Valentin Lacambre's web hosting softwares: http://altern.org/
11# ----------------------------------------------------------------------
12# LICENSE
13#
14# This program is free software; you can redistribute it and/or
15# modify it under the terms of the GNU General Public License (GPL)
16# as published by the Free Software Foundation; either version 2
17# of the License, or (at your option) any later version.
18#
19# This program is distributed in the hope that it will be useful,
20# but WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22# GNU General Public License for more details.
23#
24# To read the license please visit http://www.gnu.org/copyleft/gpl.html
25# ----------------------------------------------------------------------
26# Original Author of file: Jerome Moinet for l'Autre Net - 14/12/2000
27# Purpose of file: system level domain management
28# ----------------------------------------------------------------------
29#
30
31PATH=/sbin:/bin:/usr/sbin:/usr/bin
32
33set -e
34
35umask 022
36
37########################################################################
38# Constants & Preliminary checks
39#
40
41CONFIG_FILE="/etc/alternc/local.sh"
42
43DOMAIN_LOG_FILE="/var/log/alternc/update_domains.log"
44DATA_ROOT="/var/alternc"
45
46NAMED_TEMPLATE="/etc/bind/templates/named.template"
47ZONE_TEMPLATE="/etc/bind/templates/zone.template"
48
49ACTION_INSERT=0
50ACTION_UPDATE=1
51ACTION_DELETE=2
52TYPE_LOCAL=0
53TYPE_URL=1
54TYPE_IP=2
55TYPE_WEBMAIL=3
56YES=1
57
58if [ ! -x "/usr/bin/get_account_by_domain" ]; then
59    echo "You have to install alternc-admintools: "
60    echo "    apt-get update ; apt-get install alternc-admintools"
61    exit 1
62fi
63
64if [ ! -r "$CONFIG_FILE" ]; then
65    echo "Can't access $CONFIG_FILE."
66    exit 1
67fi
68
69. "$CONFIG_FILE"
70
71if [ -z "$MYSQL_HOST" -o -z "$MYSQL_DATABASE" -o -z "$MYSQL_USER" -o \
72     -z "$MYSQL_PASS" -o -z "$DEFAULT_MX" -o -z "$PUBLIC_IP" ]; then
73    echo "Bad configuration. Please use:"
74    echo "   dpkg-reconfigure alternc"
75    exit 1
76fi
77
78if [ -f "$LOCK_FILE" ]; then
79    echo "`date` $0: last cron unfinished or stale lock file." |
80        tee -a "$DOMAIN_LOG_FILE" >&2
81    exit 1
82fi
83
84NAMED_CONF_FILE="$DATA_ROOT/bind/automatic.conf"
85ZONES_DIR="$DATA_ROOT/bind/zones"
86APACHECONF_DIR="$DATA_ROOT/apacheconf"
87OVERRIDE_PHP_FILE="$APACHECONF_DIR/override_php.conf"
88WEBMAIL_DIR="$DATA_ROOT/bureau/admin/webmail"
89LOCK_FILE="$DATA_ROOT/bureau/cron.lock"
90HTTP_DNS="$DATA_ROOT/dns"
91HTML_HOME="$DATA_ROOT/html"
92
93MYSQL_SELECT="mysql -h${MYSQL_HOST} -u${MYSQL_USER}
94                    -p${MYSQL_PASS} -Bs ${MYSQL_DATABASE}"
95MYSQL_DELETE="mysql -h${MYSQL_HOST} -u${MYSQL_USER}
96                    -p${MYSQL_PASS} ${MYSQL_DATABASE}"
97
98########################################################################
99# Functions
100#
101
102print_domain_letter() {
103    local domain="$1"
104
105    local letter=`echo "$domain" | awk '{z=split($NF, a, ".") ; print substr(a[z-1], 1, 1)}'`
106    if [ -z "$letter" ]; then
107      letter="_"
108    fi
109    echo $letter
110}
111
112print_user_letter() {
113    local user="$1"
114
115    echo "$user" | awk '{print substr($1, 1, 1)}'
116}
117
118add_to_php_override() {
119    local fqdn="$1"
120    local escaped_fqdn=`echo "$fqdn" | sed 's/\([\*|\.]\)/\\\\\1/g'`
121
122    if ! grep -q "^${escaped_fqdn}$" "$CHANGED_PHP_OVERRIDES_TMP_FILE"; then
123        echo "$fqdn" >> "$CHANGED_PHP_OVERRIDES_TMP_FILE"
124    fi
125}
126
127add_to_named_reload() {
128    local domain="$1"
129    local escaped_domain=`echo "$domain" | sed -e 's/\./\\\./g'`
130
131    if [ "domain" = "all" ] || grep -q "^all$" "$RELOAD_ZONES_TMP_FILE"; then
132        echo "all" > "$RELOAD_ZONES_TMP_FILE"
133    else
134        if ! grep -q "^${escaped_domain}$" "$RELOAD_ZONES_TMP_FILE"; then
135            echo "$domain" >> "$RELOAD_ZONES_TMP_FILE"
136        fi
137    fi
138}
139
140# we assume that the serial line contains the "serial string", eg.:
141#                 2005012703      ; serial
142#
143# returns 1 if file isn't readable
144# returns 2 if we can't find the serial number
145# returns 3 if a tempfile can't be created
146increment_serial() {
147    local domain="$1"
148    local zone_file="$ZONES_DIR/$domain"
149    local current_serial
150    local new_serial
151    local date
152    local revision
153    local today
154
155    if [ ! -f "$zone_file" ]; then
156        return 1
157    fi
158
159    # the assumption is here
160    current_serial=`awk '/^..*serial/ {print $1}' < "$zone_file"` || return 2
161    if [ -z "$current_serial" ]; then
162        return 2
163    fi
164
165    date=`echo $current_serial | cut -c1-8`
166    revision=`echo $current_serial | sed s/"${date}0\?"/""/g`
167    today=`date +%Y%m%d`
168    # increment the serial number only if the date hasn't changed
169    if [ "$current_date" = "$today" ] ; then
170        revision=$(($revision + 1))
171    else
172        revision=1
173        date=$today
174    fi
175    new_serial="$date`printf '%.2d' $revision`"
176
177    # replace serial number
178    cp -a -f "$zone_file" "$zone_file.$$"
179    awk -v "NEW_SERIAL=$new_serial" \
180        '{if ($3 == "serial")
181             print "            "NEW_SERIAL "   ; serial"
182          else
183             print $0}' < "$zone_file" > "$zone_file.$$"
184    mv -f "$zone_file.$$" "$zone_file"
185
186    add_to_named_reload "$domain"
187
188    return 0
189}
190
191change_host_ip() {
192    local domain="$1"
193    local zone_file="$ZONES_DIR/$domain"
194    local ip="$2"
195    local host="$3"
196    local pattern
197    local a_line
198
199    if [ -z "$host" ]; then
200        host="@"
201    fi
202    a_line="$host       IN      A       $ip"
203    pattern="^$host[[:space:]]*IN[[:space:]]*A[[:space:]]*.*\$"
204    if [ ! -f "$zone_file" ]; then
205        echo "Should change $host.$domain, but can't find $zone_file."
206        return 1
207    fi
208    if grep -q "$pattern" "$zone_file"; then
209        cp -a -f "$zone_file" "$zone_file.$$"
210        sed "s/$pattern/$a_line/" < "$zone_file" > "$zone_file.$$"
211        mv "$zone_file.$$" "$zone_file"
212    else
213        echo "$a_line" >> "$zone_file"
214    fi
215    add_to_named_reload "$domain"
216}
217
218add_host() {
219    local domain="$1"
220    local host_type="$2"
221    local host="$3"
222    local value="$4"
223    local user="$5"
224    local domain_letter=`print_domain_letter "$domain"`
225    local user_letter=`print_user_letter "$user"`
226    local ip
227    local fqdn
228    local vhost_directory
229       
230    delete_host "$domain" "$host"
231
232    if [ "$host" = "@" ]; then
233        change_host_ip "$domain" "$PUBLIC_IP"
234        fqdn="$domain"
235    else
236        if [ "$host_type" = "$TYPE_IP" ]; then
237            ip="$value"
238        else
239            ip="$PUBLIC_IP"
240        fi
241        change_host_ip "$domain" "$ip" "$host"
242        fqdn="${host}.${domain}"
243    fi
244
245    vhost_directory="${HTTP_DNS}/${domain_letter}/${fqdn}"
246    htaccess_directory="${HTTP_DNS}/redir/${domain_letter}/${fqdn}"
247
248    case "$host_type" in
249      $TYPE_LOCAL)
250        ln -snf "${HTML_HOME}/${user_letter}/${user}${value}" \
251                "$vhost_directory"
252        ;;
253
254      $TYPE_WEBMAIL)
255        ln -snf "${WEBMAIL_DIR}" "$vhost_directory"
256        ;;
257
258      $TYPE_URL)
259        mkdir -p "$htaccess_directory"
260        (echo "RewriteEngine on"
261         echo "RewriteRule (.*) ${value}/\$1 [R,L]"
262        ) > "$htaccess_directory/.htaccess"
263        ln -snf "$htaccess_directory" "$vhost_directory"
264        ;;
265       
266      $TYPE_IP)
267        rm -f "$vhost_directory"
268        rm -rf "$htaccess_directory/.htaccess"
269        ;;
270
271      *)
272        echo "Unknow type code: $type" >> "$DOMAIN_LOG_FILE"
273        ;;
274    esac
275}
276
277delete_host() {
278    local domain="$1"
279    local host="$2"
280    local domain_letter=`print_domain_letter "$domain"`
281    local fqdn
282    local escaped_host
283    local escaped_fqdn
284   
285    if [ "$host" = "@" -o -z "$host" ]; then
286        fqdn="$domain"
287        escaped_host=""
288    else
289        fqdn="$host.$domain"
290        escaped_host=`echo "$host" | sed 's/\([\*|\.]\)/\\\\\1/g'`
291    fi
292
293    if [ -f "$ZONES_DIR/$domain" ] ; then
294        cp -a -f "$ZONES_DIR/$domain" "$ZONES_DIR/$domain.$$"
295        sed -e "/^$escaped_host[[:space:]]*IN[[:space:]]*A[[:space:]]/d" \
296            < "$ZONES_DIR/$domain" > "$ZONES_DIR/$domain.$$"
297        mv "$ZONES_DIR/$domain.$$" "$ZONES_DIR/$domain"
298        increment_serial "$domain"
299        add_to_named_reload "$domain"
300    fi
301
302    rm -f "$APACHECONF_DIR/$domain_letter/$fqdn"
303
304    escaped_fqdn=`echo "$fqdn" | sed 's/\([\*|\.]\)/\\\\\1/g'`
305
306    cp -a -f "$OVERRIDE_PHP_FILE" "$OVERRIDE_PHP_FILE.$$"
307    sed -e "/\/${escaped_fqdn}\$/d" \
308        < "$OVERRIDE_PHP_FILE" > "$OVERRIDE_PHP_FILE.$$"
309    mv "$OVERRIDE_PHP_FILE.$$" "$OVERRIDE_PHP_FILE"
310
311    rm -f "$HTTP_DNS/$domain_letter/$fqdn"
312    rm -rf "$HTTP_DNS/redir/$domain_letter/$fqdn"
313}
314
315
316init_zone() {
317    local domain="$1"
318    local escaped_domain=`echo "$domain" | sed -e 's/\./\\\./g'`
319    local zone_file="$ZONES_DIR/$domain"
320    local serial
321
322    if [ ! -f "$zone_file" ]; then
323        serial=`date +%Y%m%d`00
324        sed -e "s/@@DOMAINE@@/$domain/g;s/@@SERIAL@@/$serial/g" \
325            < "$ZONE_TEMPLATE" > "$zone_file"
326        chgrp bind "$zone_file"
327        chmod 640  "$zone_file"
328    fi
329    if ! grep -q "\"$escaped_domain\"" "$NAMED_CONF_FILE"; then
330        cp -a -f "$NAMED_CONF_FILE" "$NAMED_CONF_FILE".prec
331        sed -e "s/@@DOMAINE@@/$domain/g" \
332                < "$NAMED_TEMPLATE" >> "$NAMED_CONF_FILE"
333        add_to_named_reload "all"
334    fi
335}
336
337remove_zone() {
338    local domain="$1"
339    local escaped_domain=`echo "$domain" | sed -e 's/\./\\\./g'`
340    local zone_file="$ZONES_DIR/$domain"
341
342    if [ -f "$zone_file" ]; then
343        rm -f "$zone_file"
344    fi
345
346    if grep -q "\"$escaped_domain\"" "$NAMED_CONF_FILE"; then
347        cp -a -f "$NAMED_CONF_FILE" "$NAMED_CONF_FILE.prec"
348        cp -a -f "$NAMED_CONF_FILE" "$NAMED_CONF_FILE.$$"
349        # That's for multi-line template
350        #sed -e "/^zone \"$escaped_domain\"/,/^};/d" \
351        # That's for one-line template
352        grep -v "^zone \"$escaped_domain\"" \
353            < "$NAMED_CONF_FILE" > "$NAMED_CONF_FILE.$$"
354        mv -f "$NAMED_CONF_FILE.$$" "$NAMED_CONF_FILE"
355        add_to_named_reload "all"
356    fi
357}
358
359change_mx() {
360    local domain="$1"
361    local mx="$2"
362    local zone_file="$ZONES_DIR/$domain"
363    local pattern="^@*[[:space:]]*IN[[:space:]]*MX[[:space:]]*[[:digit:]]*[[:space:]].*\$"
364    local mx_line="@    IN      MX      5       $mx."
365
366    # aller chercher le numéro de la ligne MX
367    # XXX: comportement inconnu si plusieurs matchs ou MX commenté
368    if grep -q "$pattern" "$zone_file"; then
369        cp -a -f "$zone_file" "$zone_file.$$"
370        sed -e "s/$pattern/$mx_line/" < "$zone_file" > "$zone_file.$$"
371        mv "$zone_file.$$" "$zone_file"
372    else
373        echo "$mx_line" >> "$zone_file"
374    fi
375
376    increment_serial "$domain"
377    add_to_named_reload "$domain"
378}
379
380
381########################################################################
382# Main
383#
384
385# Init
386
387touch "$LOCK_FILE"
388DOMAINS_TMP_FILE=`mktemp -t alternc.update_domains.XXXXXX`
389HOSTS_TMP_FILE=`mktemp -t alternc.update_domains.XXXXXX`
390RELOAD_ZONES_TMP_FILE=`mktemp -t alternc.update_domains.XXXXXX`
391CHANGED_PHP_OVERRIDES_TMP_FILE=`mktemp -t alternc.update_domains.XXXXXX`
392
393cleanup() {
394    rm -f "$LOCK_FILE" "$DOMAINS_TMP_FILE" "$HOSTS_TMP_FILE"
395    rm -f "$RELOAD_ZONES_TMP_FILE" "$CHANGED_PHP_OVERRIDES_TMP_FILE"
396    exit 0
397}
398
399trap cleanup 1 2 15
400
401# Query database
402
403cat << EOF | $MYSQL_SELECT | tail -n '+1' > "$DOMAINS_TMP_FILE"
404SELECT membres.login,
405       domaines_standby.domaine,
406       domaines_standby.mx,
407       domaines_standby.gesdns,
408       domaines_standby.gesmx,
409       domaines_standby.action
410  FROM domaines_standby
411       LEFT JOIN membres membres
412               ON membres.uid = domaines_standby.compte
413 ORDER BY domaines_standby.action
414EOF
415
416cat << EOF | $MYSQL_SELECT | tail -n '+1' > "$HOSTS_TMP_FILE"
417SELECT membres.login,
418       sub_domaines_standby.domaine,
419       if (sub_domaines_standby.sub = '', '@', sub_domaines_standby.sub),
420       if (sub_domaines_standby.valeur = '', 'NULL',
421                                             sub_domaines_standby.valeur),
422       sub_domaines_standby.type,
423       sub_domaines_standby.action
424  FROM sub_domaines_standby
425       LEFT JOIN membres membres
426               ON membres.uid = sub_domaines_standby.compte
427 ORDER BY sub_domaines_standby.action desc
428EOF
429
430# Handle domain updates
431
432if [ "`wc -l < $DOMAINS_TMP_FILE`" -gt 0 ]; then
433    echo `date` >> $DOMAIN_LOG_FILE
434    cat "$DOMAINS_TMP_FILE" >> $DOMAIN_LOG_FILE
435fi
436
437# We need to tweak the IFS as $MYSQL_SELECT use tabs to separate fields
438OLD_IFS="$IFS"
439IFS="   "
440cat "$DOMAINS_TMP_FILE" |
441while read user domain mx are_we_dns are_we_mx action; do
442    IFS="$OLD_IFS" 
443
444    DOMAIN_LETTER=`print_domain_letter "$domain"`
445    USER_LETTER=`print_user_letter "$user"`
446
447    add_to_php_override "$domain"
448    add_to_php_override "www.$domain"
449
450    case "$action" in
451      $ACTION_INSERT)
452        # default symlinks
453        ln -snf "${HTML_HOME}/${USER_LETTER}/$user" \
454                "${HTTP_DNS}/${DOMAIN_LETTER}/$domain"
455        ln -snf "${HTML_HOME}/${USER_LETTER}/$user" \
456                "${HTTP_DNS}/${DOMAIN_LETTER}/www.$domain"
457        ln -snf "${WEBMAIL_DIR}" "${HTTP_DNS}/${DOMAIN_LETTER}/mail.$domain"
458                       
459        if [ "$are_we_dns" = "$YES" ] ; then
460            init_zone "$domain"
461            change_host_ip "$domain" "$PUBLIC_IP"
462            change_host_ip "$domain" "$PUBLIC_IP" www
463            change_host_ip "$domain" "$PUBLIC_IP" mail
464        fi
465        ;;
466
467      $ACTION_UPDATE)
468        if [ "$are_we_dns" = "$YES" ] ; then
469            init_zone "$domain"
470            change_mx "$domain" "$mx"
471        else
472            remove_zone "$domain"
473        fi
474        ;;
475
476      $ACTION_DELETE)
477        remove_zone "$domain"
478
479        # remove symlinks
480        rm -f "${HTTP_DNS}/${DOMAIN_LETTER}/"*".$domain"
481        rm -f "${HTTP_DNS}/${DOMAIN_LETTER}/$domain"
482        rm -rf "${HTTP_DNS}/redir/${DOMAIN_LETTER}/"*".$domain"
483        rm -rf "${HTTP_DNS}/redir/${DOMAIN_LETTER}/$domain"
484        ;;
485
486      *)
487        echo "Unknown action code: $action" >> "$DOMAIN_LOG_FILE"
488        ;;
489    esac
490
491    IFS="       "
492done
493IFS="$OLD_IFS"
494
495# Handle hosts update
496
497if [ "`wc -l < $HOSTS_TMP_FILE`" -gt 0 ] ; then
498    echo `date` >> $DOMAIN_LOG_FILE
499    cat "$HOSTS_TMP_FILE" >> $DOMAIN_LOG_FILE
500fi
501
502OLD_IFS="$IFS"
503IFS="   "
504cat "$HOSTS_TMP_FILE" |
505while read user domain host value type action; do
506    IFS="$OLD_IFS"
507
508    if [ "$host" = "@" ]; then
509        FQDN="$domain"
510    else
511        FQDN="$host.$domain"
512    fi
513    if [ "$type" != "$TYPE_IP" ]; then
514        add_to_php_override "$FQDN"
515    fi
516
517    case "$action" in
518      $ACTION_UPDATE | $ACTION_INSERT)
519        add_host "$domain" "$type" "$host" "$value" "$user"
520        ;;
521
522      $ACTION_DELETE)
523        delete_host "$domain" "$host"
524        ;;
525
526      *)
527        echo "Unknown action code: $action" >> "$DOMAIN_LOG_FILE"
528        ;;
529    esac
530
531    IFS="       "
532done
533IFS="$OLD_IFS"
534
535# Update PHP overrides (basedir protection)
536for domain in `cat "$CHANGED_PHP_OVERRIDES_TMP_FILE"`; do
537    /usr/lib/alternc/basedir_prot.sh "$domain" >> "$DOMAIN_LOG_FILE"
538done
539
540# Reload configuration for named and apache
541
542RELOAD_ZONES=`cat "$RELOAD_ZONES_TMP_FILE"`
543if [ ! -z "$RELOAD_ZONES" ]; then
544    if [ "$RELOAD_ZONES" = "all" ]; then
545        rndc reload
546    else
547        for zone in $RELOAD_ZONES; do
548            rndc reload "$zone"
549        done
550    fi
551    apachectl graceful >> "$DOMAIN_LOG_FILE"
552fi
553
554# Cleanup
555
556echo "DELETE FROM domaines_standby" | $MYSQL_DELETE 
557echo "DELETE FROM sub_domaines_standby" | $MYSQL_DELETE 
558
559cleanup
560
561# vim: et sw=4
Note: See TracBrowser for help on using the repository browser.