1 /*
2 * Copyright (c) 2016 Atheme Development Group <http://atheme.github.io>
3 * Copyright (c) 2010 William Pitcock, et al.
4 * The rights to this code are as documented under doc/LICENSE.
5 *
6 * Automatically AKILL a list of clients, given their operating parameters.
7 *
8 * Basically this builds a keyword patricia. O(NICKLEN) lookups at the price
9 * of a longer startup process.
10 *
11 * Configuration.
12 * ==============
13 *
14 * This module adds a new block to the config file:
15 *
16 * nicklists {
17 * all = "/home/nenolod/atheme-production.hg4576/etc/nicklists/azn.txt";
18 * nick = "/home/nenolod/atheme-production.hg4576/etc/nicklists/bottler-nicks.txt";
19 * user = "/home/nenolod/atheme-production.hg4576/etc/nicklists/bottler-users.txt";
20 * real = "/home/nenolod/atheme-production.hg4576/etc/nicklists/bottler-gecos.txt";
21 * };
22 *
23 * You can add multiple all, nick, user and real entries. The entries will be merged.
24 * I would also like to say: fuck you GNAA, you guys need to go play in fucking traffic.
25 * Thanks for reading my crappy docs, and have a nice day.
26 */
27
28 #include "atheme-compat.h"
29
30 DECLARE_MODULE_V1
31 (
32 "contrib/os_akillnicklist", false, _modinit, _moddeinit,
33 "0.1",
34 "Atheme Development Group <http://atheme.github.io>"
35 );
36
37 static mowgli_patricia_t *akillalllist = NULL;
38 static mowgli_patricia_t *akillnicklist = NULL;
39 static mowgli_patricia_t *akilluserlist = NULL;
40 static mowgli_patricia_t *akillreallist = NULL;
41
42 static mowgli_list_t conft = { NULL, NULL, 0 };
43
44 static void
add_contents_of_file_to_list(const char * filename,mowgli_patricia_t * list)45 add_contents_of_file_to_list(const char *filename, mowgli_patricia_t *list)
46 {
47 char value[BUFSIZE];
48 FILE *f;
49
50 f = fopen(filename, "r");
51 if (!f)
52 return;
53
54 while (fgets(value, BUFSIZE, f) != NULL)
55 {
56 strip(value);
57
58 if (!*value)
59 continue;
60
61 mowgli_patricia_add(list, value, (void *) 0x1);
62 }
63
64 fclose(f);
65 }
66
67 static int
nicklist_config_handler_all(mowgli_config_file_entry_t * entry)68 nicklist_config_handler_all(mowgli_config_file_entry_t *entry)
69 {
70 add_contents_of_file_to_list(entry->vardata, akillalllist);
71
72 return 0;
73 }
74
75 static int
nicklist_config_handler_nick(mowgli_config_file_entry_t * entry)76 nicklist_config_handler_nick(mowgli_config_file_entry_t *entry)
77 {
78 add_contents_of_file_to_list(entry->vardata, akillnicklist);
79
80 return 0;
81 }
82
83 static int
nicklist_config_handler_user(mowgli_config_file_entry_t * entry)84 nicklist_config_handler_user(mowgli_config_file_entry_t *entry)
85 {
86 add_contents_of_file_to_list(entry->vardata, akilluserlist);
87
88 return 0;
89 }
90
91 static int
nicklist_config_handler_real(mowgli_config_file_entry_t * entry)92 nicklist_config_handler_real(mowgli_config_file_entry_t *entry)
93 {
94 add_contents_of_file_to_list(entry->vardata, akillreallist);
95
96 return 0;
97 }
98
99 static void
aknl_nickhook(hook_user_nick_t * data)100 aknl_nickhook(hook_user_nick_t *data)
101 {
102 user_t *u;
103 bool doit = false;
104 const char *username;
105 kline_t *k;
106
107 return_if_fail(data != NULL);
108
109 if (!data->u)
110 return;
111
112 u = data->u;
113
114 if (is_internal_client(u))
115 return;
116
117 if (is_autokline_exempt(u))
118 return;
119
120 username = u->user;
121 if (*username == '~')
122 username++;
123
124 if (mowgli_patricia_retrieve(akillalllist, u->nick) != NULL &&
125 mowgli_patricia_retrieve(akillalllist, username) != NULL &&
126 mowgli_patricia_retrieve(akillalllist, u->gecos) != NULL)
127 doit = true;
128
129 if (mowgli_patricia_retrieve(akillnicklist, u->nick) != NULL)
130 doit = true;
131
132 if (mowgli_patricia_retrieve(akilluserlist, username) != NULL)
133 doit = true;
134
135 if (mowgli_patricia_retrieve(akillreallist, u->gecos) != NULL)
136 doit = true;
137
138 if (!doit)
139 return;
140
141 if (! (u->flags & UF_KLINESENT)) {
142 slog(LG_INFO, "AKNL: k-lining \2%s\2!%s@%s [%s] due to appearing to be a possible spambot", u->nick, u->user, u->host, u->gecos);
143 k = kline_add(u->user, u->host, "Possible spambot", 86400, "*");
144 u->flags |= UF_KLINESENT;
145 }
146 }
147
148 void
_modinit(module_t * m)149 _modinit(module_t *m)
150 {
151 add_subblock_top_conf("NICKLISTS", &conft);
152 add_conf_item("ALL", &conft, nicklist_config_handler_all);
153 add_conf_item("NICK", &conft, nicklist_config_handler_nick);
154 add_conf_item("USER", &conft, nicklist_config_handler_user);
155 add_conf_item("REAL", &conft, nicklist_config_handler_real);
156
157 akillalllist = mowgli_patricia_create(strcasecanon);
158 akillnicklist = mowgli_patricia_create(strcasecanon);
159 akilluserlist = mowgli_patricia_create(strcasecanon);
160 akillreallist = mowgli_patricia_create(strcasecanon);
161
162 hook_add_event("user_add");
163 hook_add_user_add(aknl_nickhook);
164 hook_add_event("user_nickchange");
165 hook_add_user_nickchange(aknl_nickhook);
166 }
167
168 void
_moddeinit(module_unload_intent_t intent)169 _moddeinit(module_unload_intent_t intent)
170 {
171 hook_del_user_add(aknl_nickhook);
172 hook_del_user_nickchange(aknl_nickhook);
173
174 del_conf_item("ALL", &conft);
175 del_conf_item("NICK", &conft);
176 del_conf_item("USER", &conft);
177 del_conf_item("REAL", &conft);
178 del_top_conf("NICKLISTS");
179 }
180