root/alternc/tags/0.9.6/src/update_domains.sh

Revision 1672, 15.1 kB (checked in by anarcat, 2 years ago)

change proper ip even if modifying TLD, closes: #661

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