Atrinik Server  4.0
ban.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
40 #ifndef __CPROTO__
41 
42 #include <global.h>
43 #include <toolkit/string.h>
44 #include <ban.h>
45 
49 typedef struct ban {
50  shstr *name;
51 
52  char *account;
53 
54  struct sockaddr_storage addr;
55 
56  unsigned short plen;
57 
58  bool removed:1;
59 } ban_t;
60 
64 static ban_t *bans = NULL;
65 
69 static size_t bans_num = 0;
70 
71 /* Prototypes */
72 static void ban_save(void);
73 static void ban_free(void);
74 static void ban_entry_free(ban_t *ban);
75 static const char *ban_entry_save(const ban_t *ban, char *buf, size_t len);
76 
77 TOOLKIT_API(DEPENDS(socket), IMPORTS(shstr), IMPORTS(string));
78 
80 {
81  char filename[HUGE_BUF];
82  snprintf(VS(filename), "%s/" BANFILE, settings.datapath);
83 
84  FILE *fp = fopen(filename, "r");
85  if (fp == NULL) {
86  return;
87  }
88 
89  char buf[HUGE_BUF];
90  while (fgets(VS(buf), fp)) {
91  /* Skip comments and blank lines. */
92  if (buf[0] == '#' || buf[0] == '\n') {
93  continue;
94  }
95 
96  char *end = strchr(buf, '\n');
97  if (end != NULL) {
98  *end = '\0';
99  }
100 
101  ban_error_t rc = ban_add(buf);
102  if (rc != BAN_OK) {
103  LOG(ERROR, "Malformed line in bans file: %s, %s", buf,
104  ban_strerror(rc));
105  }
106  }
107 
108  fclose(fp);
109 }
110 TOOLKIT_INIT_FUNC_FINISH
111 
113 {
114  ban_save();
115  ban_free();
116 }
117 TOOLKIT_DEINIT_FUNC_FINISH
118 
122 static void ban_save(void)
123 {
124  char filename[HUGE_BUF];
125  snprintf(VS(filename), "%s/" BANFILE, settings.datapath);
126 
127  FILE *fp = fopen(filename, "w");
128  if (fp == NULL) {
129  LOG(ERROR, "Cannot open %s for writing.", filename);
130  return;
131  }
132 
133  for (size_t i = 0; i < bans_num; i++) {
134  ban_t *ban = &bans[i];
135  if (ban->removed) {
136  continue;
137  }
138 
139  char buf[HUGE_BUF];
140  if (ban_entry_save(ban, VS(buf)) == NULL) {
141  continue;
142  }
143 
144  fprintf(fp, "%s", buf);
145  }
146 
147  fclose(fp);
148 }
149 
153 static void ban_free(void)
154 {
155  for (size_t i = 0; i < bans_num; i++) {
156  ban_t *ban = &bans[i];
157  if (!ban->removed) {
158  ban_entry_free(ban);
159  }
160  }
161 
162  if (bans != NULL) {
163  efree(bans);
164  bans = NULL;
165  }
166 
167  bans_num = 0;
168 }
169 
181 static void ban_entry_new(const char *name, const char *account,
182  const struct sockaddr_storage *addr, unsigned short plen)
183 {
184  bans = erealloc(bans, sizeof(*bans) * (bans_num + 1));
185  ban_t *ban = &bans[bans_num];
186  bans_num++;
187 
188  ban->name = strcmp(name, "*") == 0 ? NULL : add_string(name);
189  ban->account = strcmp(account, "*") == 0 ? NULL : estrdup(account);
190  memcpy(&ban->addr, addr, sizeof(ban->addr));
191  ban->plen = plen;
192  ban->removed = false;
193 }
194 
208 static ban_t *ban_entry_find(const char *name, const char *account,
209  const struct sockaddr_storage *addr, unsigned short plen)
210 {
211  for (size_t i = 0; i < bans_num; i++) {
212  ban_t *ban = &bans[i];
213  if (ban->removed) {
214  continue;
215  }
216 
217  if (strcmp(name, "*") != 0 && (ban->name == NULL ||
218  strcmp(ban->name, name) != 0)) {
219  continue;
220  }
221 
222  if (strcmp(account, "*") != 0 && (ban->account == NULL ||
223  strcmp(ban->account, account) != 0)) {
224  continue;
225  }
226 
227  if (ban->plen != plen) {
228  continue;
229  }
230 
231  if (plen != 0 && (ban->plen == 0 ||
232  socket_addr_cmp(&ban->addr, addr,
233  socket_addr_plen(&ban->addr)) != 0)) {
234  continue;
235  }
236 
237  return ban;
238  }
239 
240  return NULL;
241 }
242 
248 static void ban_entry_free(ban_t *ban)
249 {
250  if (ban->name != NULL) {
251  free_string_shared(ban->name);
252  }
253 
254  if (ban->account != NULL) {
255  efree(ban->account);
256  }
257 
258  ban->removed = true;
259 }
260 
272 static const char *ban_entry_save(const ban_t *ban, char *buf, size_t len)
273 {
274  char address[MAX_BUF];
275  if (ban->plen != 0) {
276  if (!socket_addr2host(&ban->addr, VS(address))) {
277  LOG(ERROR, "Failed to convert banned IP address");
278  return NULL;
279  }
280 
281  snprintfcat(VS(address), "/%u", ban->plen);
282  } else {
283  address[0] = '\0';
284  }
285 
286  if (ban->name == NULL) {
287  snprintf(buf, len, "*");
288  } else {
289  snprintf(buf, len, "\"%s\"", ban->name);
290  }
291 
292  snprintfcat(buf, len, " %s %s\n", ban->account != NULL ? ban->account : "*",
293  address);
294  return buf;
295 }
296 
313 static ban_error_t ban_parse(const char *str, char *name, size_t name_len,
314  char *account, size_t account_len, struct sockaddr_storage *addr,
315  unsigned short *plen)
316 {
317  size_t pos = 0;
318  if (!string_get_word(str, &pos, ' ', name, name_len, '"')) {
319  return BAN_BADSYNTAX;
320  }
321 
322  memset(addr, 0, sizeof(*addr));
323  *plen = 0;
324 
325  if (!string_get_word(str, &pos, ' ', account, account_len, 0)) {
326  snprintf(account, account_len, "*");
327  return BAN_OK;
328  }
329 
330  char address[MAX_BUF];
331  if (!string_get_word(str, &pos, '/', VS(address), 0)) {
332  return BAN_OK;
333  }
334 
335  if (!socket_host2addr(address, addr)) {
336  return BAN_BADIP;
337  }
338 
339  char subnet[MAX_BUF];
340  unsigned short max_plen = socket_addr_plen(addr);
341  if (string_get_word(str, &pos, ' ', VS(subnet), 0)) {
342  int val = atoi(subnet);
343  if (val <= 0 || val > max_plen) {
344  return BAN_BADPLEN;
345  }
346 
347  *plen = (unsigned short) val;
348  } else {
349  *plen = max_plen;
350  }
351 
352  return BAN_OK;
353 }
354 
363 ban_error_t ban_add(const char *str)
364 {
365  HARD_ASSERT(str != NULL);
366 
367  char name[MAX_BUF], account[MAX_BUF];
368  struct sockaddr_storage addr;
369  unsigned short plen;
370  ban_error_t rc = ban_parse(str, VS(name), VS(account), &addr, &plen);
371  if (rc != BAN_OK) {
372  return rc;
373  }
374 
375  ban_t *ban = ban_entry_find(name, account, &addr, plen);
376  if (ban != NULL) {
377  return BAN_EXIST;
378  }
379 
380  ban_entry_new(name, account, &addr, plen);
381  ban_save();
382  return BAN_OK;
383 }
384 
393 ban_error_t ban_remove(const char *str)
394 {
395  HARD_ASSERT(str != NULL);
396 
397  ban_t *ban;
398  if (string_startswith(str, "#")) {
399  if (string_isempty(str + 1)) {
400  return BAN_BADID;
401  }
402 
403  unsigned long value = strtoul(str + 1, NULL, 10);
404  if (value == 0 || value > bans_num) {
405  return BAN_BADID;
406  }
407 
408  ban = &bans[value - 1];
409  if (ban->removed) {
410  return BAN_REMOVED;
411  }
412  } else {
413  char name[MAX_BUF], account[MAX_BUF];
414  struct sockaddr_storage addr;
415  unsigned short plen;
416  ban_error_t rc = ban_parse(str, VS(name), VS(account), &addr, &plen);
417  if (rc != BAN_OK) {
418  return rc;
419  }
420 
421  ban = ban_entry_find(name, account, &addr, plen);
422  if (ban == NULL) {
423  return BAN_NOTEXIST;
424  }
425  }
426 
427  ban_entry_free(ban);
428  ban_save();
429  return BAN_OK;
430 }
431 
441 bool ban_check(socket_struct *ns, const char *name)
442 {
443  HARD_ASSERT(ns != NULL);
444 
445  for (size_t i = 0; i < bans_num; i++) {
446  ban_t *ban = &bans[i];
447  if (ban->removed) {
448  continue;
449  }
450 
451  bool got_one = false;
452 
453  if (name != NULL && ban->name != NULL &&
454  !(got_one = (strcmp(ban->name, name) == 0))) {
455  continue;
456  }
457 
458  if (ns->account != NULL && ban->account != NULL &&
459  !(got_one = (strcmp(ban->account, ns->account) == 0))) {
460  continue;
461  }
462 
463  if (ban->plen != 0 && !(got_one =
464  (socket_cmp_addr(ns->sc, &ban->addr, ban->plen) == 0))) {
465  continue;
466  }
467 
468  return got_one;
469  }
470 
471  return false;
472 }
473 
479 void ban_list(object *op)
480 {
481  draw_info(COLOR_WHITE, op, "List of bans:");
482 
483  for (size_t i = 0; i < bans_num; i++) {
484  ban_t *ban = &bans[i];
485  if (ban->removed) {
486  continue;
487  }
488 
489  char buf[HUGE_BUF];
490  if (ban_entry_save(ban, VS(buf)) == NULL) {
491  continue;
492  }
493 
494  draw_info_format(COLOR_WHITE, op, "#%" PRIuMAX ": %s",
495  (uintmax_t) i, buf);
496  }
497 }
498 
502 void ban_reset(void)
503 {
504  ban_free();
505  ban_save();
506 }
507 
515 const char *ban_strerror(ban_error_t errnum)
516 {
517  SOFT_ASSERT_RC(errnum >= BAN_OK && errnum < BAN_MAX, "unknown error",
518  "Invalid error number: %d", errnum);
519 
520  switch (errnum) {
521  case BAN_OK:
522  return "success";
523 
524  case BAN_EXIST:
525  return "specified ban already exists";
526 
527  case BAN_NOTEXIST:
528  return "no such ban entry";
529 
530  case BAN_REMOVED:
531  return "ban entry has been removed already";
532 
533  case BAN_BADID:
534  return "invalid ban ID";
535 
536  case BAN_BADIP:
537  return "IP address in invalid format";
538 
539  case BAN_BADPLEN:
540  return "invalid subnet";
541 
542  case BAN_BADSYNTAX:
543  return "invalid syntax";
544 
545  default:
546  break;
547  }
548 
549  return "<unreachable>";
550 }
551 
552 #endif
socket_t * sc
Definition: newserver.h:109
struct ban ban_t
Invalid prefix length.
Definition: ban.h:47
static const char * ban_entry_save(const ban_t *ban, char *buf, size_t len)
Definition: ban.c:272
static void ban_entry_free(ban_t *ban)
Definition: ban.c:248
char datapath[MAX_BUF]
Definition: global.h:343
void ban_list(object *op)
Definition: ban.c:479
static void ban_save(void)
Definition: ban.c:122
Ban entry exists.
Definition: ban.h:42
const char * ban_strerror(ban_error_t errnum)
Definition: ban.c:515
static ban_error_t ban_parse(const char *str, char *name, size_t name_len, char *account, size_t account_len, struct sockaddr_storage *addr, unsigned short *plen)
Definition: ban.c:313
void ban_reset(void)
Definition: ban.c:502
Bad ban ID.
Definition: ban.h:45
char * account
Name of the banned account. Can be NULL.
Definition: ban.c:52
static size_t bans_num
Definition: ban.c:69
Ban entry doesn't exist.
Definition: ban.h:43
shstr * name
Name of the banned player. Can be NULL.
Definition: ban.c:50
static void ban_entry_new(const char *name, const char *account, const struct sockaddr_storage *addr, unsigned short plen)
Definition: ban.c:181
Invalid syntax.
Definition: ban.h:48
enum ban_error ban_error_t
static ban_t * ban_entry_find(const char *name, const char *account, const struct sockaddr_storage *addr, unsigned short plen)
Definition: ban.c:208
Number of ban error codes.
Definition: ban.h:50
TOOLKIT_INIT_FUNC(http_server)
Definition: http_server.c:85
struct sockaddr_storage addr
IP address.
Definition: ban.c:54
ban_error_t ban_remove(const char *str)
Definition: ban.c:393
Ban was already removed.
Definition: ban.h:44
struct settings_struct settings
Definition: init.c:55
Definition: ban.c:49
bool removed
If true, the ban entry is no longer valid.
Definition: ban.c:58
#define BANFILE
Definition: config.h:43
static ban_t * bans
Definition: ban.c:64
static void ban_free(void)
Definition: ban.c:153
Invalid IP address.
Definition: ban.h:46
ban_error_t ban_add(const char *str)
Definition: ban.c:363
TOOLKIT_INIT_FUNC_FINISH TOOLKIT_DEINIT_FUNC(http_server)
Definition: http_server.c:124
Success.
Definition: ban.h:41
bool ban_check(socket_struct *ns, const char *name)
Definition: ban.c:441
unsigned short plen
Prefix length (the subnet).
Definition: ban.c:56