version 1.145, 2018/03/03 03:15:51 |
version 1.146, 2018/04/13 03:57:26 |
|
|
#endif |
#endif |
#include "monitor_wrap.h" |
#include "monitor_wrap.h" |
#include "ssherr.h" |
#include "ssherr.h" |
|
#include "digest.h" |
|
|
/* import */ |
/* import */ |
extern ServerOptions options; |
extern ServerOptions options; |
|
|
return 0; |
return 0; |
} |
} |
|
|
|
#define MIN_FAIL_DELAY_SECONDS 0.005 |
|
static double |
|
user_specific_delay(const char *user) |
|
{ |
|
char b[512]; |
|
size_t len = ssh_digest_bytes(SSH_DIGEST_SHA512); |
|
u_char *hash = xmalloc(len); |
|
double delay; |
|
|
|
(void)snprintf(b, sizeof b, "%llu%s", options.timing_secret, user); |
|
if (ssh_digest_memory(SSH_DIGEST_SHA512, b, strlen(b), hash, len) != 0) |
|
fatal("%s: ssh_digest_memory", __func__); |
|
/* 0-4.2 ms of delay */ |
|
delay = (double)PEEK_U32(hash) / 1000 / 1000 / 1000 / 1000; |
|
freezero(hash, len); |
|
debug3("%s: user specific delay %0.3lfms", __func__, delay/1000); |
|
return MIN_FAIL_DELAY_SECONDS + delay; |
|
} |
|
|
|
static void |
|
ensure_minimum_time_since(double start, double seconds) |
|
{ |
|
struct timespec ts; |
|
double elapsed = monotime_double() - start, req = seconds, remain; |
|
|
|
/* if we've already passed the requested time, scale up */ |
|
while ((remain = seconds - elapsed) < 0.0) |
|
seconds *= 2; |
|
|
|
ts.tv_sec = remain; |
|
ts.tv_nsec = (remain - ts.tv_sec) * 1000000000; |
|
debug3("%s: elapsed %0.3lfms, delaying %0.3lfms (requested %0.3lfms)", |
|
__func__, elapsed*1000, remain*1000, req*1000); |
|
nanosleep(&ts, NULL); |
|
} |
|
|
/*ARGSUSED*/ |
/*ARGSUSED*/ |
static int |
static int |
input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) |
input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) |
|
|
Authmethod *m = NULL; |
Authmethod *m = NULL; |
char *user, *service, *method, *style = NULL; |
char *user, *service, *method, *style = NULL; |
int authenticated = 0; |
int authenticated = 0; |
|
double tstart = monotime_double(); |
|
|
if (authctxt == NULL) |
if (authctxt == NULL) |
fatal("input_userauth_request: no authctxt"); |
fatal("input_userauth_request: no authctxt"); |
|
|
debug2("input_userauth_request: try method %s", method); |
debug2("input_userauth_request: try method %s", method); |
authenticated = m->userauth(ssh); |
authenticated = m->userauth(ssh); |
} |
} |
|
if (!authctxt->authenticated) |
|
ensure_minimum_time_since(tstart, |
|
user_specific_delay(authctxt->user)); |
userauth_finish(ssh, authenticated, method, NULL); |
userauth_finish(ssh, authenticated, method, NULL); |
|
|
free(service); |
free(service); |