diff --git a/contrib/cygwin/ssh-host-config b/contrib/cygwin/ssh-host-config index db6aaa08..d934d09b 100644 --- a/contrib/cygwin/ssh-host-config +++ b/contrib/cygwin/ssh-host-config @@ -63,6 +63,7 @@ sshd_config_configured=no port_number=22 service_name=sshd strictmodes=yes +privsep_used=yes cygwin_value="" user_account= password_value= @@ -139,21 +140,33 @@ sshd_strictmodes() { # ====================================================================== # Routine: sshd_privsep -# Try to create ssshd user account +# MODIFIES: privsep_used # ====================================================================== sshd_privsep() { local ret=0 if [ "${sshd_config_configured}" != "yes" ] then - if ! csih_create_unprivileged_user sshd + echo + csih_inform "Privilege separation is set to 'sandbox' by default since" + csih_inform "OpenSSH 6.1. This is unsupported by Cygwin and has to be set" + csih_inform "to 'yes' or 'no'." + csih_inform "However, using privilege separation requires a non-privileged account" + csih_inform "called 'sshd'." + csih_inform "For more info on privilege separation read /usr/share/doc/openssh/README.privsep." + if csih_request "Should privilege separation be used?" then - csih_error_recoverable "Could not create user 'sshd'!" - csih_error_recoverable "You will not be able to run an sshd service" - csih_error_recoverable "under a privileged account successfully." - csih_error_recoverable "Make sure to create a non-privileged user 'sshd'" - csih_error_recoverable "manually before trying to run the service!" - let ++ret + privsep_used=yes + if ! csih_create_unprivileged_user sshd + then + csih_error_recoverable "Couldn't create user 'sshd'!" + csih_error_recoverable "Privilege separation set to 'no' again!" + csih_error_recoverable "Check your ${SYSCONFDIR}/sshd_config file!" + let ++ret + privsep_used=no + fi + else + privsep_used=no fi fi return $ret @@ -189,6 +202,18 @@ sshd_config_tweak() { let ++ret fi fi + if [ "${sshd_config_configured}" != "yes" ] + then + /usr/bin/sed -i -e " + s/^#\?UsePrivilegeSeparation .*/UsePrivilegeSeparation ${privsep_used}/" \ + ${SYSCONFDIR}/sshd_config + if [ $? -ne 0 ] + then + csih_warning "Setting privilege separation failed!" + csih_warning "Check your ${SYSCONFDIR}/sshd_config file!" + let ++ret + fi + fi return $ret } # --- End of sshd_config_tweak --- # @@ -668,7 +693,7 @@ then fi fi -# handle sshd_config +# handle sshd_config (and privsep) csih_install_config "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults" || let ++warning_cnt if ! /usr/bin/cmp "${SYSCONFDIR}/sshd_config" "${SYSCONFDIR}/defaults/${SYSCONFDIR}/sshd_config" >/dev/null 2>&1 then diff --git a/servconf.c b/servconf.c index 0f0d0906..a63cec91 100644 --- a/servconf.c +++ b/servconf.c @@ -590,7 +590,7 @@ static struct { { "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL }, { "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL }, { "authorizedkeysfile2", sDeprecated, SSHCFG_ALL }, - { "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL}, + { "useprivilegeseparation", sUsePrivilegeSeparation, SSHCFG_GLOBAL}, { "acceptenv", sAcceptEnv, SSHCFG_ALL }, { "permittunnel", sPermitTunnel, SSHCFG_ALL }, { "permittty", sPermitTTY, SSHCFG_ALL }, @@ -1130,6 +1130,13 @@ static const struct multistate multistate_gatewayports[] = { { "no", 0 }, { NULL, -1 } }; +static const struct multistate multistate_privsep[] = { + { "yes", PRIVSEP_NOSANDBOX }, + { "sandbox", PRIVSEP_ON }, + { "nosandbox", PRIVSEP_NOSANDBOX }, + { "no", PRIVSEP_OFF }, + { NULL, -1 } +}; static const struct multistate multistate_tcpfwd[] = { { "yes", FORWARD_ALLOW }, { "all", FORWARD_ALLOW }, @@ -1563,6 +1570,11 @@ process_server_config_line(ServerOptions *options, char *line, intptr = &options->disable_forwarding; goto parse_flag; + case sUsePrivilegeSeparation: + intptr = &use_privsep; + multistate_ptr = multistate_privsep; + goto parse_multistate; + case sAllowUsers: while ((arg = strdelim(&cp)) && *arg != '\0') { if (match_user(NULL, NULL, NULL, arg) == -1) @@ -2289,6 +2301,8 @@ fmt_intarg(ServerOpCodes code, int val) return fmt_multistate_int(val, multistate_gatewayports); case sCompression: return fmt_multistate_int(val, multistate_compression); + case sUsePrivilegeSeparation: + return fmt_multistate_int(val, multistate_privsep); case sAllowTcpForwarding: return fmt_multistate_int(val, multistate_tcpfwd); case sAllowStreamLocalForwarding: @@ -2480,6 +2494,7 @@ dump_config(ServerOptions *o) dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding); dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding); dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); + dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep); dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info); diff --git a/sshd.c b/sshd.c index fd95b681..697f5a8b 100644 --- a/sshd.c +++ b/sshd.c @@ -228,7 +228,6 @@ int startup_pipe; /* in child */ int use_privsep = -1; struct monitor *pmonitor = NULL; int privsep_is_preauth = 1; -static int privsep_chroot = 1; /* global authentication context */ Authctxt *the_authctxt = NULL; @@ -541,7 +540,7 @@ privsep_preauth_child(void) demote_sensitive_data(); /* Demote the child */ - if (privsep_chroot) { + if (getuid() == 0 || geteuid() == 0) { /* Change our root directory */ if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, @@ -1641,9 +1640,8 @@ main(int ac, char **av) ); /* Store privilege separation user for later use if required. */ - privsep_chroot = use_privsep && (getuid() == 0 || geteuid() == 0); if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) { - if (privsep_chroot || options.kerberos_authentication) + if (use_privsep || options.kerberos_authentication) fatal("Privilege separation user %s does not exist", SSH_PRIVSEP_USER); } else { @@ -1801,7 +1790,7 @@ main(int ac, char **av) key_type(key)); } - if (privsep_chroot) { + if (use_privsep) { struct stat st; if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || diff --git a/sshd_config b/sshd_config index 3109d5d7..018b5eb2 100644 --- a/sshd_config +++ b/sshd_config @@ -92,6 +92,7 @@ AuthorizedKeysFile .ssh/authorized_keys #PrintLastLog yes #TCPKeepAlive yes #UseLogin no +#UsePrivilegeSeparation sandbox #PermitUserEnvironment no #Compression delayed #ClientAliveInterval 0 diff --git a/sshd_config.5 b/sshd_config.5 index e3c7c393..20a185f0 100644 --- a/sshd_config.5 +++ b/sshd_config.5 @@ -1542,6 +1542,28 @@ is enabled, you will not be able to run as a non-root user. The default is .Cm no . +.It Cm UsePrivilegeSeparation +Specifies whether +.Xr sshd 8 +separates privileges by creating an unprivileged child process +to deal with incoming network traffic. +After successful authentication, another process will be created that has +the privilege of the authenticated user. +The goal of privilege separation is to prevent privilege +escalation by containing any corruption within the unprivileged processes. +The argument must be +.Cm yes , +.Cm no , +or +.Cm sandbox . +If +.Cm UsePrivilegeSeparation +is set to +.Cm sandbox +then the pre-authentication unprivileged process is subject to additional +restrictions. +The default is +.Cm sandbox . .It Cm VersionAddendum Optionally specifies additional text to append to the SSH protocol banner sent by the server upon connection.