diff options
Diffstat (limited to 'auth2.c')
-rw-r--r-- | auth2.c | 81 |
1 files changed, 64 insertions, 17 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2.c,v 1.145 2018/03/03 03:15:51 djm Exp $ */ | 1 | /* $OpenBSD: auth2.c,v 1.149 2018/07/11 18:53:29 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -41,28 +41,30 @@ | |||
41 | #include "ssh2.h" | 41 | #include "ssh2.h" |
42 | #include "packet.h" | 42 | #include "packet.h" |
43 | #include "log.h" | 43 | #include "log.h" |
44 | #include "buffer.h" | 44 | #include "sshbuf.h" |
45 | #include "misc.h" | 45 | #include "misc.h" |
46 | #include "servconf.h" | 46 | #include "servconf.h" |
47 | #include "compat.h" | 47 | #include "compat.h" |
48 | #include "key.h" | 48 | #include "sshkey.h" |
49 | #include "hostfile.h" | 49 | #include "hostfile.h" |
50 | #include "auth.h" | 50 | #include "auth.h" |
51 | #include "dispatch.h" | 51 | #include "dispatch.h" |
52 | #include "pathnames.h" | 52 | #include "pathnames.h" |
53 | #include "buffer.h" | 53 | #include "sshbuf.h" |
54 | #include "ssherr.h" | ||
54 | 55 | ||
55 | #ifdef GSSAPI | 56 | #ifdef GSSAPI |
56 | #include "ssh-gss.h" | 57 | #include "ssh-gss.h" |
57 | #endif | 58 | #endif |
58 | #include "monitor_wrap.h" | 59 | #include "monitor_wrap.h" |
59 | #include "ssherr.h" | 60 | #include "ssherr.h" |
61 | #include "digest.h" | ||
60 | 62 | ||
61 | /* import */ | 63 | /* import */ |
62 | extern ServerOptions options; | 64 | extern ServerOptions options; |
63 | extern u_char *session_id2; | 65 | extern u_char *session_id2; |
64 | extern u_int session_id2_len; | 66 | extern u_int session_id2_len; |
65 | extern Buffer loginmsg; | 67 | extern struct sshbuf *loginmsg; |
66 | 68 | ||
67 | /* methods */ | 69 | /* methods */ |
68 | 70 | ||
@@ -210,6 +212,43 @@ input_service_request(int type, u_int32_t seq, struct ssh *ssh) | |||
210 | return 0; | 212 | return 0; |
211 | } | 213 | } |
212 | 214 | ||
215 | #define MIN_FAIL_DELAY_SECONDS 0.005 | ||
216 | static double | ||
217 | user_specific_delay(const char *user) | ||
218 | { | ||
219 | char b[512]; | ||
220 | size_t len = ssh_digest_bytes(SSH_DIGEST_SHA512); | ||
221 | u_char *hash = xmalloc(len); | ||
222 | double delay; | ||
223 | |||
224 | (void)snprintf(b, sizeof b, "%llu%s", | ||
225 | (unsigned long long)options.timing_secret, user); | ||
226 | if (ssh_digest_memory(SSH_DIGEST_SHA512, b, strlen(b), hash, len) != 0) | ||
227 | fatal("%s: ssh_digest_memory", __func__); | ||
228 | /* 0-4.2 ms of delay */ | ||
229 | delay = (double)PEEK_U32(hash) / 1000 / 1000 / 1000 / 1000; | ||
230 | freezero(hash, len); | ||
231 | debug3("%s: user specific delay %0.3lfms", __func__, delay/1000); | ||
232 | return MIN_FAIL_DELAY_SECONDS + delay; | ||
233 | } | ||
234 | |||
235 | static void | ||
236 | ensure_minimum_time_since(double start, double seconds) | ||
237 | { | ||
238 | struct timespec ts; | ||
239 | double elapsed = monotime_double() - start, req = seconds, remain; | ||
240 | |||
241 | /* if we've already passed the requested time, scale up */ | ||
242 | while ((remain = seconds - elapsed) < 0.0) | ||
243 | seconds *= 2; | ||
244 | |||
245 | ts.tv_sec = remain; | ||
246 | ts.tv_nsec = (remain - ts.tv_sec) * 1000000000; | ||
247 | debug3("%s: elapsed %0.3lfms, delaying %0.3lfms (requested %0.3lfms)", | ||
248 | __func__, elapsed*1000, remain*1000, req*1000); | ||
249 | nanosleep(&ts, NULL); | ||
250 | } | ||
251 | |||
213 | /*ARGSUSED*/ | 252 | /*ARGSUSED*/ |
214 | static int | 253 | static int |
215 | input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | 254 | input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) |
@@ -218,6 +257,7 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
218 | Authmethod *m = NULL; | 257 | Authmethod *m = NULL; |
219 | char *user, *service, *method, *style = NULL; | 258 | char *user, *service, *method, *style = NULL; |
220 | int authenticated = 0; | 259 | int authenticated = 0; |
260 | double tstart = monotime_double(); | ||
221 | 261 | ||
222 | if (authctxt == NULL) | 262 | if (authctxt == NULL) |
223 | fatal("input_userauth_request: no authctxt"); | 263 | fatal("input_userauth_request: no authctxt"); |
@@ -286,6 +326,9 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) | |||
286 | debug2("input_userauth_request: try method %s", method); | 326 | debug2("input_userauth_request: try method %s", method); |
287 | authenticated = m->userauth(ssh); | 327 | authenticated = m->userauth(ssh); |
288 | } | 328 | } |
329 | if (!authctxt->authenticated) | ||
330 | ensure_minimum_time_since(tstart, | ||
331 | user_specific_delay(authctxt->user)); | ||
289 | userauth_finish(ssh, authenticated, method, NULL); | 332 | userauth_finish(ssh, authenticated, method, NULL); |
290 | 333 | ||
291 | free(service); | 334 | free(service); |
@@ -336,11 +379,15 @@ userauth_finish(struct ssh *ssh, int authenticated, const char *method, | |||
336 | 379 | ||
337 | #ifdef USE_PAM | 380 | #ifdef USE_PAM |
338 | if (options.use_pam && authenticated) { | 381 | if (options.use_pam && authenticated) { |
382 | int r; | ||
383 | |||
339 | if (!PRIVSEP(do_pam_account())) { | 384 | if (!PRIVSEP(do_pam_account())) { |
340 | /* if PAM returned a message, send it to the user */ | 385 | /* if PAM returned a message, send it to the user */ |
341 | if (buffer_len(&loginmsg) > 0) { | 386 | if (sshbuf_len(loginmsg) > 0) { |
342 | buffer_append(&loginmsg, "\0", 1); | 387 | if ((r = sshbuf_put(loginmsg, "\0", 1)) != 0) |
343 | userauth_send_banner(buffer_ptr(&loginmsg)); | 388 | fatal("%s: buffer error: %s", |
389 | __func__, ssh_err(r)); | ||
390 | userauth_send_banner(sshbuf_ptr(loginmsg)); | ||
344 | packet_write_wait(); | 391 | packet_write_wait(); |
345 | } | 392 | } |
346 | fatal("Access denied for user %s by PAM account " | 393 | fatal("Access denied for user %s by PAM account " |
@@ -409,11 +456,12 @@ auth2_method_allowed(Authctxt *authctxt, const char *method, | |||
409 | static char * | 456 | static char * |
410 | authmethods_get(Authctxt *authctxt) | 457 | authmethods_get(Authctxt *authctxt) |
411 | { | 458 | { |
412 | Buffer b; | 459 | struct sshbuf *b; |
413 | char *list; | 460 | char *list; |
414 | u_int i; | 461 | int i, r; |
415 | 462 | ||
416 | buffer_init(&b); | 463 | if ((b = sshbuf_new()) == NULL) |
464 | fatal("%s: sshbuf_new failed", __func__); | ||
417 | for (i = 0; authmethods[i] != NULL; i++) { | 465 | for (i = 0; authmethods[i] != NULL; i++) { |
418 | if (strcmp(authmethods[i]->name, "none") == 0) | 466 | if (strcmp(authmethods[i]->name, "none") == 0) |
419 | continue; | 467 | continue; |
@@ -423,14 +471,13 @@ authmethods_get(Authctxt *authctxt) | |||
423 | if (!auth2_method_allowed(authctxt, authmethods[i]->name, | 471 | if (!auth2_method_allowed(authctxt, authmethods[i]->name, |
424 | NULL)) | 472 | NULL)) |
425 | continue; | 473 | continue; |
426 | if (buffer_len(&b) > 0) | 474 | if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) ? "," : "", |
427 | buffer_append(&b, ",", 1); | 475 | authmethods[i]->name)) != 0) |
428 | buffer_append(&b, authmethods[i]->name, | 476 | fatal("%s: buffer error: %s", __func__, ssh_err(r)); |
429 | strlen(authmethods[i]->name)); | ||
430 | } | 477 | } |
431 | if ((list = sshbuf_dup_string(&b)) == NULL) | 478 | if ((list = sshbuf_dup_string(b)) == NULL) |
432 | fatal("%s: sshbuf_dup_string failed", __func__); | 479 | fatal("%s: sshbuf_dup_string failed", __func__); |
433 | buffer_free(&b); | 480 | sshbuf_free(b); |
434 | return list; | 481 | return list; |
435 | } | 482 | } |
436 | 483 | ||