Code cleanup
[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 "log.h"
35 #include "list.h"
36 #include "ban.h"
37 #include "conf.h"
38 #include "ssl.h"
39 #include "util.h"
40
41 static void Ban_saveBanFile(void);
42 static void Ban_readBanFile(void);
43
44
45 declare_list(banlist);
46 static int bancount; /* = 0 */
47 static int ban_duration;
48 static bool_t banlist_changed;
49
50 void Ban_init(void)
51 {
52         ban_duration = getIntConf(BAN_LENGTH);
53         /* Read ban file here */
54         if (getStrConf(BANFILE) != NULL)
55                 Ban_readBanFile();
56 }
57
58 void Ban_deinit(void)
59 {
60         /* Save banlist */
61         if (getStrConf(BANFILE) != NULL)
62                 Ban_saveBanFile();
63
64         Ban_clearBanList();
65 }
66
67 void Ban_UserBan(client_t *client, char *reason)
68 {
69         ban_t *ban;
70         char hexhash[41];
71
72         ban = malloc(sizeof(ban_t));
73         if (ban == NULL)
74                 Log_fatal("Out of memory");
75         memset(ban, 0, sizeof(ban_t));
76
77         memcpy(ban->hash, client->hash, 20);
78         if (client->remote_tcp.ss_family == AF_INET) {
79                 memcpy(&ban->address, &(((struct sockaddr_in*)&client->remote_tcp)->sin_addr), sizeof(in_addr_t));
80                 ban->mask = sizeof(in_addr_t);
81         } else {
82                 memcpy(&ban->address, &(((struct sockaddr_in6*)&client->remote_tcp)->sin6_addr), 4 * sizeof(in_addr_t));
83                 ban->mask = 4 * sizeof(in_addr_t);
84         }
85         ban->reason = strdup(reason);
86         ban->name = strdup(client->username);
87         ban->time = time(NULL);
88         ban->duration = ban_duration;
89         Timer_init(&ban->startTime);
90         list_add_tail(&ban->node, &banlist);
91         bancount++;
92         banlist_changed = true;
93         if(getBoolConf(SYNC_BANFILE))
94                 Ban_saveBanFile();
95
96         SSLi_hash2hex(ban->hash, hexhash);
97
98         Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
99                 ban->reason, hexhash, Util_clientAddressToString(client), ban->duration);
100 }
101
102
103 void Ban_pruneBanned()
104 {
105         struct dlist *itr;
106         ban_t *ban;
107         char hexhash[41];
108         uint64_t bantime_long;
109
110         list_iterate(itr, &banlist) {
111                 ban = list_get_entry(itr, ban_t, node);
112                 bantime_long = ban->duration * 1000000LL;
113 #ifdef DEBUG
114                 SSLi_hash2hex(ban->hash, hexhash);
115                 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
116                         ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
117                         bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
118 #endif
119                 /* Duration of 0 = forever */
120                 if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
121                         free(ban->name);
122                         free(ban->reason);
123                         list_del(&ban->node);
124                         free(ban);
125                         bancount--;
126                         banlist_changed = true;
127                         if(getBoolConf(SYNC_BANFILE))
128                                 Ban_saveBanFile();
129                 }
130         }
131 }
132
133 bool_t Ban_isBanned(client_t *client)
134 {
135         struct dlist *itr;
136         ban_t *ban;
137         list_iterate(itr, &banlist) {
138                 ban = list_get_entry(itr, ban_t, node);
139                 if (memcmp(ban->hash, client->hash, 20) == 0)
140                         return true;
141         }
142         return false;
143
144 }
145
146 bool_t Ban_isBannedAddr(struct sockaddr_storage *address)
147 {
148         struct dlist *itr;
149         ban_t *ban;
150         in_addr_t tempaddr1, tempaddr2;
151
152         list_iterate(itr, &banlist) {
153                 ban = list_get_entry(itr, ban_t, node);
154
155                 if(ban->mask == sizeof(in_addr_t)) {
156                         if(memcmp(ban->address, &((struct sockaddr_in *)address)->sin_addr, ban->mask) == 0)
157                                 return true;
158                 }
159                 else {
160                         if(memcmp(ban->address, &((struct sockaddr_in6 *)address)->sin6_addr, ban->mask) == 0)
161                                 return true;
162                 }
163         }
164         return false;
165 }
166
167 int Ban_getBanCount(void)
168 {
169         return bancount;
170 }
171
172 message_t *Ban_getBanList(void)
173 {
174         int i = 0;
175         struct dlist *itr;
176         ban_t *ban;
177         message_t *msg;
178         struct tm timespec;
179         char timestr[32];
180         char hexhash[41];
181         uint8_t address[16];
182
183         msg = Msg_banList_create(bancount);
184         list_iterate(itr, &banlist) {
185                 ban = list_get_entry(itr, ban_t, node);
186                 gmtime_r(&ban->time, &timespec);
187                 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%S", &timespec);
188                 SSLi_hash2hex(ban->hash, hexhash);
189                 /* ipv4 representation as ipv6 address. */
190                 memset(address, 0, 16);
191                 memcpy(&address[12], &ban->address, 4);
192                 memset(&address[10], 0xff, 2); /* IPv4 */
193                 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name,
194                         hexhash, ban->reason, timestr, ban->duration);
195         }
196         return msg;
197 }
198
199 void Ban_clearBanList(void)
200 {
201         ban_t *ban;
202         struct dlist *itr, *save;
203         list_iterate_safe(itr, save, &banlist) {
204                 ban = list_get_entry(itr, ban_t, node);
205                 free(ban->name);
206                 free(ban->reason);
207                 list_del(&ban->node);
208                 free(ban);
209                 bancount--;
210         }
211 }
212
213 void Ban_putBanList(message_t *msg, int n_bans)
214 {
215         int i = 0;
216         struct tm timespec;
217         ban_t *ban;
218         char *hexhash, *name, *reason, *start;
219         uint32_t duration, mask;
220         uint8_t *address;
221
222         for (i = 0; i < n_bans; i++) {
223                 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
224                 ban = malloc(sizeof(ban_t));
225                 if (ban == NULL)
226                         Log_fatal("Out of memory");
227                 memset(ban, 0, sizeof(ban_t));
228                 SSLi_hex2hash(hexhash, ban->hash);
229                 memcpy(&ban->address, &address[12], 4);
230                 ban->mask = mask;
231                 ban->reason = strdup(reason);
232                 ban->name = strdup(name);
233                 strptime(start, "%Y-%m-%dT%H:%M:%S", &timespec);
234                 ban->time = mktime(&timespec);
235                 ban->startTime = ban->time * 1000000LL;
236                 ban->duration = duration;
237                 list_add_tail(&ban->node, &banlist);
238                 bancount++;
239         }
240         banlist_changed = true;
241         if(getBoolConf(SYNC_BANFILE))
242                 Ban_saveBanFile();
243 }
244
245 static void Ban_saveBanFile(void)
246 {
247         struct dlist *itr;
248         ban_t *ban;
249         char hexhash[41];
250         FILE *file;
251
252         if (!banlist_changed)
253                 return;
254         file = fopen(getStrConf(BANFILE), "w");
255         if (file == NULL) {
256                 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
257                 return;
258         }
259         list_iterate(itr, &banlist) {
260                 ban = list_get_entry(itr, ban_t, node);
261                 SSLi_hash2hex(ban->hash, hexhash);
262                 fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
263                         ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
264         }
265         fclose(file);
266         banlist_changed = false;
267         Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
268 }
269
270 static void Ban_readBanFile(void)
271 {
272         struct dlist *itr;
273         ban_t *ban;
274         char line[1024], *hexhash, *address, *name, *reason;
275         uint32_t mask, duration;
276         time_t time;
277         char *p;
278         FILE *file;
279
280         file = fopen(getStrConf(BANFILE), "r");
281         if (file == NULL) {
282                 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
283                 return;
284         }
285         while (fgets(line, 1024, file) != NULL) {
286                 p = strtok(line, ",");
287                 hexhash = p;
288                 p = strtok(NULL, ",");
289                 if (p == NULL) break;
290                 address = p;
291                 p = strtok(NULL, ",");
292                 if (p == NULL) break;
293                 mask = strtoul(p, NULL, 0);
294                 p = strtok(NULL, ",");
295                 if (p == NULL) break;
296                 time = strtoul(p, NULL, 0);
297                 p = strtok(NULL, ",");
298                 if (p == NULL) break;
299                 duration = strtoul(p, NULL, 0);
300                 p = strtok(NULL, ",");
301                 if (p == NULL) break;
302                 name = p;
303                 p = strtok(NULL, "\n");
304                 if (p == NULL) break;
305                 reason = p;
306
307                 ban = malloc(sizeof(ban_t));
308                 if (ban == NULL)
309                         Log_fatal("Out of memory");
310                 memset(ban, 0, sizeof(ban_t));
311                 SSLi_hex2hash(hexhash, ban->hash);
312                 inet_aton(address, (struct in_addr *)&ban->address);
313                 ban->name = strdup(name);
314                 ban->reason = strdup(reason);
315                 if (ban->name == NULL || ban->reason == NULL)
316                         Log_fatal("Out of memory");
317                 ban->time = time;
318                 ban->duration = duration;
319                 ban->mask = mask;
320                 ban->startTime = ban->time * 1000000LL;
321                 list_add_tail(&ban->node, &banlist);
322                 bancount++;
323                 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
324         }
325         fclose(file);
326         Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);
327 }