Added bad login throttling.

This commit is contained in:
default 2024-12-19 18:54:15 +01:00
parent f82c7a5cdb
commit 57a8716f72
3 changed files with 120 additions and 3 deletions

105
data.c
View file

@ -3821,3 +3821,108 @@ xs_str *make_url(const char *href, const char *proxy, int by_token)
return url;
}
/** bad login throttle **/
xs_str *_badlogin_fn(const char *addr)
{
xs *md5 = xs_md5_hex(addr, strlen(addr));
xs *dir = xs_fmt("%s/badlogin", srv_basedir);
mkdirx(dir);
return xs_fmt("%s/%s", dir, md5);
}
int _badlogin_read(const char *fn, int *failures)
/* reads a badlogin file */
{
int ok = 0;
FILE *f;
pthread_mutex_lock(&data_mutex);
if ((f = fopen(fn, "r")) != NULL) {
xs *l = xs_readline(f);
fclose(f);
if (sscanf(l, "%d", failures) == 1)
ok = 1;
}
pthread_mutex_unlock(&data_mutex);
return ok;
}
int badlogin_check(const char *user, const char *addr)
/* checks if this address is authorized to try a login */
{
int valid = 1;
if (xs_type(addr) == XSTYPE_STRING) {
xs *fn = _badlogin_fn(addr);
double mt = mtime(fn);
if (mt > 0) {
int badlogin_expire = xs_number_get(xs_dict_get_def(srv_config,
"badlogin_expire", "300"));
mt += badlogin_expire;
/* if file is expired, delete and give pass */
if (mt < time(NULL)) {
srv_debug(1, xs_fmt("Login from %s for %s allowed again", addr, user));
unlink(fn);
}
else {
int failures;
if (_badlogin_read(fn, &failures)) {
int badlogin_max = xs_number_get(xs_dict_get_def(srv_config,
"badlogin_retries", "5"));
if (failures >= badlogin_max) {
valid = 0;
xs *d = xs_str_iso_date((time_t) mt);
srv_debug(1,
xs_fmt("Login from %s for %s forbidden until %s", addr, user, d));
}
}
}
}
}
return valid;
}
void badlogin_inc(const char *user, const char *addr)
/* increments a bad login from this address */
{
if (xs_type(addr) == XSTYPE_STRING) {
int failures = 0;
xs *fn = _badlogin_fn(addr);
FILE *f;
_badlogin_read(fn, &failures);
pthread_mutex_lock(&data_mutex);
if ((f = fopen(fn, "w")) != NULL) {
failures++;
fprintf(f, "%d %s %s\n", failures, addr, user);
fclose(f);
srv_log(xs_fmt("Registered %d login failure(s) from %s for %s", failures, addr, user));
}
pthread_mutex_unlock(&data_mutex);
}
}

15
html.c
View file

@ -29,9 +29,18 @@ int login(snac *snac, const xs_dict *headers)
xs *l1 = xs_split_n(s2, ":", 1);
if (xs_list_len(l1) == 2) {
logged_in = check_password(
xs_list_get(l1, 0), xs_list_get(l1, 1),
xs_dict_get(snac->config, "passwd"));
const char *user = xs_list_get(l1, 0);
const char *pwd = xs_list_get(l1, 1);
const char *addr = xs_or(xs_dict_get(headers, "remote-addr"),
xs_dict_get(headers, "x-forwarded-for"));
if (badlogin_check(user, addr)) {
logged_in = check_password(user, pwd,
xs_dict_get(snac->config, "passwd"));
if (!logged_in)
badlogin_inc(user, addr);
}
}
}

3
snac.h
View file

@ -425,3 +425,6 @@ typedef struct {
t_announcement *announcement(double after);
xs_str *make_url(const char *href, const char *proxy, int by_token);
int badlogin_check(const char *user, const char *addr);
void badlogin_inc(const char *user, const char *addr);