Mercurial > dropbear
comparison svr-auth.c @ 808:d7784616409a
improve auth failure delays to avoid indicating which users exist
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 26 May 2013 18:39:24 +0800 |
parents | e0084f136cb8 |
children | 8fe36617bf4e |
comparison
equal
deleted
inserted
replaced
782:e0084f136cb8 | 808:d7784616409a |
---|---|
108 * checking, and handle success or failure */ | 108 * checking, and handle success or failure */ |
109 void recv_msg_userauth_request() { | 109 void recv_msg_userauth_request() { |
110 | 110 |
111 unsigned char *username = NULL, *servicename = NULL, *methodname = NULL; | 111 unsigned char *username = NULL, *servicename = NULL, *methodname = NULL; |
112 unsigned int userlen, servicelen, methodlen; | 112 unsigned int userlen, servicelen, methodlen; |
113 int valid_user = 0; | |
113 | 114 |
114 TRACE(("enter recv_msg_userauth_request")) | 115 TRACE(("enter recv_msg_userauth_request")) |
115 | 116 |
116 /* ignore packets if auth is already done */ | 117 /* ignore packets if auth is already done */ |
117 if (ses.authstate.authdone == 1) { | 118 if (ses.authstate.authdone == 1) { |
122 /* send the banner if it exists, it will only exist once */ | 123 /* send the banner if it exists, it will only exist once */ |
123 if (svr_opts.banner) { | 124 if (svr_opts.banner) { |
124 send_msg_userauth_banner(); | 125 send_msg_userauth_banner(); |
125 } | 126 } |
126 | 127 |
127 | |
128 username = buf_getstring(ses.payload, &userlen); | 128 username = buf_getstring(ses.payload, &userlen); |
129 servicename = buf_getstring(ses.payload, &servicelen); | 129 servicename = buf_getstring(ses.payload, &servicelen); |
130 methodname = buf_getstring(ses.payload, &methodlen); | 130 methodname = buf_getstring(ses.payload, &methodlen); |
131 | 131 |
132 /* only handle 'ssh-connection' currently */ | 132 /* only handle 'ssh-connection' currently */ |
139 m_free(servicename); | 139 m_free(servicename); |
140 m_free(methodname); | 140 m_free(methodname); |
141 dropbear_exit("unknown service in auth"); | 141 dropbear_exit("unknown service in auth"); |
142 } | 142 } |
143 | 143 |
144 /* check username is good before continuing */ | 144 /* check username is good before continuing. |
145 if (checkusername(username, userlen) == DROPBEAR_FAILURE) { | 145 * the 'incrfail' varies depending on the auth method to |
146 /* username is invalid/no shell/etc - send failure */ | 146 * avoid giving away which users exist on the system through |
147 TRACE(("sending checkusername failure")) | 147 * the time delay. */ |
148 send_msg_userauth_failure(0, 1); | 148 if (checkusername(username, userlen) == DROPBEAR_SUCCESS) { |
149 goto out; | 149 valid_user = 1; |
150 } | 150 } |
151 | 151 |
152 /* user wants to know what methods are supported */ | 152 /* user wants to know what methods are supported */ |
153 if (methodlen == AUTH_METHOD_NONE_LEN && | 153 if (methodlen == AUTH_METHOD_NONE_LEN && |
154 strncmp(methodname, AUTH_METHOD_NONE, | 154 strncmp(methodname, AUTH_METHOD_NONE, |
155 AUTH_METHOD_NONE_LEN) == 0) { | 155 AUTH_METHOD_NONE_LEN) == 0) { |
156 TRACE(("recv_msg_userauth_request: 'none' request")) | 156 TRACE(("recv_msg_userauth_request: 'none' request")) |
157 if (svr_opts.allowblankpass | 157 if (valid_user |
158 && svr_opts.allowblankpass | |
158 && !svr_opts.noauthpass | 159 && !svr_opts.noauthpass |
159 && !(svr_opts.norootpass && ses.authstate.pw_uid == 0) | 160 && !(svr_opts.norootpass && ses.authstate.pw_uid == 0) |
160 && ses.authstate.pw_passwd[0] == '\0') | 161 && ses.authstate.pw_passwd[0] == '\0') |
161 { | 162 { |
162 dropbear_log(LOG_NOTICE, | 163 dropbear_log(LOG_NOTICE, |
166 send_msg_userauth_success(); | 167 send_msg_userauth_success(); |
167 goto out; | 168 goto out; |
168 } | 169 } |
169 else | 170 else |
170 { | 171 { |
172 /* 'none' has no failure delay */ | |
171 send_msg_userauth_failure(0, 0); | 173 send_msg_userauth_failure(0, 0); |
172 goto out; | 174 goto out; |
173 } | 175 } |
174 } | 176 } |
175 | 177 |
178 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { | 180 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { |
179 /* user wants to try password auth */ | 181 /* user wants to try password auth */ |
180 if (methodlen == AUTH_METHOD_PASSWORD_LEN && | 182 if (methodlen == AUTH_METHOD_PASSWORD_LEN && |
181 strncmp(methodname, AUTH_METHOD_PASSWORD, | 183 strncmp(methodname, AUTH_METHOD_PASSWORD, |
182 AUTH_METHOD_PASSWORD_LEN) == 0) { | 184 AUTH_METHOD_PASSWORD_LEN) == 0) { |
183 svr_auth_password(); | 185 if (valid_user) { |
184 goto out; | 186 svr_auth_password(); |
187 goto out; | |
188 } | |
185 } | 189 } |
186 } | 190 } |
187 #endif | 191 #endif |
188 | 192 |
189 #ifdef ENABLE_SVR_PAM_AUTH | 193 #ifdef ENABLE_SVR_PAM_AUTH |
191 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { | 195 !(svr_opts.norootpass && ses.authstate.pw_uid == 0) ) { |
192 /* user wants to try password auth */ | 196 /* user wants to try password auth */ |
193 if (methodlen == AUTH_METHOD_PASSWORD_LEN && | 197 if (methodlen == AUTH_METHOD_PASSWORD_LEN && |
194 strncmp(methodname, AUTH_METHOD_PASSWORD, | 198 strncmp(methodname, AUTH_METHOD_PASSWORD, |
195 AUTH_METHOD_PASSWORD_LEN) == 0) { | 199 AUTH_METHOD_PASSWORD_LEN) == 0) { |
196 svr_auth_pam(); | 200 if (valid_user) { |
197 goto out; | 201 svr_auth_pam(); |
202 goto out; | |
203 } | |
198 } | 204 } |
199 } | 205 } |
200 #endif | 206 #endif |
201 | 207 |
202 #ifdef ENABLE_SVR_PUBKEY_AUTH | 208 #ifdef ENABLE_SVR_PUBKEY_AUTH |
203 /* user wants to try pubkey auth */ | 209 /* user wants to try pubkey auth */ |
204 if (methodlen == AUTH_METHOD_PUBKEY_LEN && | 210 if (methodlen == AUTH_METHOD_PUBKEY_LEN && |
205 strncmp(methodname, AUTH_METHOD_PUBKEY, | 211 strncmp(methodname, AUTH_METHOD_PUBKEY, |
206 AUTH_METHOD_PUBKEY_LEN) == 0) { | 212 AUTH_METHOD_PUBKEY_LEN) == 0) { |
207 svr_auth_pubkey(); | 213 if (valid_user) { |
214 svr_auth_pubkey(); | |
215 } else { | |
216 /* pubkey has no failure delay */ | |
217 send_msg_userauth_failure(0, 0); | |
218 } | |
208 goto out; | 219 goto out; |
209 } | 220 } |
210 #endif | 221 #endif |
211 | 222 |
212 /* nothing matched, we just fail */ | 223 /* nothing matched, we just fail with a delay */ |
213 send_msg_userauth_failure(0, 1); | 224 send_msg_userauth_failure(0, 1); |
214 | 225 |
215 out: | 226 out: |
216 | 227 |
217 m_free(username); | 228 m_free(username); |
250 if (!ses.authstate.pw_name) { | 261 if (!ses.authstate.pw_name) { |
251 TRACE(("leave checkusername: user '%s' doesn't exist", username)) | 262 TRACE(("leave checkusername: user '%s' doesn't exist", username)) |
252 dropbear_log(LOG_WARNING, | 263 dropbear_log(LOG_WARNING, |
253 "Login attempt for nonexistent user from %s", | 264 "Login attempt for nonexistent user from %s", |
254 svr_ses.addrstring); | 265 svr_ses.addrstring); |
255 send_msg_userauth_failure(0, 1); | |
256 return DROPBEAR_FAILURE; | 266 return DROPBEAR_FAILURE; |
257 } | 267 } |
258 | 268 |
259 /* check if we are running as non-root, and login user is different from the server */ | 269 /* check if we are running as non-root, and login user is different from the server */ |
260 uid = geteuid(); | 270 uid = geteuid(); |
262 TRACE(("running as nonroot, only server uid is allowed")) | 272 TRACE(("running as nonroot, only server uid is allowed")) |
263 dropbear_log(LOG_WARNING, | 273 dropbear_log(LOG_WARNING, |
264 "Login attempt with wrong user %s from %s", | 274 "Login attempt with wrong user %s from %s", |
265 ses.authstate.pw_name, | 275 ses.authstate.pw_name, |
266 svr_ses.addrstring); | 276 svr_ses.addrstring); |
267 send_msg_userauth_failure(0, 1); | |
268 return DROPBEAR_FAILURE; | 277 return DROPBEAR_FAILURE; |
269 } | 278 } |
270 | 279 |
271 /* check for non-root if desired */ | 280 /* check for non-root if desired */ |
272 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { | 281 if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { |
273 TRACE(("leave checkusername: root login disabled")) | 282 TRACE(("leave checkusername: root login disabled")) |
274 dropbear_log(LOG_WARNING, "root login rejected"); | 283 dropbear_log(LOG_WARNING, "root login rejected"); |
275 send_msg_userauth_failure(0, 1); | |
276 return DROPBEAR_FAILURE; | 284 return DROPBEAR_FAILURE; |
277 } | 285 } |
278 | 286 |
279 TRACE(("shell is %s", ses.authstate.pw_shell)) | 287 TRACE(("shell is %s", ses.authstate.pw_shell)) |
280 | 288 |
299 /* no matching shell */ | 307 /* no matching shell */ |
300 endusershell(); | 308 endusershell(); |
301 TRACE(("no matching shell")) | 309 TRACE(("no matching shell")) |
302 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", | 310 dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", |
303 ses.authstate.pw_name); | 311 ses.authstate.pw_name); |
304 send_msg_userauth_failure(0, 1); | |
305 return DROPBEAR_FAILURE; | 312 return DROPBEAR_FAILURE; |
306 | 313 |
307 goodshell: | 314 goodshell: |
308 endusershell(); | 315 endusershell(); |
309 TRACE(("matching shell")) | 316 TRACE(("matching shell")) |
310 | 317 |
311 TRACE(("uid = %d", ses.authstate.pw_uid)) | 318 TRACE(("uid = %d", ses.authstate.pw_uid)) |
312 TRACE(("leave checkusername")) | 319 TRACE(("leave checkusername")) |
313 return DROPBEAR_SUCCESS; | 320 return DROPBEAR_SUCCESS; |
314 | |
315 } | 321 } |
316 | 322 |
317 /* Send a failure message to the client, in responds to a userauth_request. | 323 /* Send a failure message to the client, in responds to a userauth_request. |
318 * Partial indicates whether to set the "partial success" flag, | 324 * Partial indicates whether to set the "partial success" flag, |
319 * incrfail is whether to count this failure in the failure count (which | 325 * incrfail is whether to count this failure in the failure count (which |
356 encrypt_packet(); | 362 encrypt_packet(); |
357 | 363 |
358 if (incrfail) { | 364 if (incrfail) { |
359 unsigned int delay; | 365 unsigned int delay; |
360 genrandom((unsigned char*)&delay, sizeof(delay)); | 366 genrandom((unsigned char*)&delay, sizeof(delay)); |
361 /* We delay for 300ms +- 50ms, 0.1ms granularity */ | 367 /* We delay for 300ms +- 50ms */ |
362 delay = 250000 + (delay % 1000)*100; | 368 delay = 250000 + (delay % 100000); |
363 usleep(delay); | 369 usleep(delay); |
364 ses.authstate.failcount++; | 370 ses.authstate.failcount++; |
365 } | 371 } |
366 | 372 |
367 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { | 373 if (ses.authstate.failcount >= MAX_AUTH_TRIES) { |