commit 57a8716
default
·
2024-12-19 17:54:15 +0000 UTC
parent f82c7a5
Added bad login throttling.
M
data.c
+105,
-0
1@@ -3821,3 +3821,108 @@ xs_str *make_url(const char *href, const char *proxy, int by_token)
2
3 return url;
4 }
5+
6+
7+/** bad login throttle **/
8+
9+xs_str *_badlogin_fn(const char *addr)
10+{
11+ xs *md5 = xs_md5_hex(addr, strlen(addr));
12+ xs *dir = xs_fmt("%s/badlogin", srv_basedir);
13+
14+ mkdirx(dir);
15+
16+ return xs_fmt("%s/%s", dir, md5);
17+}
18+
19+
20+int _badlogin_read(const char *fn, int *failures)
21+/* reads a badlogin file */
22+{
23+ int ok = 0;
24+ FILE *f;
25+
26+ pthread_mutex_lock(&data_mutex);
27+
28+ if ((f = fopen(fn, "r")) != NULL) {
29+ xs *l = xs_readline(f);
30+ fclose(f);
31+
32+ if (sscanf(l, "%d", failures) == 1)
33+ ok = 1;
34+ }
35+
36+ pthread_mutex_unlock(&data_mutex);
37+
38+ return ok;
39+}
40+
41+
42+int badlogin_check(const char *user, const char *addr)
43+/* checks if this address is authorized to try a login */
44+{
45+ int valid = 1;
46+
47+ if (xs_type(addr) == XSTYPE_STRING) {
48+ xs *fn = _badlogin_fn(addr);
49+ double mt = mtime(fn);
50+
51+ if (mt > 0) {
52+ int badlogin_expire = xs_number_get(xs_dict_get_def(srv_config,
53+ "badlogin_expire", "300"));
54+
55+ mt += badlogin_expire;
56+
57+ /* if file is expired, delete and give pass */
58+ if (mt < time(NULL)) {
59+ srv_debug(1, xs_fmt("Login from %s for %s allowed again", addr, user));
60+ unlink(fn);
61+ }
62+ else {
63+ int failures;
64+
65+ if (_badlogin_read(fn, &failures)) {
66+ int badlogin_max = xs_number_get(xs_dict_get_def(srv_config,
67+ "badlogin_retries", "5"));
68+
69+ if (failures >= badlogin_max) {
70+ valid = 0;
71+
72+ xs *d = xs_str_iso_date((time_t) mt);
73+
74+ srv_debug(1,
75+ xs_fmt("Login from %s for %s forbidden until %s", addr, user, d));
76+ }
77+ }
78+ }
79+ }
80+ }
81+
82+ return valid;
83+}
84+
85+
86+void badlogin_inc(const char *user, const char *addr)
87+/* increments a bad login from this address */
88+{
89+ if (xs_type(addr) == XSTYPE_STRING) {
90+ int failures = 0;
91+ xs *fn = _badlogin_fn(addr);
92+ FILE *f;
93+
94+ _badlogin_read(fn, &failures);
95+
96+ pthread_mutex_lock(&data_mutex);
97+
98+ if ((f = fopen(fn, "w")) != NULL) {
99+ failures++;
100+
101+ fprintf(f, "%d %s %s\n", failures, addr, user);
102+ fclose(f);
103+
104+ srv_log(xs_fmt("Registered %d login failure(s) from %s for %s", failures, addr, user));
105+ }
106+
107+ pthread_mutex_unlock(&data_mutex);
108+ }
109+}
M
html.c
+12,
-3
1@@ -29,9 +29,18 @@ int login(snac *snac, const xs_dict *headers)
2 xs *l1 = xs_split_n(s2, ":", 1);
3
4 if (xs_list_len(l1) == 2) {
5- logged_in = check_password(
6- xs_list_get(l1, 0), xs_list_get(l1, 1),
7- xs_dict_get(snac->config, "passwd"));
8+ const char *user = xs_list_get(l1, 0);
9+ const char *pwd = xs_list_get(l1, 1);
10+ const char *addr = xs_or(xs_dict_get(headers, "remote-addr"),
11+ xs_dict_get(headers, "x-forwarded-for"));
12+
13+ if (badlogin_check(user, addr)) {
14+ logged_in = check_password(user, pwd,
15+ xs_dict_get(snac->config, "passwd"));
16+
17+ if (!logged_in)
18+ badlogin_inc(user, addr);
19+ }
20 }
21 }
22
M
snac.h
+3,
-0
1@@ -425,3 +425,6 @@ typedef struct {
2 t_announcement *announcement(double after);
3
4 xs_str *make_url(const char *href, const char *proxy, int by_token);
5+
6+int badlogin_check(const char *user, const char *addr);
7+void badlogin_inc(const char *user, const char *addr);