import of openssh-5.8p1
[openssh.git] / contrib / cygwin / ssh-host-config
1 #!/bin/bash
2 #
3 # ssh-host-config, Copyright 2000-2009 Red Hat Inc.
4 #
5 # This file is part of the Cygwin port of OpenSSH.
6 #
7 # Permission to use, copy, modify, and distribute this software for any
8 # purpose with or without fee is hereby granted, provided that the above
9 # copyright notice and this permission notice appear in all copies.
10 #
11 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  
12 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               
13 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   
14 # IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   
15 # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    
16 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    
17 # THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               
18
19 # ======================================================================
20 # Initialization
21 # ======================================================================
22 PROGNAME=$(basename $0)
23 _tdir=$(dirname $0)
24 PROGDIR=$(cd $_tdir && pwd)
25
26 CSIH_SCRIPT=/usr/share/csih/cygwin-service-installation-helper.sh
27
28 # Subdirectory where the new package is being installed
29 PREFIX=/usr
30
31 # Directory where the config files are stored
32 SYSCONFDIR=/etc
33 LOCALSTATEDIR=/var
34
35 source ${CSIH_SCRIPT}
36
37 port_number=22
38 privsep_configured=no
39 privsep_used=yes
40 cygwin_value=""
41 user_account=
42 password_value=
43 opt_force=no
44
45 # ======================================================================
46 # Routine: create_host_keys
47 # ======================================================================
48 create_host_keys() {
49   if [ ! -f "${SYSCONFDIR}/ssh_host_key" ]
50   then
51     csih_inform "Generating ${SYSCONFDIR}/ssh_host_key"
52     ssh-keygen -t rsa1 -f ${SYSCONFDIR}/ssh_host_key -N '' > /dev/null
53   fi
54
55   if [ ! -f "${SYSCONFDIR}/ssh_host_rsa_key" ]
56   then
57     csih_inform "Generating ${SYSCONFDIR}/ssh_host_rsa_key"
58     ssh-keygen -t rsa -f ${SYSCONFDIR}/ssh_host_rsa_key -N '' > /dev/null
59   fi
60
61   if [ ! -f "${SYSCONFDIR}/ssh_host_dsa_key" ]
62   then
63     csih_inform "Generating ${SYSCONFDIR}/ssh_host_dsa_key"
64     ssh-keygen -t dsa -f ${SYSCONFDIR}/ssh_host_dsa_key -N '' > /dev/null
65   fi
66 } # --- End of create_host_keys --- #
67
68 # ======================================================================
69 # Routine: update_services_file
70 # ======================================================================
71 update_services_file() {
72   local _my_etcdir="/ssh-host-config.$$"
73   local _win_etcdir
74   local _services
75   local _spaces
76   local _serv_tmp
77   local _wservices
78
79   if csih_is_nt
80   then
81     _win_etcdir="${SYSTEMROOT}\\system32\\drivers\\etc"
82     _services="${_my_etcdir}/services"
83     # On NT, 27 spaces, no space after the hash
84     _spaces="                           #"
85   else
86     _win_etcdir="${WINDIR}"
87     _services="${_my_etcdir}/SERVICES"
88     # On 9x, 18 spaces (95 is very touchy), a space after the hash
89     _spaces="                  # "
90   fi
91   _serv_tmp="${_my_etcdir}/srv.out.$$"
92
93   mount -o text,posix=0,noacl -f "${_win_etcdir}" "${_my_etcdir}"
94
95   # Depends on the above mount
96   _wservices=`cygpath -w "${_services}"`
97
98   # Remove sshd 22/port from services
99   if [ `grep -q 'sshd[ \t][ \t]*22' "${_services}"; echo $?` -eq 0 ]
100   then
101     grep -v 'sshd[ \t][ \t]*22' "${_services}" > "${_serv_tmp}"
102     if [ -f "${_serv_tmp}" ]
103     then
104       if mv "${_serv_tmp}" "${_services}"
105       then
106         csih_inform "Removing sshd from ${_wservices}"
107       else
108         csih_warning "Removing sshd from ${_wservices} failed!"
109       fi
110       rm -f "${_serv_tmp}"
111     else
112       csih_warning "Removing sshd from ${_wservices} failed!"
113     fi
114   fi
115
116   # Add ssh 22/tcp  and ssh 22/udp to services
117   if [ `grep -q 'ssh[ \t][ \t]*22' "${_services}"; echo $?` -ne 0 ]
118   then
119     if awk '{ if ( $2 ~ /^23\/tcp/ ) print "ssh                22/tcp'"${_spaces}"'SSH Remote Login Protocol\nssh                22/udp'"${_spaces}"'SSH Remote Login Protocol"; print $0; }' < "${_services}" > "${_serv_tmp}"
120     then
121       if mv "${_serv_tmp}" "${_services}"
122       then
123         csih_inform "Added ssh to ${_wservices}"
124       else
125         csih_warning "Adding ssh to ${_wservices} failed!"
126       fi
127       rm -f "${_serv_tmp}"
128     else
129       csih_warning "Adding ssh to ${_wservices} failed!"
130     fi
131   fi
132   umount "${_my_etcdir}"
133 } # --- End of update_services_file --- #
134
135 # ======================================================================
136 # Routine: sshd_privsep
137 #  MODIFIES: privsep_configured  privsep_used
138 # ======================================================================
139 sshd_privsep() {
140   local sshdconfig_tmp
141
142   if [ "${privsep_configured}" != "yes" ]
143   then
144     if csih_is_nt
145     then
146       csih_inform "Privilege separation is set to yes by default since OpenSSH 3.3."
147       csih_inform "However, this requires a non-privileged account called 'sshd'."
148       csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep."
149       if csih_request "Should privilege separation be used?"
150       then
151         privsep_used=yes
152         if ! csih_create_unprivileged_user sshd
153         then
154           csih_warning "Couldn't create user 'sshd'!"
155           csih_warning "Privilege separation set to 'no' again!"
156           csih_warning "Check your ${SYSCONFDIR}/sshd_config file!"
157           privsep_used=no
158         fi
159       else
160         privsep_used=no
161       fi
162     else
163       # On 9x don't use privilege separation.  Since security isn't
164       # available it just adds useless additional processes.
165       privsep_used=no
166     fi
167   fi
168
169   # Create default sshd_config from skeleton files in /etc/defaults/etc or
170   # modify to add the missing privsep configuration option
171   if cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
172   then
173     csih_inform "Updating ${SYSCONFDIR}/sshd_config file"
174     sshdconfig_tmp=${SYSCONFDIR}/sshd_config.$$
175     sed -e "s/^#UsePrivilegeSeparation yes/UsePrivilegeSeparation ${privsep_used}/
176           s/^#Port 22/Port ${port_number}/
177           s/^#StrictModes yes/StrictModes no/" \
178         < ${SYSCONFDIR}/sshd_config \
179         > "${sshdconfig_tmp}"
180     mv "${sshdconfig_tmp}" ${SYSCONFDIR}/sshd_config
181   elif [ "${privsep_configured}" != "yes" ]
182   then
183     echo >> ${SYSCONFDIR}/sshd_config
184     echo "UsePrivilegeSeparation ${privsep_used}" >> ${SYSCONFDIR}/sshd_config
185   fi
186 } # --- End of sshd_privsep --- #
187
188 # ======================================================================
189 # Routine: update_inetd_conf
190 # ======================================================================
191 update_inetd_conf() {
192   local _inetcnf="${SYSCONFDIR}/inetd.conf"
193   local _inetcnf_tmp="${SYSCONFDIR}/inetd.conf.$$"
194   local _inetcnf_dir="${SYSCONFDIR}/inetd.d"
195   local _sshd_inetd_conf="${_inetcnf_dir}/sshd-inetd"
196   local _sshd_inetd_conf_tmp="${_inetcnf_dir}/sshd-inetd.$$"
197   local _with_comment=1
198
199   if [ -d "${_inetcnf_dir}" ]
200   then
201     # we have inetutils-1.5 inetd.d support
202     if [ -f "${_inetcnf}" ]
203     then
204       grep -q '^[ \t]*ssh' "${_inetcnf}" && _with_comment=0
205
206       # check for sshd OR ssh in top-level inetd.conf file, and remove
207       # will be replaced by a file in inetd.d/
208       if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -eq 0 ]
209       then
210         grep -v '^[# \t]*ssh' "${_inetcnf}" >> "${_inetcnf_tmp}"
211         if [ -f "${_inetcnf_tmp}" ]
212         then
213           if mv "${_inetcnf_tmp}" "${_inetcnf}"
214           then
215             csih_inform "Removed ssh[d] from ${_inetcnf}"
216           else
217             csih_warning "Removing ssh[d] from ${_inetcnf} failed!"
218           fi
219           rm -f "${_inetcnf_tmp}"
220         else
221           csih_warning "Removing ssh[d] from ${_inetcnf} failed!"
222         fi
223       fi
224     fi
225
226     csih_install_config "${_sshd_inetd_conf}"   "${SYSCONFDIR}/defaults"
227     if cmp "${SYSCONFDIR}/defaults${_sshd_inetd_conf}" "${_sshd_inetd_conf}" >/dev/null 2>&1
228     then
229       if [ "${_with_comment}" -eq 0 ]
230       then
231         sed -e 's/@COMMENT@[ \t]*//' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
232       else
233         sed -e 's/@COMMENT@[ \t]*/# /' < "${_sshd_inetd_conf}" > "${_sshd_inetd_conf_tmp}"
234       fi
235       mv "${_sshd_inetd_conf_tmp}" "${_sshd_inetd_conf}"
236       csih_inform "Updated ${_sshd_inetd_conf}"
237     fi
238
239   elif [ -f "${_inetcnf}" ]
240   then
241     grep -q '^[ \t]*sshd' "${_inetcnf}" && _with_comment=0
242
243     # check for sshd in top-level inetd.conf file, and remove
244     # will be replaced by a file in inetd.d/
245     if [ `grep -q '^[# \t]*sshd' "${_inetcnf}"; echo $?` -eq 0 ]
246     then
247       grep -v '^[# \t]*sshd' "${_inetcnf}" >> "${_inetcnf_tmp}"
248       if [ -f "${_inetcnf_tmp}" ]
249       then
250         if mv "${_inetcnf_tmp}" "${_inetcnf}"
251         then
252             csih_inform "Removed sshd from ${_inetcnf}"
253         else
254             csih_warning "Removing sshd from ${_inetcnf} failed!"
255         fi
256         rm -f "${_inetcnf_tmp}"
257       else
258         csih_warning "Removing sshd from ${_inetcnf} failed!"
259       fi
260     fi
261
262     # Add ssh line to inetd.conf
263     if [ `grep -q '^[# \t]*ssh' "${_inetcnf}"; echo $?` -ne 0 ]
264     then
265       if [ "${_with_comment}" -eq 0 ]
266       then
267         echo 'ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
268       else
269         echo '# ssh  stream  tcp     nowait  root    /usr/sbin/sshd sshd -i' >> "${_inetcnf}"
270       fi
271       csih_inform "Added ssh to ${_inetcnf}"
272     fi
273   fi
274 } # --- End of update_inetd_conf --- #
275
276 # ======================================================================
277 # Routine: install_service
278 #   Install sshd as a service
279 # ======================================================================
280 install_service() {
281   local run_service_as
282   local password
283
284   if csih_is_nt
285   then
286     if ! cygrunsrv -Q sshd >/dev/null 2>&1
287     then
288       echo
289       echo
290       csih_warning "The following functions require administrator privileges!"
291       echo
292       echo -e "${_csih_QUERY_STR} Do you want to install sshd as a service?"
293       if csih_request "(Say \"no\" if it is already installed as a service)"
294       then
295         csih_get_cygenv "${cygwin_value}"
296
297         if ( csih_is_nt2003 || [ "$csih_FORCE_PRIVILEGED_USER" = "yes" ] )
298         then
299           csih_inform "On Windows Server 2003, Windows Vista, and above, the"
300           csih_inform "SYSTEM account cannot setuid to other users -- a capability"
301           csih_inform "sshd requires.  You need to have or to create a privileged"
302           csih_inform "account.  This script will help you do so."
303           echo
304
305           [ "${opt_force}" = "yes" ] && opt_f=-f
306           [ -n "${user_account}" ] && opt_u="-u ""${user_account}"""
307           csih_select_privileged_username ${opt_f} ${opt_u} sshd
308
309           if ! csih_create_privileged_user "${password_value}"
310           then
311             csih_error_recoverable "There was a serious problem creating a privileged user."
312             csih_request "Do you want to proceed anyway?" || exit 1
313           fi
314         fi
315
316         # never returns empty if NT or above
317         run_service_as=$(csih_service_should_run_as)
318
319         if [ "${run_service_as}" = "${csih_PRIVILEGED_USERNAME}" ]
320         then
321           password="${csih_PRIVILEGED_PASSWORD}"
322           if [ -z "${password}" ]
323           then
324             csih_get_value "Please enter the password for user '${run_service_as}':" "-s"
325             password="${csih_value}"
326           fi
327         fi
328
329         # at this point, we either have $run_service_as = "system" and $password is empty,
330         # or $run_service_as is some privileged user and (hopefully) $password contains
331         # the correct password.  So, from here out, we use '-z "${password}"' to discriminate
332         # the two cases.
333
334         csih_check_user "${run_service_as}"
335
336         if [ -n "${csih_cygenv}" ]
337         then
338           cygwin_env=( -e "CYGWIN=${csih_cygenv}" )
339         fi
340         if [ -z "${password}" ]
341         then
342           if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd \
343                             -a "-D" -y tcpip "${cygwin_env[@]}"
344           then
345             echo
346             csih_inform "The sshd service has been installed under the LocalSystem"
347             csih_inform "account (also known as SYSTEM). To start the service now, call"
348             csih_inform "\`net start sshd' or \`cygrunsrv -S sshd'.  Otherwise, it"
349             csih_inform "will start automatically after the next reboot."
350           fi
351         else
352           if cygrunsrv -I sshd -d "CYGWIN sshd" -p /usr/sbin/sshd \
353                             -a "-D" -y tcpip "${cygwin_env[@]}" \
354                             -u "${run_service_as}" -w "${password}"
355           then
356             echo
357             csih_inform "The sshd service has been installed under the '${run_service_as}'"
358             csih_inform "account.  To start the service now, call \`net start sshd' or"
359             csih_inform "\`cygrunsrv -S sshd'.  Otherwise, it will start automatically"
360             csih_inform "after the next reboot."
361           fi
362         fi
363
364         # now, if successfully installed, set ownership of the affected files
365         if cygrunsrv -Q sshd >/dev/null 2>&1
366         then
367           chown "${run_service_as}" ${SYSCONFDIR}/ssh*
368           chown "${run_service_as}".544 ${LOCALSTATEDIR}/empty
369           chown "${run_service_as}".544 ${LOCALSTATEDIR}/log/lastlog
370           if [ -f ${LOCALSTATEDIR}/log/sshd.log ]
371           then
372             chown "${run_service_as}".544 ${LOCALSTATEDIR}/log/sshd.log
373           fi
374         else
375           csih_warning "Something went wrong installing the sshd service."
376         fi
377       fi # user allowed us to install as service
378     fi # service not yet installed
379   fi # csih_is_nt
380 } # --- End of install_service --- #
381
382 # ======================================================================
383 # Main Entry Point
384 # ======================================================================
385
386 # Check how the script has been started.  If
387 #   (1) it has been started by giving the full path and
388 #       that path is /etc/postinstall, OR
389 #   (2) Otherwise, if the environment variable
390 #       SSH_HOST_CONFIG_AUTO_ANSWER_NO is set
391 # then set auto_answer to "no".  This allows automatic
392 # creation of the config files in /etc w/o overwriting
393 # them if they already exist.  In both cases, color
394 # escape sequences are suppressed, so as to prevent
395 # cluttering setup's logfiles.
396 if [ "$PROGDIR" = "/etc/postinstall" ]
397 then
398   csih_auto_answer="no"
399   csih_disable_color
400   opt_force=yes
401 fi
402 if [ -n "${SSH_HOST_CONFIG_AUTO_ANSWER_NO}" ]
403 then
404   csih_auto_answer="no"
405   csih_disable_color
406   opt_force=yes
407 fi
408
409 # ======================================================================
410 # Parse options
411 # ======================================================================
412 while :
413 do
414   case $# in
415   0)
416     break
417     ;;
418   esac
419
420   option=$1
421   shift
422
423   case "${option}" in
424   -d | --debug )
425     set -x
426     csih_trace_on
427     ;;
428
429   -y | --yes )
430     csih_auto_answer=yes
431     opt_force=yes
432     ;;
433
434   -n | --no )
435     csih_auto_answer=no
436     opt_force=yes
437     ;;
438
439   -c | --cygwin )
440     cygwin_value="$1"
441     shift
442     ;;
443
444   -p | --port )
445     port_number=$1
446     shift
447     ;;
448
449   -u | --user )
450     user_account="$1"
451     shift
452     ;;
453     
454   -w | --pwd )
455     password_value="$1"
456     shift
457     ;;
458
459   --privileged )
460     csih_FORCE_PRIVILEGED_USER=yes
461     ;;
462
463   *)
464     echo "usage: ${progname} [OPTION]..."
465     echo
466     echo "This script creates an OpenSSH host configuration."
467     echo
468     echo "Options:"
469     echo "  --debug  -d            Enable shell's debug output."
470     echo "  --yes    -y            Answer all questions with \"yes\" automatically."
471     echo "  --no     -n            Answer all questions with \"no\" automatically."
472     echo "  --cygwin -c <options>  Use \"options\" as value for CYGWIN environment var."
473     echo "  --port   -p <n>        sshd listens on port n."
474     echo "  --user   -u <account>  privileged user for service."
475     echo "  --pwd    -w <passwd>   Use \"pwd\" as password for privileged user."
476     echo "  --privileged           On Windows NT/2k/XP, require privileged user"
477     echo "                         instead of LocalSystem for sshd service."
478     echo
479     exit 1
480     ;;
481
482   esac
483 done
484
485 # ======================================================================
486 # Action!
487 # ======================================================================
488
489 # Check for running ssh/sshd processes first. Refuse to do anything while
490 # some ssh processes are still running
491 if ps -ef | grep -q '/sshd\?$'
492 then
493   echo
494   csih_error "There are still ssh processes running. Please shut them down first."
495 fi
496
497 # Check for ${SYSCONFDIR} directory
498 csih_make_dir "${SYSCONFDIR}" "Cannot create global configuration files."
499 chmod 775 "${SYSCONFDIR}"
500 setfacl -m u:system:rwx "${SYSCONFDIR}"
501
502 # Check for /var/log directory
503 csih_make_dir "${LOCALSTATEDIR}/log" "Cannot create log directory."
504 chmod 775 "${LOCALSTATEDIR}/log"
505 setfacl -m u:system:rwx "${LOCALSTATEDIR}/log"
506
507 # Create /var/log/lastlog if not already exists
508 if [ -e ${LOCALSTATEDIR}/log/lastlog -a ! -f ${LOCALSTATEDIR}/log/lastlog ]
509 then
510   echo
511   csih_error_multi "${LOCALSTATEDIR}/log/lastlog exists, but is not a file." \
512                    "Cannot create ssh host configuration."
513 fi
514 if [ ! -e ${LOCALSTATEDIR}/log/lastlog ]
515 then
516   cat /dev/null > ${LOCALSTATEDIR}/log/lastlog
517   chmod 644 ${LOCALSTATEDIR}/log/lastlog
518 fi
519
520 # Create /var/empty file used as chroot jail for privilege separation
521 csih_make_dir "${LOCALSTATEDIR}/empty" "Cannot create ${LOCALSTATEDIR}/empty directory."
522 chmod 755 "${LOCALSTATEDIR}/empty"
523 setfacl -m u:system:rwx "${LOCALSTATEDIR}/empty"
524
525 # host keys
526 create_host_keys
527
528 # use 'cmp' program to determine if a config file is identical
529 # to the default version of that config file
530 csih_check_program_or_error cmp diffutils
531
532
533 # handle ssh_config
534 csih_install_config "${SYSCONFDIR}/ssh_config"   "${SYSCONFDIR}/defaults"
535 if cmp "${SYSCONFDIR}/ssh_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/ssh_config" >/dev/null 2>&1
536 then
537   if [ "${port_number}" != "22" ]
538   then
539     csih_inform "Updating ${SYSCONFDIR}/ssh_config file with requested port"
540     echo "Host localhost" >> ${SYSCONFDIR}/ssh_config
541     echo "    Port ${port_number}" >> ${SYSCONFDIR}/ssh_config
542   fi
543 fi
544
545 # handle sshd_config (and privsep)
546 csih_install_config "${SYSCONFDIR}/sshd_config"   "${SYSCONFDIR}/defaults"
547 if ! cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1
548 then
549   grep -q UsePrivilegeSeparation ${SYSCONFDIR}/sshd_config && privsep_configured=yes
550 fi
551 sshd_privsep
552
553
554
555 update_services_file
556 update_inetd_conf
557 install_service
558
559 echo
560 csih_inform "Host configuration finished. Have fun!"
561