Hotfix for banning issues
[umurmur.git] / src / ban.c
1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
10    - Redistributions of source code must retain the above copyright notice,
11          this list of conditions and the following disclaimer.
12    - Redistributions in binary form must reproduce the above copyright notice,
13      this list of conditions and the following disclaimer in the documentation
14      and/or other materials provided with the distribution.
15    - Neither the name of the Developers nor the names of its contributors may
16      be used to endorse or promote products derived from this software without
17      specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
23    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30    */
31
32 #include <stdlib.h>
33 #include <time.h>
34 #include <string.h>
35 #include "log.h"
36 #include "list.h"
37 #include "ban.h"
38 #include "conf.h"
39 #include "ssl.h"
40 #include "util.h"
41
42 static void Ban_saveBanFile(void);
43 static void Ban_readBanFile(void);
44
45
46 declare_list(banlist);
47 static int bancount; /* = 0 */
48 static int ban_duration;
49 static bool_t banlist_changed;
50
51 void Ban_init(void)
52 {
53         ban_duration = getIntConf(BAN_LENGTH);
54         /* Read ban file here */
55         if (getStrConf(BANFILE) != NULL)
56                 Ban_readBanFile();
57 }
58
59 void Ban_deinit(void)
60 {
61         /* Save banlist */
62         if (getStrConf(BANFILE) != NULL)
63                 Ban_saveBanFile();
64
65         Ban_clearBanList();
66 }
67
68 void Ban_UserBan(client_t *client, char *reason)
69 {
70         ban_t *ban;
71         char hexhash[41];
72
73         ban = calloc(1, sizeof(ban_t));
74         if (ban == NULL)
75                 Log_fatal("Out of memory");
76
77         memcpy(ban->hash, client->hash, 20);
78
79         ban->address = client->remote_tcp;
80         ban->mask = (ban->address.ss_family == AF_INET) ? 32 : 128;
81         ban->reason = strdup(reason);
82         ban->name = strdup(client->username);
83         ban->time = time(NULL);
84         ban->duration = ban_duration;
85         Timer_init(&ban->startTime);
86         list_add_tail(&ban->node, &banlist);
87         bancount++;
88         banlist_changed = true;
89         if(getBoolConf(SYNC_BANFILE))
90                 Ban_saveBanFile();
91
92         SSLi_hash2hex(ban->hash, hexhash);
93
94         Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
95                 ban->reason, hexhash, Util_clientAddressToString(client), ban->duration);
96 }
97
98
99 void Ban_pruneBanned()
100 {
101         struct dlist *itr;
102         ban_t *ban;
103         uint64_t bantime_long;
104
105         list_iterate(itr, &banlist) {
106                 ban = list_get_entry(itr, ban_t, node);
107                 bantime_long = ban->duration * 1000000LL;
108 #ifdef DEBUG
109                 SSLi_hash2hex(ban->hash, hexhash);
110                 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
111                         ban->name, ban->reason, hexhash, Util_addressToString(&ban->address)),
112                         bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
113 #endif
114                 /* Duration of 0 = forever */
115                 if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
116                         free(ban->name);
117                         free(ban->reason);
118                         list_del(&ban->node);
119                         free(ban);
120                         bancount--;
121                         banlist_changed = true;
122                         if(getBoolConf(SYNC_BANFILE))
123                                 Ban_saveBanFile();
124                 }
125         }
126 }
127
128 bool_t Ban_isBanned(client_t *client)
129 {
130         struct dlist *itr;
131         ban_t *ban;
132         list_iterate(itr, &banlist) {
133                 ban = list_get_entry(itr, ban_t, node);
134                 if (memcmp(ban->hash, client->hash, 20) == 0)
135                         return true;
136         }
137         return false;
138
139 }
140
141 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
142 {
143         struct dlist *itr;
144         ban_t *ban;
145         char* addressString = Util_addressToString(address);
146
147         list_iterate(itr, &banlist) {
148                 ban = list_get_entry(itr, ban_t, node);
149
150                 if( strncmp(Util_addressToString(&ban->address), addressString, ban->mask) == 0) {
151                         return true;
152                 }
153
154         }
155         return false;
156 }
157
158 int Ban_getBanCount(void)
159 {
160         return bancount;
161 }
162
163 message_t *Ban_getBanList(void)
164 {
165         int i = 0;
166         struct dlist *itr;
167         ban_t *ban;
168         message_t *msg;
169         struct tm timespec;
170         char timestr[32];
171         char hexhash[41];
172         uint8_t address[16];
173
174         msg = Msg_banList_create(bancount);
175         list_iterate(itr, &banlist) {
176                 ban = list_get_entry(itr, ban_t, node);
177                 gmtime_r(&ban->time, &timespec);
178                 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%S", &timespec);
179                 SSLi_hash2hex(ban->hash, hexhash);
180                 memset(address, 0, 16);
181
182                 if(ban->address.ss_family == AF_INET) {
183                         memcpy(&address[12], &((struct sockaddr_in *)&ban->address)->sin_addr, 4);
184                         memset(&address[10], 0xff, 2);
185                         Msg_banList_addEntry(msg, i++, address, ban->mask + 96, ban->name, hexhash, ban->reason, timestr, ban->duration);
186                 } else {
187                         memcpy(&address, &((struct sockaddr_in6 *)&ban->address)->sin6_addr, 16);
188                         Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name, hexhash, ban->reason, timestr, ban->duration);
189                 }
190
191         }
192         return msg;
193 }
194
195 void Ban_clearBanList(void)
196 {
197         ban_t *ban;
198         struct dlist *itr, *save;
199         list_iterate_safe(itr, save, &banlist) {
200                 ban = list_get_entry(itr, ban_t, node);
201                 free(ban->name);
202                 free(ban->reason);
203                 list_del(&ban->node);
204                 free(ban);
205                 bancount--;
206         }
207 }
208
209 void Ban_putBanList(message_t *msg, int n_bans)
210 {
211         int i = 0;
212         struct tm timespec;
213         ban_t *ban;
214         char *hexhash, *name, *reason, *start;
215         uint32_t duration, mask;
216         uint8_t *address;
217         char mappedBytes[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff};
218
219         for (i = 0; i < n_bans; i++) {
220                 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
221                 ban = malloc(sizeof(ban_t));
222                 if (ban == NULL)
223                         Log_fatal("Out of memory");
224                 SSLi_hex2hash(hexhash, ban->hash);
225
226                 if(memcmp(address, mappedBytes, 12) == 0) {
227                         memcpy(&((struct sockaddr_in *)&ban->address)->sin_addr, &address[12], 4);
228                         ban->address.ss_family = AF_INET;
229                         if (mask > 32) {
230                                 mask = 32;
231                         }
232                 } else {
233                         memcpy(&((struct sockaddr_in6 *)&ban->address)->sin6_addr, address, 16);
234                         ban->address.ss_family = AF_INET6;
235                 }
236
237                 ban->mask = mask;
238                 ban->reason = strdup(reason);
239                 ban->name = strdup(name);
240                 strptime(start, "%Y-%m-%dT%H:%M:%S", &timespec);
241                 ban->time = mktime(&timespec);
242                 ban->startTime = ban->time * 1000000LL;
243                 ban->duration = duration;
244                 list_add_tail(&ban->node, &banlist);
245                 bancount++;
246         }
247         banlist_changed = true;
248         if(getBoolConf(SYNC_BANFILE))
249                 Ban_saveBanFile();
250 }
251
252 static void Ban_saveBanFile(void)
253 {
254         struct dlist *itr;
255         ban_t *ban;
256         char hexhash[41];
257         FILE *file;
258
259         if (!banlist_changed)
260                 return;
261         file = fopen(getStrConf(BANFILE), "w");
262         if (file == NULL) {
263                 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
264                 return;
265         }
266         list_iterate(itr, &banlist) {
267                 ban = list_get_entry(itr, ban_t, node);
268                 SSLi_hash2hex(ban->hash, hexhash);
269
270                 fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, Util_addressToString(&ban->address),ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
271         }
272         fclose(file);
273         banlist_changed = false;
274         Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
275 }
276
277 static void Ban_readBanFile(void)
278 {
279         ban_t *ban;
280         char line[1024], *hexhash, *address, *name, *reason;
281         uint32_t mask, duration;
282         time_t time;
283         char *p;
284         FILE *file;
285
286         file = fopen(getStrConf(BANFILE), "r");
287         if (file == NULL) {
288                 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
289                 return;
290         }
291         while (fgets(line, 1024, file) != NULL) {
292                 p = strtok(line, ",");
293                 hexhash = p;
294                 p = strtok(NULL, ",");
295                 if (p == NULL) break;
296                 address = p;
297                 p = strtok(NULL, ",");
298                 if (p == NULL) break;
299                 mask = strtoul(p, NULL, 0);
300                 p = strtok(NULL, ",");
301                 if (p == NULL) break;
302                 time = strtoul(p, NULL, 0);
303                 p = strtok(NULL, ",");
304                 if (p == NULL) break;
305                 duration = strtoul(p, NULL, 0);
306                 p = strtok(NULL, ",");
307                 if (p == NULL) break;
308                 name = p;
309                 p = strtok(NULL, "\n");
310                 if (p == NULL) break;
311                 reason = p;
312
313                 ban = malloc(sizeof(ban_t));
314                 if (ban == NULL)
315                         Log_fatal("Out of memory");
316                 memset(ban, 0, sizeof(ban_t));
317                 SSLi_hex2hash(hexhash, ban->hash);
318                 if (inet_pton(AF_INET, address, &ban->address) == 0) {
319                         if (inet_pton(AF_INET6, address, &ban->address) == 0) {
320                                 Log_warn("Address \"%s\" is illegal!", address);
321                         } else {
322                                 ban->address.ss_family = AF_INET6;
323                         }
324                 } else {
325                         ban->address.ss_family = AF_INET;
326                 }
327                 ban->name = strdup(name);
328                 ban->reason = strdup(reason);
329                 if (ban->name == NULL || ban->reason == NULL)
330                         Log_fatal("Out of memory");
331                 ban->time = time;
332                 ban->duration = duration;
333                 ban->mask = mask;
334                 ban->startTime = ban->time * 1000000LL;
335                 list_add_tail(&ban->node, &banlist);
336                 bancount++;
337                 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
338         }
339         fclose(file);
340         Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);
341 }