CVE-2020-28013: Heap buffer overflow in parse_fix_phrase()
[exim.git] / src / scripts / exim_install
1 #! /bin/sh
2
3 # Script to install Exim binaries in BIN_DIRECTORY, which is defined in
4 # the local Makefile. It expects to be run in a build directory. It needs
5 # to be run as root in order to make exim setuid to root. If exim runs setuid
6 # to (e.g.) exim, this script should be run as that user or root.
7
8 # This script also installs a default configuration file in CONFIGURE_FILE
9 # if there is no configuration file there, but only if CONFIGURE_FILE specifies
10 # single file. If it specifies a list, no action is taken.
11
12 # If a default configuration file is installed, the existence of the system
13 # aliases file is tested. A default, containing only comments, is installed if
14 # necessary.
15
16 # If INFO_DIRECTORY is defined in any of the local Makefiles, and the Exim doc
17 # directory contains the Texinfo documentation, this script also installs a
18 # the info files in INFO_DIRECTORY.
19
20 # If DESTDIR is defined, all file paths are prefixed with ${DESTDIR}, with the
21 # sole exception of the reference to the system aliases file in the default
22 # configuration, because it is assumed that Exim is not actually going to be
23 # run from this position. For backward compatibility, if DESTDIR is not
24 # defined, ROOT is used instead.
25
26 # The script can be made to output what it would do, without actually doing
27 # anything, by giving it the option "-n" (cf make). Arguments are the names
28 # of things to install. No arguments installs everything.
29
30 do_chown=yes
31 do_symlink=yes
32
33 while [ $# -gt 0 ] ; do
34   case "$1" in
35     -n)
36       real="true || "
37       ver="verification "
38       com=": "
39       echo $com ""
40       echo $com "*** Verification mode only: no commands will actually be obeyed"
41       echo $com "*** You can cut and paste the bits you want to a shell, etc"
42       echo $com ""
43       echo cd `pwd`
44       ;;
45
46     -no_chown)
47       do_chown=no
48       ;;
49
50     -no_symlink)
51       do_symlink=no
52       ;;
53
54     *)
55       break
56       ;;
57   esac
58   shift
59 done
60
61 # Get the values of BIN_DIRECTORY, CONFIGURE_FILE, INFO_DIRECTORY, NO_SYMLINK,
62 # SYSTEM_ALIASES_FILE, and EXE from the global Makefile (in the build
63 # directory). EXE is empty except in the Cygwin environment. In each case, keep
64 # the latest definition, thus respecting the Makefiles precedence. The sed
65 # sequences here are messy, but have to be very "basic" in order to work on
66 # Solaris, where the regular expressions in sed are primitive indeed. Modify at
67 # your peril.
68
69 BIN_DIRECTORY=`sed -n   -e '/^ *BIN_DIRECTORY *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
70 CONFIGURE_FILE=`sed -n -e '/^ *CONFIGURE_FILE *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
71 INFO_DIRECTORY=`sed -n -e '/^ *INFO_DIRECTORY *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
72 NO_SYMLINK=`sed -n         -e '/^ *NO_SYMLINK *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
73
74 CHOWN=`sed -n           -e '/^ *CHOWN_COMMAND *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
75 MV=`sed -n                 -e '/^ *MV_COMMAND *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
76
77 SYSTEM_ALIASES_FILE=`sed -n -e '/^ *SYSTEM_ALIASES_FILE *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
78 EXE=`sed -n                                 -e '/^ *EXE *=/{s/^[^=]*= *//; s/ \{1,\}#.*//;s/ *$//;h;}' -e '${g;p;}' Makefile`
79
80 # Set a default for SYSTEM_ALIASES_FILE
81
82 if [ "${SYSTEM_ALIASES_FILE}" = "" ] ; then
83   SYSTEM_ALIASES_FILE=/etc/aliases
84 fi
85
86 # Allow INST_xx to over-ride xx
87 case "$INST_BIN_DIRECTORY"       in ?*) BIN_DIRECTORY="$INST_BIN_DIRECTORY";; esac
88 case "$INST_CONFIGURE_FILE"      in ?*) CONFIGURE_FILE="$INST_CONFIGURE_FILE";; esac
89 case "$INST_INFO_DIRECTORY"      in ?*) INFO_DIRECTORY="$INST_INFO_DIRECTORY";; esac
90 case "$INST_SYSTEM_ALIASES_FILE" in ?*) SYSTEM_ALIASES_FILE="$INST_SYSTEM_ALIASES_FILE";; esac
91
92 case "$INST_CHOWN"               in ?*) CHOWN="$INST_CHOWN";; esac
93 case "$INST_MV"                  in ?*) MV="$INST_MV";; esac
94
95 case "$INST_UID"     in '') INST_UID=root;;    *) INST_UID="$INST_UID";; esac
96 case "$INST_CP"      in '') CP=cp;;            *) CP="$INST_CP";; esac
97 case "$INST_LN"      in '') LN=ln;;            *) LN="$INST_LN";; esac
98 case "$INST_CHMOD"   in '') CHMOD=chmod;;      *) CHMOD="$INST_CHMOD";; esac
99 case "$INST_DIRNAME" in '') DIRNAME=dirname;;  *) DIRNAME="$INST_DIRNAME";; esac
100 case "$INST_MKDIR"   in '') MKDIR=mkdir;;      *) MKDIR="$INST_MKDIR";; esac
101
102 # Allow the user to over-ride xx
103 case "$inst_dest"    in ?*) BIN_DIRECTORY="$inst_dest";; esac
104 case "$inst_conf"    in ?*) CONFIGURE_FILE="$inst_conf";; esac
105 case "$inst_info"    in ?*) INFO_DIRECTORY="$inst_info";; esac
106 case "$inst_aliases" in ?*) SYSTEM_ALIASES_FILE="$inst_aliases";; esac
107
108 # Insert ${DESTDIR} at the start of all paths so that the whole thing can be
109 # installed under a different file root. For backwards compatibility, use
110 # ${ROOT} if ${DESTDIR} is not set. However, we need to save the value of
111 # the real system aliases file, and use that in the default configuration.
112
113 ACTUAL_SYSTEM_ALIASES_FILE=${SYSTEM_ALIASES_FILE}
114 DESTDIR=${DESTDIR:-${ROOT}}
115
116 BIN_DIRECTORY=${DESTDIR}${BIN_DIRECTORY}
117 CONFIGURE_FILE=${DESTDIR}${CONFIGURE_FILE}
118 SYSTEM_ALIASES_FILE=${DESTDIR}${SYSTEM_ALIASES_FILE}
119
120 if [ "${INFO_DIRECTORY}" != "" ] ; then
121   INFO_DIRECTORY=${DESTDIR}${INFO_DIRECTORY}
122 fi
123
124 # Overrides of other things
125 case "$inst_uid"     in ?*) INST_UID="$inst_uid";; esac
126 case "$inst_cp"      in ?*) CP="$inst_cp";; esac
127 case "$inst_mv"      in ?*) MV="$inst_mv";; esac
128 case "$inst_ln"      in ?*) LN="$inst_ln";; esac
129 case "$inst_chown"   in ?*) CHOWN="$inst_chown";; esac
130 case "$inst_chmod"   in ?*) CHMOD="$inst_chmod";; esac
131 case "$inst_dirname" in ?*) DIRNAME="$inst_dirname";; esac
132 case "$inst_mkdir"   in ?*) MKDIR="$inst_mkdir";; esac
133
134 # chown is a special case; in at least one OS it is in /usr/etc instead
135 # of in /usr/bin, and therefore not likely to be on the path. Another OS
136 # has it in /usr/sbin. This fudge tries to cope with these variations.
137
138 # Otherwise, and for other commands, we assume that the normal PATH will
139 # give access to where they are on your operating system (normally /usr/bin
140 # or /bin).
141
142 if [ "${CHOWN}" = "chown" -a -x /usr/sbin/chown ] ; then
143   CHOWN=/usr/sbin/chown
144 fi
145
146 if [ "${CHOWN}" = "chown" -a ! -f /usr/bin/chown -a -f /usr/etc/chown ] ; then
147   CHOWN=/usr/etc/chown
148 fi
149
150 # The values of CHOWN and MV taken from the Makefile are sometimes set to
151 # "look_for_it", which causes a search of the usual suspects. This code is
152 # similar to that in exicyclog, but has to be fudged for upper/lower case
153 # distinctions.
154
155 for cmd in CHOWN MV ; do
156   eval "oldcmd=\$$cmd"
157   if [ "$oldcmd" != "look_for_it" ] ; then continue ; fi
158   if [ "$cmd" = "CHOWN" ] ; then cmdlc="chown" ; fi
159   if [ "$cmd" = "MV" ] ; then cmdlc="mv" ; fi
160   newcmd=$cmdlc
161   for dir in /bin /usr/bin /usr/sbin /usr/etc ; do
162     if [ -f $dir/$cmdlc ] ; then
163       newcmd=$dir/$cmdlc
164       break
165     fi
166   done
167   eval $cmd=$newcmd
168 done
169
170 # See if the exim monitor has been built
171
172 if [ -f eximon -a -f eximon.bin ]; then
173   exim_monitor="eximon eximon.bin"
174 fi
175
176 # If bin directory doesn't exist, try to create it
177
178 if [ ! -d "${BIN_DIRECTORY}" ]; then
179   echo mkdir -p ${BIN_DIRECTORY}
180   ${real} mkdir -p ${BIN_DIRECTORY}
181   if [ $? -ne 0 ]; then
182     echo $com ""
183     echo $com "*** Exim installation ${ver}failed ***"
184     exit 1
185   else
186     ${real} echo $com ${BIN_DIRECTORY} created
187   fi
188 fi
189
190 # If no arguments, install everything
191
192 if [ $# -gt 0 ]; then
193   set $@
194 else
195   set exim${EXE} ${exim_monitor} exim_dumpdb${EXE} exim_fixdb${EXE} \
196       exim_tidydb${EXE} exinext exiwhat exim_dbmbuild${EXE} exicyclog \
197       exigrep eximstats exipick exiqgrep exiqsumm exim_lock${EXE} \
198       exim_checkaccess
199 fi
200
201 echo $com ""
202 echo $com Installation directory is ${BIN_DIRECTORY}
203 echo $com ""
204
205 while [ $# -gt 0 ]; do
206   name=$1
207   shift
208
209   if [ ! -s ${name} ]; then
210     echo $com ""
211     echo $com "*** `pwd`/${name} does not exist or is empty"
212     echo $com "*** Have you built Exim successfully?"
213     echo $com "*** Exim installation ${ver}failed ***"
214     exit 1
215   fi
216
217   # The exim binary is handled specially
218
219   if [ $name = exim${EXE} ]; then
220     exim="./exim -bV -C /dev/null"
221     version=exim-`$exim 2>/dev/null | \
222       awk '/Exim version/ { OFS=""; print $3,"-",substr($4,2,length($4)-1) }'`${EXE}
223
224     if [ "${version}" = "exim-${EXE}" ]; then
225       echo $com ""
226       echo $com "*** Could not run $exim to find version number ***"
227       echo $com "*** Exim installation ${ver}failed ***"
228       $exim
229       exit 1
230     fi
231
232     # Do something only if newer than existing file, or no existing file
233
234     if ../scripts/newer ${name} ${BIN_DIRECTORY}/${version}; then
235       echo ${CP} ${name} ${BIN_DIRECTORY}/${version}
236       ${real} ${CP} ${name} ${BIN_DIRECTORY}/${version}
237       if [ $? -ne 0 ]; then
238         echo $com ""
239         echo $com "*** Exim installation ${ver}failed ***"
240         exit 1
241       fi
242
243       # After copy, set ownership and permissions, unless disabled
244
245       if [ "$do_chown" != "no" ]; then
246         echo ${CHOWN} ${INST_UID} ${BIN_DIRECTORY}/${version}
247         ${real} ${CHOWN} ${INST_UID} ${BIN_DIRECTORY}/${version}
248         if [ $? -ne 0 ]; then
249           echo $com ""
250           echo $com "*** You must be ${INST_UID} to install exim ***"
251           exit 1
252         fi
253         echo ${CHMOD} a+x ${BIN_DIRECTORY}/${version}
254         ${real} ${CHMOD} a+x ${BIN_DIRECTORY}/${version}
255         if [ $? -ne 0 ]; then
256           echo $com ""
257           echo $com "*** Exim installation ${ver}failed ***"
258           exit 1
259         fi
260         echo ${CHMOD} u+s ${BIN_DIRECTORY}/${version}
261         ${real} ${CHMOD} u+s ${BIN_DIRECTORY}/${version}
262         if [ $? -ne 0 ]; then
263           echo $com ""
264           echo $com "*** Exim installation ${ver}failed ***"
265           exit 1
266         fi
267       else
268         echo $com "$CHOWN $INST_UID omitted: -no_chown was specified"
269         echo $com "$CHMOD u+s omitted: -no_chown was specified"
270       fi
271
272       # Now sort out the "exim" alias, unless NO_SYMLINK is set.
273
274       if [ "X$NO_SYMLINK" = "X" ] && [ "$do_symlink" != "no" ] ; then
275
276         #  First check whether "exim" exists in the directory.
277         if [ -f ${BIN_DIRECTORY}/exim ]; then
278
279           # If it's not a symbolic link, make a copy with the old version number
280           if [ `ls -l ${BIN_DIRECTORY}/exim | cut -c1-1` != 'l' ]; then
281             oldversion=exim-`${BIN_DIRECTORY}/exim -bV -C /dev/null | \
282               awk '/Exim version/ { OFS=""; print $3,"-",substr($4,2,length($4)-1) }'`${EXE}
283             if [ "${version}" = "${oldversion}" ] ; then
284               echo $com ""
285               echo $com "*** Existing file called exim has the same version and compile number ***"
286               echo $com "*** Exim installation ${ver}failed ***"
287               exit 1
288             fi
289             echo ${CP} ${BIN_DIRECTORY}/exim ${BIN_DIRECTORY}/${oldversion}
290             ${real} ${CP} ${BIN_DIRECTORY}/exim ${BIN_DIRECTORY}/${oldversion}
291             if [ $? -ne 0 ]; then
292               echo $com ""
293               echo $com "*** Exim installation ${ver}failed ***"
294               exit 1
295             fi
296           fi
297
298           # Now we can move the name "exim" to be a symbolic link to the new
299           # version, atomically.
300
301           echo \(cd ${BIN_DIRECTORY}\; ${LN} -s ${version} temporary_exim\)
302           (${real} cd ${BIN_DIRECTORY}; ${real} ${LN} -s ${version} temporary_exim)
303           if [ $? -ne 0 ]; then
304             echo $com ""
305             echo $com "*** Exim installation ${ver}failed ***"
306             exit 1
307           fi
308
309           echo ${MV} -f ${BIN_DIRECTORY}/temporary_exim ${BIN_DIRECTORY}/exim
310           ${real} ${MV} -f ${BIN_DIRECTORY}/temporary_exim ${BIN_DIRECTORY}/exim
311           if [ $? -ne 0 ]; then
312             echo $com ""
313             echo $com "*** Exim installation ${ver}failed ***"
314             exit 1
315           fi
316
317         # If "exim" does not already exist just create a symbolic link.
318
319         else
320           echo \(cd ${BIN_DIRECTORY}\; ${LN} -s ${version} exim\)
321           (${real} cd ${BIN_DIRECTORY}; ${real} ${LN} -s ${version} exim)
322           if [ $? -ne 0 ]; then
323             echo $com ""
324             echo $com "*** Exim installation ${ver}failed ***"
325             exit 1
326           fi
327         fi
328
329       else
330         echo $com "creation of symlink omitted"
331         if [ "X$NO_SYMLINK" != "X" ] ; then
332           echo $com "(NO_SYMLINK is specified in Local/Makefile)"
333         else
334           echo $com "(-no_symlink was specified)"
335         fi
336       fi
337
338     # New binary is not newer than the installed file
339
340     else
341       echo $com ${name} is not newer than ${BIN_DIRECTORY}/${version}
342     fi
343
344   # Handle everything other than the exim binary itself
345
346   else
347     if ../scripts/newer ${name} ${BIN_DIRECTORY}/${name}; then
348       if [ -f ${BIN_DIRECTORY}/${name} ]; then
349         echo ${CP} ${BIN_DIRECTORY}/${name} ${BIN_DIRECTORY}/${name}.O
350         ${real} ${CP} ${BIN_DIRECTORY}/${name} ${BIN_DIRECTORY}/${name}.O
351         if [ $? -ne 0 ]; then
352           echo $com ""
353           echo $com "*** Exim installation ${ver}failed ***"
354           exit 1
355         fi
356       fi
357       echo ${CP} ${name} ${BIN_DIRECTORY}
358       ${real} ${CP} ${name} ${BIN_DIRECTORY}
359       if [ $? -ne 0 ]; then
360         echo $com ""
361         echo $com "*** Exim installation ${ver}failed ***"
362         exit 1
363       fi
364     else
365       echo $com ${name} is not newer than ${BIN_DIRECTORY}/${name}
366     fi
367   fi
368
369 done
370
371
372
373 # If there is no configuration file, install the default, modifying it to refer
374 # to the configured system aliases file. If there is no setting for
375 # SYSTEM_ALIASES_FILE, use the traditional /etc/aliases. If the file does not
376 # exist, install a default (dummy) for that too.
377
378 # However, if CONFIGURE_FILE specifies a list of files, skip this code.
379
380 echo $com ""
381
382 if [ `expr -- "${CONFIGURE_FILE}" : ".*:"` -ne 0 ] ; then
383   echo $com Runtime configuration is specified as the following list:
384   echo $com ' ' ${CONFIGURE_FILE}
385   echo $com Therefore, skipping automatic installation.
386
387 elif [ ! -f ${CONFIGURE_FILE} ]; then
388   echo $com Installing default configuration in ${CONFIGURE_FILE}
389   echo $com because there is no existing configuration file.
390   if [ "${SYSTEM_ALIASES_FILE}" = "" ] ; then
391     SYSTEM_ALIASES_FILE=/etc/aliases
392     echo $com This configuration has system aliases in ${SYSTEM_ALIASES_FILE}.
393   fi
394
395   echo ${MKDIR} -p `${DIRNAME} ${CONFIGURE_FILE}`
396   ${real} ${MKDIR} -p `${DIRNAME} ${CONFIGURE_FILE}`
397
398   echo sed -e '\\'
399   echo "  \"/SYSTEM_ALIASES_FILE/ s'SYSTEM_ALIASES_FILE'${ACTUAL_SYSTEM_ALIASES_FILE}'\"" '\\'
400   echo "  ../src/configure.default > \${CONFIGURE_FILE}"
401
402   # I can't find a way of writing this using the ${real} feature because
403   # it seems that the output redirection always happens, even when -n was
404   # specified. So control it the hard way.
405
406   if [ "$real" = "" ] ; then
407     sed -e \
408       "/SYSTEM_ALIASES_FILE/ s'SYSTEM_ALIASES_FILE'${ACTUAL_SYSTEM_ALIASES_FILE}'" \
409       ../src/configure.default > ${CONFIGURE_FILE}
410   else
411     true
412   fi
413
414   if [ $? -ne 0 ]; then
415     echo $com ""
416     echo $com "*** Exim installation ${ver}failed ***"
417     exit 1
418   fi
419   if [ ! -f ${SYSTEM_ALIASES_FILE} ]; then
420     echo $com '****'
421     echo $com Installing a dummy ${SYSTEM_ALIASES_FILE} file because you do not have
422     echo $com one, and the default configuration requires it. You should
423     echo $com edit ${SYSTEM_ALIASES_FILE} and at least create an alias for postmaster.
424     echo $com '***'
425     echo ${CP} ../src/aliases.default ${SYSTEM_ALIASES_FILE}
426     ${real} ${CP} ../src/aliases.default ${SYSTEM_ALIASES_FILE}
427   fi
428
429 else
430   echo $com Configuration file ${CONFIGURE_FILE} already exists
431 fi
432
433 # Install info files if the directory is defined and the Texinfo
434 # source documentation is present.
435
436 if [ "${INFO_DIRECTORY}" != "" -a -f ../doc/spec.texinfo ] ; then
437   echo $com ""
438   if [ ! -d "${INFO_DIRECTORY}" ] ; then
439     echo mkdir -p ${INFO_DIRECTORY}
440     ${real} mkdir -p ${INFO_DIRECTORY}
441     if [ $? -ne 0 ]; then
442       echo $com ""
443       echo $com "*** Exim installation ${ver}failed ***"
444       exit 1
445     else
446       echo $com ${INFO_DIRECTORY} created
447     fi
448   fi
449
450   echo $com Info installation directory is ${INFO_DIRECTORY}
451   echo $com ""
452
453   ${real} makeinfo --no-split --output exim.info ../doc/spec.texinfo
454   echo ${CP} exim.info ${INFO_DIRECTORY}
455   ${real} ${CP} exim.info ${INFO_DIRECTORY}
456   ${real} install-info --section="Exim" \
457       --entry "* User guide: (exim).           Exim manual" \
458       ${INFO_DIRECTORY}/exim.info ${INFO_DIRECTORY}/dir
459   ${real} makeinfo --no-split --output exim_filter.info ../doc/filter.texinfo
460   echo ${CP} exim_filter.info ${INFO_DIRECTORY}
461   ${real} ${CP} exim_filter.info ${INFO_DIRECTORY}
462   ${real} install-info --section="Exim" \
463       --entry "* Filtering: (exim_filter).     Filtering mail with Exim" \
464       ${INFO_DIRECTORY}/exim_filter.info ${INFO_DIRECTORY}/dir
465 fi
466
467 # Everything OK
468
469 echo $com ""
470 echo $com Exim installation ${ver}complete
471
472 # End of exim_install