1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
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.
|