]>
Commit | Line | Data |
---|---|---|
8ac0e8a7 CP |
1 | /* |
2 | * NOperserv Fakeuser module | |
3 | * | |
4 | * Allows fakeusers to be added so as to block nicks, for example. | |
5 | * | |
6 | * Copyright (c) Tim Gordon 2006. | |
7 | */ | |
8 | ||
9 | #include "../core/schedule.h" | |
10 | #include "../localuser/localuser.h" | |
11 | #include "../localuser/localuserchannel.h" | |
12 | #include "../irc/irc_config.h" | |
13 | #include "../lib/irc_string.h" | |
14 | #include "../control/control.h" | |
15 | #include "../channel/channel.h" | |
6c5439b1 | 16 | #include "../dbapi2/dbapi2.h" |
8ac0e8a7 | 17 | #include "../lib/strlfunc.h" |
87698d77 | 18 | #include "../lib/version.h" |
8ac0e8a7 CP |
19 | #include <string.h> |
20 | #include <stdlib.h> | |
8ac0e8a7 | 21 | |
70b0a4e5 | 22 | MODULE_VERSION(""); |
87698d77 | 23 | |
8ac0e8a7 CP |
24 | #define KILL_WAIT 10 |
25 | #define KILL_TIME 60 | |
26 | ||
27 | typedef struct fakeuser { | |
8ac0e8a7 CP |
28 | char nick[NICKLEN + 1]; |
29 | char ident[USERLEN + 1]; | |
30 | char host[HOSTLEN + 1]; | |
31 | char realname[REALLEN + 1]; | |
57eb978d | 32 | nick *user; |
8ac0e8a7 | 33 | time_t lastkill; |
57eb978d P |
34 | struct fakeuser *next; |
35 | } fakeuser; | |
8ac0e8a7 | 36 | |
710f0af8 | 37 | static fakeuser *fakeuserlist; |
6c5439b1 P |
38 | static DBAPIConn *nofudb; |
39 | ||
710f0af8 GB |
40 | static void reconnectfakeuser(void *arg); |
41 | ||
42 | static fakeuser *findfakeuserbynick(char *nick) { | |
8ac0e8a7 | 43 | fakeuser *fake; |
e0f6f3b8 | 44 | |
710f0af8 GB |
45 | for (fake = fakeuserlist; fake; fake = fake->next) |
46 | if (!ircd_strcmp(nick, fake->nick)) | |
47 | return fake; | |
e0f6f3b8 | 48 | |
710f0af8 | 49 | return NULL; |
8ac0e8a7 CP |
50 | } |
51 | ||
710f0af8 GB |
52 | static void fake_free(fakeuser *fake) { |
53 | fakeuser **pnext; | |
e0f6f3b8 | 54 | |
710f0af8 GB |
55 | if (fake->user) |
56 | deregisterlocaluser(fake->user, "Signing off"); | |
57 | ||
58 | deleteschedule(NULL, &reconnectfakeuser, fake); | |
59 | ||
60 | for (pnext = &fakeuserlist; *pnext; pnext = &((*pnext)->next)) { | |
61 | if (*pnext == fake) { | |
62 | *pnext = fake->next; | |
63 | break; | |
6c5439b1 P |
64 | } |
65 | } | |
66 | ||
710f0af8 GB |
67 | free(fake); |
68 | } | |
6c5439b1 | 69 | |
710f0af8 GB |
70 | static void fake_remove(fakeuser *fake) { |
71 | nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", fake->nick); | |
72 | ||
73 | fake_free(fake); | |
8ac0e8a7 CP |
74 | } |
75 | ||
710f0af8 GB |
76 | static void fakeuser_handler(nick *user, int command, void **params) { |
77 | if (command == LU_KILLED) { | |
78 | fakeuser *fake; | |
79 | time_t timenow = time(NULL); | |
8ac0e8a7 | 80 | |
710f0af8 | 81 | fake = findfakeuserbynick(user->nick); |
6c5439b1 | 82 | |
710f0af8 GB |
83 | if (!fake) { |
84 | controlwall(NO_OPER, NL_FAKEUSERS, "Error: A fakeuser was killed, but wasn't found in the list"); | |
85 | Error("fakeuser", ERR_ERROR, "A fakeuser was killed, but wasn't found in the list"); | |
86 | return; | |
87 | } | |
8ac0e8a7 | 88 | |
710f0af8 | 89 | fake->user = NULL; |
e0f6f3b8 | 90 | |
710f0af8 GB |
91 | if (timenow - fake->lastkill < KILL_TIME) { |
92 | controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) KILL'ed twice under in %d seconds. Removing.", | |
93 | fake->nick, fake->ident, fake->host, fake->realname, KILL_TIME); | |
94 | fake_remove(fake); | |
95 | return; | |
96 | } | |
97 | ||
98 | fake->lastkill = timenow; | |
99 | ||
100 | scheduleoneshot(time(NULL) + KILL_WAIT, &reconnectfakeuser, fake); | |
101 | } | |
8ac0e8a7 CP |
102 | } |
103 | ||
710f0af8 GB |
104 | static void reconnectfakeuser(void *arg) { |
105 | fakeuser *fake = arg; | |
8ac0e8a7 | 106 | nick *user; |
710f0af8 GB |
107 | |
108 | if (fake->user) | |
109 | return; | |
e0f6f3b8 | 110 | |
4c3d420f GB |
111 | if ((user = getnickbynick(fake->nick)) && (IsOper(user) || IsService(user) || IsXOper(user))) { |
112 | fake_remove(fake); | |
710f0af8 | 113 | return; |
4c3d420f | 114 | } |
8ac0e8a7 | 115 | |
710f0af8 GB |
116 | fake->user = registerlocaluser(fake->nick, fake->ident, fake->host, fake->realname, |
117 | NULL, UMODE_INV | UMODE_DEAF, &fakeuser_handler); | |
8ac0e8a7 CP |
118 | } |
119 | ||
710f0af8 GB |
120 | static fakeuser *fake_add(const char *nick, const char *ident, const char *host, const char *realname) { |
121 | fakeuser *fake; | |
8ac0e8a7 | 122 | |
710f0af8 | 123 | fake = malloc(sizeof(fakeuser)); |
e0f6f3b8 | 124 | |
710f0af8 | 125 | if (!fake) |
8ac0e8a7 | 126 | return NULL; |
8ac0e8a7 | 127 | |
710f0af8 GB |
128 | strlcpy(fake->nick, nick, NICKLEN + 1); |
129 | strlcpy(fake->ident, ident, USERLEN + 1); | |
130 | strlcpy(fake->host, host, HOSTLEN + 1); | |
131 | strlcpy(fake->realname, realname, REALLEN + 1); | |
8ac0e8a7 | 132 | |
710f0af8 GB |
133 | fake->user = NULL; |
134 | fake->lastkill = 0; | |
8ac0e8a7 | 135 | |
710f0af8 GB |
136 | fake->next = fakeuserlist; |
137 | fakeuserlist = fake; | |
138 | ||
139 | scheduleoneshot(time(NULL) + 1, reconnectfakeuser, fake); | |
140 | ||
141 | return fake; | |
8ac0e8a7 CP |
142 | } |
143 | ||
710f0af8 GB |
144 | static fakeuser *fake_create(const char *nick, const char *ident, const char *host, const char *realname) { |
145 | fakeuser *fake; | |
146 | ||
147 | fake = fake_add(nick, ident, host, realname); | |
8ac0e8a7 | 148 | |
710f0af8 GB |
149 | if (!fake) |
150 | return NULL; | |
151 | ||
152 | nofudb->squery(nofudb, "INSERT INTO ? (nick, ident, host, realname) VALUES (?,?,?,?)", "Tssss", "fakeusers", | |
153 | fake->nick, fake->ident, fake->host, fake->realname); | |
e0f6f3b8 | 154 | |
710f0af8 GB |
155 | return fake; |
156 | } | |
8bbe812b | 157 | |
710f0af8 GB |
158 | static void fakeusers_load(const DBAPIResult *res, void *arg) { |
159 | if (!res) | |
160 | return; | |
e0f6f3b8 | 161 | |
710f0af8 GB |
162 | if (!res->success) { |
163 | Error("fakeuser", ERR_ERROR, "Error loading fakeuser list."); | |
164 | res->clear(res); | |
165 | return; | |
8ac0e8a7 | 166 | } |
8ac0e8a7 | 167 | |
710f0af8 GB |
168 | while (res->next(res)) |
169 | fake_add(res->get(res, 0), res->get(res, 1), res->get(res, 2), res->get(res, 3)); | |
e0f6f3b8 | 170 | |
710f0af8 GB |
171 | res->clear(res); |
172 | } | |
8ac0e8a7 | 173 | |
710f0af8 GB |
174 | static int fakeuser_loaddb() { |
175 | if (!nofudb) { | |
176 | nofudb = dbapi2open(DBAPI2_DEFAULT, "fakeusers"); | |
8ac0e8a7 | 177 | |
710f0af8 GB |
178 | if (!nofudb) { |
179 | Error("fakeuser", ERR_STOP, "Could not connect to database."); | |
180 | return 0; | |
8ac0e8a7 | 181 | } |
710f0af8 | 182 | } |
e0f6f3b8 | 183 | |
710f0af8 GB |
184 | nofudb->createtable(nofudb, NULL, NULL, |
185 | "CREATE TABLE ? (" | |
186 | "nick VARCHAR(?) NOT NULL," | |
187 | "ident VARCHAR(?) NOT NULL," | |
188 | "host VARCHAR(?) NOT NULL," | |
189 | "realname VARCHAR(?) NOT NULL," | |
190 | "PRIMARY KEY (nick))", "Tdddd", "fakeusers", NICKLEN, USERLEN, HOSTLEN, REALLEN); | |
8ac0e8a7 | 191 | |
710f0af8 GB |
192 | nofudb->query(nofudb, fakeusers_load, NULL, |
193 | "SELECT nick, ident, host, realname FROM ?", "T", "fakeusers"); | |
194 | ||
195 | return 1; | |
8ac0e8a7 CP |
196 | } |
197 | ||
710f0af8 GB |
198 | static int fakeadd(void *source, int cargc, char **cargv) { |
199 | nick *sender = source; | |
57eb978d | 200 | fakeuser *fake; |
710f0af8 GB |
201 | char *nick, *ident, *realname; |
202 | char host[HOSTLEN + 1]; | |
8ac0e8a7 CP |
203 | |
204 | if (cargc == 0) | |
205 | return CMD_USAGE; | |
57eb978d P |
206 | |
207 | fake = findfakeuserbynick(cargv[0]); | |
e0f6f3b8 P |
208 | |
209 | if (fake) { | |
57eb978d P |
210 | controlreply(sender, "Fake User with nick %s already found", cargv[0]); |
211 | return CMD_ERROR; | |
212 | } | |
213 | ||
710f0af8 | 214 | nick = cargv[0]; |
e0f6f3b8 | 215 | |
8ac0e8a7 | 216 | if (cargc < 4) |
710f0af8 | 217 | realname = cargv[0]; |
8ac0e8a7 | 218 | else |
710f0af8 | 219 | realname = cargv[3]; |
e0f6f3b8 P |
220 | |
221 | if (cargc < 3) { | |
710f0af8 GB |
222 | strlcpy(host, cargv[0], NICKLEN + 1); |
223 | strlcat(host, ".fakeusers.quakenet.org", HOSTLEN + 1); | |
e0f6f3b8 | 224 | } else |
710f0af8 | 225 | strlcpy(host, cargv[2], HOSTLEN + 1); |
e0f6f3b8 | 226 | |
8ac0e8a7 | 227 | if (cargc < 2) |
710f0af8 | 228 | ident = cargv[0]; |
8ac0e8a7 | 229 | else |
710f0af8 | 230 | ident = cargv[1]; |
8ac0e8a7 | 231 | |
710f0af8 | 232 | fake = fake_create(nick, ident, host, realname); |
e0f6f3b8 | 233 | |
710f0af8 | 234 | if (!fake) |
8ac0e8a7 | 235 | return CMD_ERROR; |
57eb978d | 236 | |
57eb978d | 237 | controlreply(sender, "Added fake user %s", fake->nick); |
710f0af8 GB |
238 | controlwall(NO_OPER, NL_FAKEUSERS, "%s added fake user: %s!%s@%s (%s)", controlid(sender), |
239 | fake->nick, fake->ident, fake->host, fake->realname); | |
57eb978d | 240 | |
710f0af8 | 241 | scheduleoneshot(time(NULL) + 1, &reconnectfakeuser, fake); |
836d332e | 242 | |
8ac0e8a7 CP |
243 | return CMD_OK; |
244 | } | |
245 | ||
710f0af8 | 246 | static int fakelist(void *sender, int cargc, char **cargv) { |
8ac0e8a7 | 247 | fakeuser *fake; |
e0f6f3b8 P |
248 | int fakeusercount = 0; |
249 | ||
250 | for (fake = fakeuserlist; fake; fake = fake->next) { | |
251 | if (!fake->user) | |
8bbe812b | 252 | controlreply(sender, "%s!%s@%s (%s) - RECONNECTING", fake->nick, fake->ident, |
57eb978d | 253 | fake->host, fake->realname); |
8ac0e8a7 | 254 | else |
57eb978d P |
255 | controlreply(sender, "%s!%s@%s (%s)", fake->nick, fake->ident, |
256 | fake->host, fake->realname); | |
257 | ||
258 | fakeusercount++; | |
8ac0e8a7 | 259 | } |
e0f6f3b8 | 260 | |
57eb978d | 261 | controlreply(sender, "%d fakeusers are currently connected", fakeusercount); |
836d332e | 262 | |
8ac0e8a7 CP |
263 | return CMD_OK; |
264 | } | |
265 | ||
710f0af8 | 266 | static int fakekill(void *sender, int cargc, char **cargv) { |
8ac0e8a7 | 267 | fakeuser *fake; |
e0f6f3b8 | 268 | |
8ac0e8a7 CP |
269 | if (cargc == 0) |
270 | return CMD_USAGE; | |
57eb978d P |
271 | |
272 | fake = findfakeuserbynick(cargv[0]); | |
e0f6f3b8 P |
273 | |
274 | if (!fake) { | |
57eb978d P |
275 | controlreply(sender, "No Fake User with nick %s found", cargv[0]); |
276 | return CMD_ERROR; | |
277 | } | |
278 | ||
57eb978d P |
279 | controlreply(sender, "Killed fake user %s", fake->nick); |
280 | controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) removed by %s/%s", fake->nick, fake->ident, | |
e0f6f3b8 | 281 | fake->host, fake->realname, ((nick *)sender)->nick, ((nick *)sender)->authname); |
57eb978d | 282 | |
710f0af8 | 283 | fake_remove(fake); |
836d332e | 284 | |
57eb978d P |
285 | return CMD_OK; |
286 | } | |
287 | ||
8bbe812b P |
288 | void _init() { |
289 | if (!fakeuser_loaddb()) { | |
290 | Error("fakeuser", ERR_FATAL, "Cannot load database"); | |
291 | return; | |
292 | } | |
293 | ||
294 | registercontrolhelpcmd("fakeuser", NO_OPER, 4, &fakeadd, "Usage: FAKEUSER nick <ident> <host> <realname>\nCreates a fake user."); | |
295 | registercontrolhelpcmd("fakelist", NO_OPER, 0, &fakelist, "Usage: FAKELIST\nLists all fake users."); | |
296 | registercontrolhelpcmd("fakekill", NO_OPER, 2, &fakekill, "Usage: FAKEKILL nick\nRemoves a fake user"); | |
297 | } | |
298 | ||
299 | void _fini() { | |
710f0af8 GB |
300 | fakeuser *fake, *next; |
301 | ||
302 | for (fake = fakeuserlist; fake; fake = next) { | |
303 | next = fake->next; | |
304 | fake_free(fake); | |
305 | } | |
306 | ||
8bbe812b P |
307 | deregistercontrolcmd("fakeuser", &fakeadd); |
308 | deregistercontrolcmd("fakelist", &fakelist); | |
309 | deregistercontrolcmd("fakekill", &fakekill); | |
310 | } |