root/alternc/trunk/src/functions.sh

Revision 2117, 9.4 kB (checked in by anarcat, 8 months ago)

Major redesign of the MySQL backend interface to fix a security issue.
See: #318.

As of now, the MySQL configuration used everywhere by AlternC is not
stored in the main configuration file (/etc/alternc/local.sh) but in a
MySQL configuration file in /etc/alternc/my.cnf, which enables us to
call mysql without exposing the password on the commandline.

The changes here are quite invasive but will allow us to factor out
the MySQL configuration better. See #364.

This includes a partial rewrite of the mysql.sh logic, which is now ran
from the postinst script (and not alternc.install) which will allow us
to actually change the MySQL root user properly. See #601.

This commit was tested like this:

  • clean install on etch (working)
  • upgrade from a clean 0.9.7 (working)
Line 
1 # some miscellaneous shell functions
2
3 print_domain_letter() {
4     local domain="$1"
5
6     local letter=`echo "$domain" | awk '{z=split($NF, a, ".") ; print substr(a[z-1], 1, 1)}'`
7     if [ -z "$letter" ]; then
8       letter="_"
9     fi
10     echo $letter
11 }
12
13 print_user_letter() {
14     local user="$1"
15
16     echo "$user" | awk '{print substr($1, 1, 1)}'
17 }
18
19 add_to_php_override() {
20     local fqdn="$1"
21
22     /usr/lib/alternc/basedir_prot.sh "$fqdn" >> "$DOMAIN_LOG_FILE"
23 }
24
25 remove_php_override() {
26     local fqdn="$1"
27     local letter=`print_domain_letter $fqdn`
28
29     sed -i "/$fqdn/d" $APACHECONF_DIR/override_php.conf
30     rm -f $APACHECONF_DIR/$letter/$fqdn
31 }
32
33 add_to_named_reload() {
34     local domain="$1"
35     local escaped_domain=`echo "$domain" | sed -e 's/\./\\\./g'`
36
37     if [ "domain" = "all" ] || grep -q "^all$" "$RELOAD_ZONES_TMP_FILE"; then
38         echo "all" > "$RELOAD_ZONES_TMP_FILE"
39     else
40         if ! grep -q "^${escaped_domain}$" "$RELOAD_ZONES_TMP_FILE"; then
41             echo "$domain" >> "$RELOAD_ZONES_TMP_FILE"
42         fi
43     fi
44 }
45
46 # we assume that the serial line contains the "serial string", eg.:
47 #                 2005012703      ; serial
48 #
49 # returns 1 if file isn't readable
50 # returns 2 if we can't find the serial number
51 # returns 3 if a tempfile can't be created
52 increment_serial() {
53     local domain="$1"
54     local zone_file="$ZONES_DIR/$domain"
55     local current_serial
56     local new_serial
57     local date
58     local revision
59     local today
60
61     if [ ! -f "$zone_file" ]; then
62         return 1
63     fi
64
65     # the assumption is here
66     current_serial=`awk '/^..*serial/ {print $1}' < "$zone_file"` || return 2
67     if [ -z "$current_serial" ]; then
68         return 2
69     fi
70
71     date=`echo $current_serial | cut -c1-8`
72     revision=`echo $current_serial | sed s/"${date}0\?"/""/g`
73     today=`date +%Y%m%d`
74     # increment the serial number only if the date hasn't changed
75     if [ "$date" = "$today" ] ; then
76         revision=$(($revision + 1))
77     else
78         revision=1
79         date=$today
80     fi
81     new_serial="$date`printf '%.2d' $revision`"
82
83     # replace serial number
84     cp -a -f "$zone_file" "$zone_file.$$"
85     awk -v "NEW_SERIAL=$new_serial" \
86         '{if ($3 == "serial")
87              print "            "NEW_SERIAL "   ; serial"
88           else
89              print $0}' < "$zone_file" > "$zone_file.$$"
90     mv -f "$zone_file.$$" "$zone_file"
91
92     add_to_named_reload "$domain"
93
94     return 0
95 }
96
97 change_host_ip() {
98     local domain="$1"
99     local zone_file="$ZONES_DIR/$domain"
100     local ip="$2"
101     local host="$3"
102     local pattern
103     local a_line
104
105     if [ -z "$host" ]; then
106         host="@"
107     fi
108     a_line="$host       IN      A       $ip"
109     pattern="^$host[[:space:]]*IN[[:space:]]*A[[:space:]]*.*\$"
110     if [ ! -f "$zone_file" ]; then
111         echo "Should change $host.$domain, but can't find $zone_file."
112         return 1
113     fi
114     if grep -q "$pattern" "$zone_file"; then
115         cp -a -f "$zone_file" "$zone_file.$$"
116         sed "s/$pattern/$a_line/" < "$zone_file" > "$zone_file.$$"
117         mv "$zone_file.$$" "$zone_file"
118     else
119         echo "$a_line" >> "$zone_file"
120     fi
121     add_to_named_reload "$domain"
122 }
123
124 add_host() {
125     local domain="$1"
126     local host_type="$2"
127     local host="$3"
128     local value="$4"
129     local user="$5"
130     local domain_letter=`print_domain_letter "$domain"`
131     local user_letter=`print_user_letter "$user"`
132     local ip
133     local fqdn
134     local vhost_directory
135        
136     delete_host "$domain" "$host"
137
138     if [ "$host" = "@" -o -z "$host" ]; then
139         FQDN="$domain"
140     else
141         FQDN="$host.$domain"
142     fi
143
144     if [ "$host_type" = "$TYPE_IP" ]; then
145        ip="$value"
146     else
147        ip="$PUBLIC_IP"
148        if [ "$host_type" != "$TYPE_WEBMAIL" ]; then
149            add_to_php_override "$FQDN"
150        fi
151     fi
152     if [ "$host" = "@" -o -z "$host" ]; then
153         change_host_ip "$domain" "$ip" || true
154         fqdn="$domain"
155     else
156         change_host_ip "$domain" "$ip" "$host" || true
157         fqdn="${host}.${domain}"
158     fi
159
160     vhost_directory="${HTTP_DNS}/${domain_letter}/${fqdn}"
161     htaccess_directory="${HTTP_DNS}/redir/${domain_letter}/${fqdn}"
162
163     case "$host_type" in
164       $TYPE_LOCAL)
165         ln -snf "${HTML_HOME}/${user_letter}/${user}${value}" \
166                 "$vhost_directory"
167         ;;
168
169       $TYPE_WEBMAIL)
170         ln -snf "${WEBMAIL_DIR}" "$vhost_directory"
171         ;;
172
173       $TYPE_URL)
174         mkdir -p "$htaccess_directory"
175         # normalize the url provided to make sure the hostname part is
176         # followed by at least /
177         value=`echo $value | sed -e 's#\([^/:]*://\)\?\([^/]*\)/*\(.*\)#\1\2/\3#'`
178
179         (echo "RewriteEngine on"
180          echo "RewriteRule (.*) ${value}\$1 [R,L]"
181         ) > "$htaccess_directory/.htaccess"
182         ln -snf "$htaccess_directory" "$vhost_directory"
183         ;;
184        
185       $TYPE_IP)
186         rm -f "$vhost_directory"
187         rm -rf "$htaccess_directory/.htaccess"
188         ;;
189
190       *)
191         echo "Unknow type code: $type" >> "$DOMAIN_LOG_FILE"
192         ;;
193     esac
194 }
195
196 delete_host() {
197     local domain="$1"
198     local host="$2"
199     local domain_letter=`print_domain_letter "$domain"`
200     local fqdn
201     local escaped_host
202     local escaped_fqdn
203    
204     if [ "$host" = "@" -o -z "$host" ]; then
205         fqdn="$domain"
206         escaped_host=""
207     else
208         fqdn="$host.$domain"
209         escaped_host=`echo "$host" | sed 's/\([\*|\.]\)/\\\\\1/g'`
210     fi
211
212     if [ -f "$ZONES_DIR/$domain" ] ; then
213         cp -a -f "$ZONES_DIR/$domain" "$ZONES_DIR/$domain.$$"
214         sed -e "/^$escaped_host[[:space:]]*IN[[:space:]]*A[[:space:]]/d" \
215             < "$ZONES_DIR/$domain" > "$ZONES_DIR/$domain.$$"
216         mv "$ZONES_DIR/$domain.$$" "$ZONES_DIR/$domain"
217         increment_serial "$domain"
218         add_to_named_reload "$domain"
219     fi
220
221     rm -f "$APACHECONF_DIR/$domain_letter/$fqdn"
222
223     escaped_fqdn=`echo "$fqdn" | sed 's/\([\*|\.]\)/\\\\\1/g'`
224
225     cp -a -f "$OVERRIDE_PHP_FILE" "$OVERRIDE_PHP_FILE.$$"
226     sed -e "/\/${escaped_fqdn}\$/d" \
227         < "$OVERRIDE_PHP_FILE" > "$OVERRIDE_PHP_FILE.$$"
228     mv "$OVERRIDE_PHP_FILE.$$" "$OVERRIDE_PHP_FILE"
229
230     rm -f "$HTTP_DNS/$domain_letter/$fqdn"
231     rm -rf "$HTTP_DNS/redir/$domain_letter/$fqdn"
232 }
233
234
235 init_zone() {
236     local domain="$1"
237     local escaped_domain=`echo "$domain" | sed -e 's/\./\\\./g'`
238     local zone_file="$ZONES_DIR/$domain"
239     local serial
240
241     if [ ! -f "$zone_file" ]; then
242         serial=`date +%Y%m%d`00
243         sed -e "s/@@DOMAINE@@/$domain/g;s/@@SERIAL@@/$serial/g" \
244             < "$ZONE_TEMPLATE" > "$zone_file"
245         chgrp bind "$zone_file"
246         chmod 640  "$zone_file"
247     fi
248     if ! grep -q "\"$escaped_domain\"" "$NAMED_CONF_FILE"; then
249         cp -a -f "$NAMED_CONF_FILE" "$NAMED_CONF_FILE".prec
250         sed -e "s/@@DOMAINE@@/$domain/g" \
251                 < "$NAMED_TEMPLATE" >> "$NAMED_CONF_FILE"
252         add_to_named_reload "all"
253     fi
254 }
255
256 remove_zone() {
257     local domain="$1"
258     local escaped_domain=`echo "$domain" | sed -e 's/\./\\\./g'`
259     local zone_file="$ZONES_DIR/$domain"
260
261     if [ -f "$zone_file" ]; then
262         rm -f "$zone_file"
263     fi
264
265     if grep -q "\"$escaped_domain\"" "$NAMED_CONF_FILE"; then
266         cp -a -f "$NAMED_CONF_FILE" "$NAMED_CONF_FILE.prec"
267         cp -a -f "$NAMED_CONF_FILE" "$NAMED_CONF_FILE.$$"
268         # That's for multi-line template
269         #sed -e "/^zone \"$escaped_domain\"/,/^};/d" \
270         # That's for one-line template
271         grep -v "^zone \"$escaped_domain\"" \
272             < "$NAMED_CONF_FILE" > "$NAMED_CONF_FILE.$$" || true
273         mv -f "$NAMED_CONF_FILE.$$" "$NAMED_CONF_FILE"
274         add_to_named_reload "all"
275     fi
276 }
277
278 change_mx() {
279     local domain="$1"
280     local mx="$2"
281     local zone_file="$ZONES_DIR/$domain"
282     local pattern="^@*[[:space:]]*IN[[:space:]]*MX[[:space:]]*[[:digit:]]*[[:space:]].*\$"
283     local mx_line="@    IN      MX      5       $mx."
284
285     # aller chercher le numéro de la ligne MX
286     # XXX: comportement inconnu si plusieurs matchs ou MX commenté
287     if grep -q "$pattern" "$zone_file"; then
288         cp -a -f "$zone_file" "$zone_file.$$"
289         sed -e "s/$pattern/$mx_line/" < "$zone_file" > "$zone_file.$$"
290         mv "$zone_file.$$" "$zone_file"
291     else
292         echo "$mx_line" >> "$zone_file"
293     fi
294
295     increment_serial "$domain"
296     add_to_named_reload "$domain"
297 }
298
299
300
301 # imprime le nom d'usager associé au domaine
302 get_account_by_domain() {
303         # les admintools ne sont peut-être pas là
304         if [ -x "/usr/bin/get_account_by_domain" ]
305         then
306                 # only first field, only first line
307                 /usr/bin/get_account_by_domain "$1" | cut -d\  -f1 | cut -d'
308 ' -f 1
309         else
310                 # implantons localement ce que nous avons besoin, puisque admintools
311                 # n'est pas là
312                 mysql --defaults-file=/etc/alternc/my.cnf -B -N -e \
313                 'SELECT a.login FROM membres a, sub_domaines b WHERE a.uid = b.compte AND \
314                 CONCAT(IF(sub="", "", CONCAT(sub, ".")), domaine) = "'"$1"'" LIMIT 1;'
315         fi
316 }
317
318 # add the standard input to a given file, only if not already present
319 append_no_dupe() {
320         realfile="$1"
321         tmpfile=`mktemp`
322         trap "rm -f $tmpfile; exit 1" 1 2 15
323         cat > $tmpfile
324         if [ -r "$realfile" ] &&
325                 (diff -q "$tmpfile" "$realfile" > /dev/null || \
326                         diff -u "$tmpfile" "$realfile"  | grep '^ ' | sed 's/^ //' | diff -q - "$tmpfile" > /dev/null)
327         then
328                 ret=0
329         else
330                 ret=1
331                 cat "$tmpfile" >> "$realfile"
332         fi
333         rm -f "$tmpfile"
334         return "$ret"
335 }
336
337 add_dom_entry() {
338         # protect ourselves from interrupts
339         trap "rm -f ${override_f}.new; exit 1" 1 2 15
340         # ajouter une entrée, seulement s'il n'y en pas déjà, pour ce domaine
341         (echo "$1"; [ -r $override_f ] && cat $override_f) | \
342         sort -u > ${override_f}.new && \
343         cp ${override_f}.new ${override_f} && \
344         rm ${override_f}.new
345 }
Note: See TracBrowser for help on using the browser.