Indentation fixed
[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
40 static void Ban_saveBanFile(void);
41 static void Ban_readBanFile(void);
42
43
44 declare_list(banlist);
45 static int bancount; /* = 0 */
46 static int ban_duration;
47 static bool_t banlist_changed;
48
49 void Ban_init(void)
50 {
51         ban_duration = getIntConf(BAN_LENGTH);
52         /* Read ban file here */
53         if (getStrConf(BANFILE) != NULL)
54                 Ban_readBanFile();
55 }
56
57 void Ban_deinit(void)
58 {
59         /* Save banlist */
60         if (getStrConf(BANFILE) != NULL)
61                 Ban_saveBanFile();
62
63         Ban_clearBanList();
64 }
65
66 void Ban_UserBan(client_t *client, char *reason)
67 {
68         ban_t *ban;
69         char hexhash[41];
70
71         ban = malloc(sizeof(ban_t));
72         if (ban == NULL)
73                 Log_fatal("Out of memory");
74         memset(ban, 0, sizeof(ban_t));
75
76         memcpy(ban->hash, client->hash, 20);
77         if (client->remote_tcp.ss_family == AF_INET) {
78                 memcpy(&ban->address, &(((struct sockaddr_in*)&client->remote_tcp)->sin_addr), sizeof(in_addr_t));
79                 ban->mask = sizeof(in_addr_t);
80         } else {
81                 memcpy(&ban->address, &(((struct sockaddr_in6*)&client->remote_tcp)->sin6_addr), 4 * sizeof(in_addr_t));
82                 ban->mask = 4 * sizeof(in_addr_t);
83         }
84         ban->reason = strdup(reason);
85         ban->name = strdup(client->username);
86         ban->time = time(NULL);
87         ban->duration = ban_duration;
88         Timer_init(&ban->startTime);
89         list_add_tail(&ban->node, &banlist);
90         bancount++;
91         banlist_changed = true;
92         if(getBoolConf(SYNC_BANFILE))
93                 Ban_saveBanFile();
94
95         SSLi_hash2hex(ban->hash, hexhash);
96
97         Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
98                 ban->reason, hexhash, client->addressString, ban->duration);
99 }
100
101
102 void Ban_pruneBanned()
103 {
104         struct dlist *itr;
105         ban_t *ban;
106         char hexhash[41];
107         uint64_t bantime_long;
108
109         list_iterate(itr, &banlist) {
110                 ban = list_get_entry(itr, ban_t, node);
111                 bantime_long = ban->duration * 1000000LL;
112 #ifdef DEBUG
113                 SSLi_hash2hex(ban->hash, hexhash);
114                 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
115                         ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
116                         bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
117 #endif
118                 /* Duration of 0 = forever */
119                 if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
120                         free(ban->name);
121                         free(ban->reason);
122                         list_del(&ban->node);
123                         free(ban);
124                         bancount--;
125                         banlist_changed = true;
126                         if(getBoolConf(SYNC_BANFILE))
127                                 Ban_saveBanFile();
128                 }
129         }
130 }
131
132 bool_t Ban_isBanned(client_t *client)
133 {
134         struct dlist *itr;
135         ban_t *ban;
136         list_iterate(itr, &banlist) {
137                 ban = list_get_entry(itr, ban_t, node);
138                 if (memcmp(ban->hash, client->hash, 20) == 0)
139                         return true;
140         }
141         return false;
142
143 }
144
145 bool_t Ban_isBannedAddr(in_addr_t *addr)
146 {
147         struct dlist *itr;
148         ban_t *ban;
149         int mask;
150         in_addr_t tempaddr1, tempaddr2;
151
152         list_iterate(itr, &banlist) {
153                 ban = list_get_entry(itr, ban_t, node);
154                 mask = ban->mask - 96;
155                 if (mask < 32) { /* XXX - only ipv4 support */
156                         memcpy(&tempaddr1, addr, sizeof(in_addr_t));
157                         memcpy(&tempaddr2, &ban->address, sizeof(in_addr_t));
158                         tempaddr1 &= (2 ^ mask) - 1;
159                         tempaddr2 &= (2 ^ mask) - 1;
160                 }
161                 if (memcmp(&tempaddr1, &tempaddr2, sizeof(in_addr_t)) == 0)
162                         return true;
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 }