]> jfr.im git - irc/quakenet/newserv.git/blame - fakeusers/fakeusers.c
FAKEUSERS: remove unused variable
[irc/quakenet/newserv.git] / fakeusers / fakeusers.c
CommitLineData
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 22MODULE_VERSION("");
87698d77 23
8ac0e8a7
CP
24/* #define SIT_CHANNEL "#qnet.fakeusers" */
25#define KILL_WAIT 10
26#define KILL_TIME 60
27
28typedef struct fakeuser {
29 nick *user;
30 time_t lastkill;
31 struct fakeuser *next;
32} fakeuser;
33
34typedef struct user_details {
35 char nick[NICKLEN + 1];
36 char ident[USERLEN + 1];
37 char host[HOSTLEN + 1];
38 char realname[REALLEN + 1];
39 time_t lastkill;
40 struct user_details *next;
41 void *schedule;
42} user_details;
43
44fakeuser *fakeuserlist = NULL;
45user_details *killeduserlist = NULL;
46int fakeusercount = 0;
47int killedusercount = 0;
48
49void fakeuser_cleanup();
50int fakeuser_loaddb();
6c5439b1 51void fakeusers_load(const DBAPIResult *res, void *arg);
8ac0e8a7
CP
52void fakeuser_handler(nick *user, int command, void **params);
53int fakeadd(void *sender, int cargc, char **cargv);
54int fakelist(void *sender, int cargc, char **cargv);
55int fakekill(void *sender, int cargc, char **cargv);
56void reconnectfake(void *details);
57
6c5439b1
P
58static DBAPIConn *nofudb;
59
8ac0e8a7
CP
60void _init() {
61 if (!fakeuser_loaddb())
62 {
6189af13 63 Error("fakeuser", ERR_FATAL, "Cannot load database");
8ac0e8a7
CP
64 return;
65 }
66 registercontrolhelpcmd("fakeuser", NO_OPER, 4, &fakeadd, "Usage: FAKEUSER nick <ident> <host> <realname>\nCreates a fake user.");
67 registercontrolhelpcmd("fakelist", NO_OPER, 0, &fakelist, "Usage: FAKELIST\nLists all fake users.");
68 registercontrolhelpcmd("fakekill", NO_OPER, 2, &fakekill, "Usage: FAKEKILL nick <reason>\nRemoves a fake user");
69}
70
71void _fini() {
72 fakeuser_cleanup();
73 deregistercontrolcmd("fakeuser", &fakeadd);
74 deregistercontrolcmd("fakelist", &fakelist);
75 deregistercontrolcmd("fakekill", &fakekill);
76}
77
78void fakeuser_cleanup()
79{
80 fakeuser *fake;
81 user_details *killed;
82 void *next;
83 for (fake = fakeuserlist; fake; fake = next)
84 {
85 deregisterlocaluser(fake->user, "Signing off");
86 next = fake->next;
87 free(fake);
88 }
89 for (killed = killeduserlist; killed; killed = next)
90 {
91 deleteschedule(killed->schedule, &reconnectfake, killed);
92 next = killed->next;
93 free(killed);
94 }
95 fakeusercount = 0;
15167802 96 killedusercount = 0;
8ac0e8a7
CP
97 fakeuserlist = NULL;
98 killeduserlist = NULL;
99}
100
101int fakeuser_loaddb()
102{
6c5439b1 103 if (!nofudb) {
6189af13 104 nofudb = dbapi2open(DBAPI2_DEFAULT, "fakeusers");
6c5439b1
P
105 if(!nofudb) {
106 Error("fakeuser", ERR_STOP, "Could not connect to database.");
107 return 0;
108 }
109 }
110
6c5439b1
P
111 nofudb->createtable(nofudb, NULL, NULL,
112 "CREATE TABLE ? ("
113 "nick VARCHAR(?) NOT NULL,"
114 "ident VARCHAR(?) NOT NULL,"
115 "host VARCHAR(?) NOT NULL,"
116 "realname VARCHAR(?) NOT NULL,"
117 "PRIMARY KEY (nick))", "Tdddd", "fakeusers", NICKLEN, USERLEN, HOSTLEN, REALLEN);
118
119 nofudb->query(nofudb, fakeusers_load, NULL,
120 "SELECT nick, ident, host, realname FROM ?", "T", "fakeusers");
121
8ac0e8a7
CP
122 return 1;
123}
124
6c5439b1 125void fakeusers_load(const DBAPIResult *res, void *arg) {
8ac0e8a7 126 user_details details;
8ac0e8a7 127
6c5439b1
P
128 if(!res)
129 return;
130
131 if(!res->success) {
132 Error("fakeuser", ERR_ERROR, "Error loading fakeuser list.");
133 res->clear(res);
8ac0e8a7
CP
134 return;
135 }
8ac0e8a7
CP
136
137 details.lastkill = 0;
15167802 138 details.schedule = NULL;
6c5439b1
P
139 while(res->next(res)) {
140 strlcpy(details.nick, res->get(res, 0), NICKLEN + 1);
141 strlcpy(details.ident, res->get(res, 1), USERLEN + 1);
142 strlcpy(details.host, res->get(res, 2), HOSTLEN + 1);
143 strlcpy(details.realname, res->get(res, 3), REALLEN + 1);
8ac0e8a7
CP
144 reconnectfake(&details);
145 }
6c5439b1
P
146
147 res->clear(res);
8ac0e8a7
CP
148}
149
150user_details *getdetails(nick *user)
151{
152 user_details *details;
153 details = malloc(sizeof(user_details));
154 if (!details)
155 return NULL;
8ac0e8a7
CP
156 strlcpy(details->nick, user->nick, NICKLEN + 1);
157 strlcpy(details->ident, user->ident, USERLEN + 1);
158 strlcpy(details->host, user->host->name->content, HOSTLEN + 1);
159 strlcpy(details->realname, user->realname->name->content, REALLEN + 1);
15167802 160 details->schedule = NULL;
8ac0e8a7
CP
161 details->lastkill = 0;
162 return details;
163}
164
165#define ERR_EXISTS 1
166#define ERR_MEM 2
167#define ERR_WONTKILL 3
168int err_code;
169
170nick *register_fakeuser(user_details *details)
171{
172 nick *user;
15167802 173 if ((user = getnickbynick(details->nick)) && (IsOper(user) || IsService(user) || IsXOper(user))) {
8ac0e8a7
CP
174 err_code = ERR_WONTKILL;
175 return NULL;
176 }
177
178 err_code = ERR_MEM;
179 return registerlocaluser(details->nick, details->ident, details->host, details->realname,
180 NULL, UMODE_INV | UMODE_DEAF, &fakeuser_handler);
181}
182
15167802
TG
183fakeuser *ll_add(user_details *details)
184// Adds to the (sorted) linked list
8ac0e8a7
CP
185{
186 fakeuser *fake, *newfake;
187 int cmp;
188
189 if (fakeuserlist)
190 {
191 cmp = ircd_strcmp(details->nick, fakeuserlist->user->nick);
192 if (!cmp)
193 {
194 err_code = ERR_EXISTS;
195 return NULL;
196 }
197 }
198 else
199 cmp = -1;
200 if (cmp < 0)
201 {
202 newfake = malloc(sizeof(fakeuser));
203 if (!newfake)
204 {
205 err_code = ERR_MEM;
206 return NULL;
207 }
8ac0e8a7
CP
208 newfake->user = register_fakeuser(details);
209 if (!newfake->user)
210 {
211 free(newfake);
15167802 212 return NULL; //errcode already set by register_fakeuser
8ac0e8a7
CP
213 }
214 newfake->lastkill = details->lastkill;
215 newfake->next = fakeuserlist;
216 fakeuserlist = newfake;
217 fakeusercount++;
218 return newfake;
219 }
220 for (fake = fakeuserlist; fake->next; fake = fake->next)
221 {
222 cmp = ircd_strcmp(details->nick, fake->next->user->nick);
223 if (!cmp)
224 {
225 err_code = ERR_EXISTS;
226 return NULL;
227 }
228 if (cmp < 0)
229 {
230 newfake = malloc(sizeof(fakeuser));
231 if (!newfake)
232 {
233 err_code = ERR_MEM;
234 return NULL;
235 }
236 newfake->user = register_fakeuser(details);
237 if (!newfake->user)
238 {
239 free(newfake);
15167802 240 return NULL; //errcode already set by register_fakeuser
8ac0e8a7
CP
241 }
242 newfake->lastkill = details->lastkill;
243 newfake->next = fake->next;
244 fake->next = newfake;
245 fakeusercount++;
246 return newfake;
247 }
248 }
249 newfake = malloc(sizeof(fakeuser));
250 if (!newfake)
251 {
252 err_code = ERR_MEM;
253 return NULL;
254 }
255 newfake->user = register_fakeuser(details);
256 if (!newfake->user)
257 {
258 free(newfake);
15167802 259 return NULL; //errcode already set by register_fakeuser
8ac0e8a7
CP
260 }
261 newfake->lastkill = details->lastkill;
262 newfake->next = NULL;
263 fake->next = newfake;
264 fakeusercount++;
265 return newfake;
266}
267
15167802
TG
268void kll_add(user_details *details)
269//Adds to the (sorted) linked list of killed users
8ac0e8a7
CP
270{
271 int cmp;
272 user_details *killed;
273
274 if (killeduserlist)
275 cmp = ircd_strcmp(details->nick, killeduserlist->nick);
276 else
277 cmp = -1;
278 if (cmp < 0) //Add to the start of the list
279 {
280 details->next = killeduserlist;
281 killeduserlist = details;
282 killedusercount++;
283 return;
284 }
285 for (killed = killeduserlist; killed->next; killed = killed->next)
286 {
287 cmp = ircd_strcmp(details->nick, killed->next->nick);
288 if (cmp < 0)
289 {
290 details->next = killed->next;
291 killed->next = details;
292 killedusercount++;
293 return;
294 }
295 }
296 details->next = NULL;
297 killed->next = details;
298 killedusercount++;
299 return;
300}
301
15167802
TG
302fakeuser *ll_remove(char *nickname)
303//Removes from the linked list
8ac0e8a7
CP
304{
305 fakeuser *fake, *rmfake;
306 int cmp;
307
308 if (!fakeuserlist)
309 return NULL;
310 cmp = ircd_strcmp(nickname, fakeuserlist->user->nick);
311 if (cmp < 0)
312 return NULL;
313 if (!cmp)
314 {
315 rmfake = fakeuserlist;
316 fakeuserlist = fakeuserlist->next;
317 fakeusercount--;
318 rmfake->next = NULL;
319 return rmfake;
320 }
321 for (fake = fakeuserlist; fake->next; fake = fake->next)
322 {
323 rmfake = fake->next;
324 cmp = ircd_strcmp(nickname, rmfake->user->nick);
325 if (cmp < 0)
326 return NULL;
327 if (!cmp)
328 {
329 fake->next = rmfake->next;
330 fakeusercount--;
331 rmfake->next = NULL;
332 return rmfake;
333 }
334 }
335 return NULL;
336}
337
338user_details *kll_remove(char *nickname) //Removes from the killed user linked list
339{
340 user_details *details, *rmdetails;
341 int cmp;
342
343 if (!killeduserlist)
344 return NULL;
345 cmp = ircd_strcmp(nickname, killeduserlist->nick);
346 if (cmp < 0)
347 return NULL;
348 if (!cmp)
349 {
350 rmdetails = killeduserlist;
351 killeduserlist = killeduserlist->next;
352 rmdetails->next = NULL;
353 killedusercount--;
354 return rmdetails;
355 }
356 for (details = killeduserlist; details->next; details = details->next)
357 {
358 rmdetails = details->next;
359 cmp = ircd_strcmp(nickname, rmdetails->nick);
360 if (cmp < 0)
361 return NULL;
362 if (!cmp)
363 {
364 details->next = rmdetails->next;
365 rmdetails->next = NULL;
366 killedusercount--;
367 return rmdetails;
368 }
369 }
370 return NULL;
371}
372
373void fakeuser_handler(nick *user, int command, void **params)
374{
375 if (command == LU_KILLED)
376 {
377 user_details *details;
378 fakeuser *item;
379 time_t timenow = time(NULL);
380
381 details = getdetails(user);
382 item = ll_remove(details->nick);
15167802
TG
383 if (!item)
384 {
385 controlwall(NO_OPER, NL_FAKEUSERS, "Error: A fakeuser was killed, but wasn't found in the list");
6189af13 386 Error("fakeuser", ERR_ERROR, "A fakeuser was killed, but wasn't found in the list");
8ac0e8a7 387 return;
15167802 388 }
8ac0e8a7
CP
389
390 details->lastkill = item->lastkill;
391 free(item);
392
15167802 393 if (timenow - details->lastkill < KILL_TIME) {
8ac0e8a7 394 controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) KILL'ed twice under in %d seconds. Removing.", details->nick, details->ident, details->host, details->realname, KILL_TIME);
6c5439b1 395 nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", details->nick);
8ac0e8a7
CP
396 return;
397 }
398 details->lastkill = timenow;
399
8ac0e8a7
CP
400 details->schedule = scheduleoneshot(time(NULL) + KILL_WAIT, &reconnectfake, details);
401 if (!details->schedule)
402 {
6189af13 403 Error("fakeuser", ERR_ERROR, "Couldn't reschedule fakeuser for reconnect");
8ac0e8a7
CP
404 free(details);
405 return;
406 }
407 kll_add(details);
408 }
409}
410
411//Usage: FAKEUSER nick <ident> <host> <realname>
412int fakeadd(void *sender, int cargc, char **cargv)
413{
414 user_details details, *killed;
8ac0e8a7
CP
415 nick *newnick;
416 fakeuser *newfake;
417
418 if (cargc == 0)
419 return CMD_USAGE;
420 strlcpy(details.nick, cargv[0], NICKLEN + 1);
421 if (cargc < 4)
422 strlcpy(details.realname, cargv[0], REALLEN + 1);
423 else
424 strlcpy(details.realname, cargv[3], REALLEN + 1);
425 if (cargc < 3)
426 {
427 strlcpy(details.host, cargv[0], NICKLEN + 1);
428 strlcat(details.host, ".fakeusers.quakenet.org", HOSTLEN + 1);
429 }
430 else
431 strlcpy(details.host, cargv[2], HOSTLEN + 1);
432 if (cargc < 2)
433 strlcpy(details.ident, cargv[0], USERLEN + 1);
434 else
435 strlcpy(details.ident, cargv[1], USERLEN + 1);
436
437 details.lastkill = 0;
438
439 newfake = ll_add(&details);
440 if (!newfake)
441 {
442 if (err_code == ERR_EXISTS)
443 controlreply(sender, "Error: fakeuser already exists");
444 else if (err_code == ERR_MEM)
15167802 445 {
8ac0e8a7 446 controlreply(sender, "Error: memory error!!");
6189af13 447 Error("fakeuser", ERR_STOP, "malloc error");
15167802 448 }
8ac0e8a7
CP
449 else if (err_code == ERR_WONTKILL)
450 controlreply(sender, "Nick already exists and I won't kill it");
451 else
15167802 452 {
8ac0e8a7 453 controlreply(sender, "Unknown error when adding fakeuser");
6189af13 454 Error("fakeuser", ERR_ERROR, "Unknown error when adding fakeuser");
15167802 455 }
8ac0e8a7
CP
456 return CMD_ERROR;
457 }
458 newnick = newfake->user;
8ac0e8a7
CP
459 if ((killed = kll_remove(newnick->nick))) //Is this nickname scheduled to reconnect?
460 {
461 deleteschedule(killed->schedule, &reconnectfake, killed);
462 free(killed);
6c5439b1 463 nofudb->squery(nofudb, "UPDATE ? SET ident=?, host=?, realname=? WHERE nick = ?", "Tssss", "fakeusers", newnick->ident, newnick->host->name->content, newnick->realname->name->content, newnick->nick);
8ac0e8a7
CP
464 }
465 else
6c5439b1 466 nofudb->squery(nofudb, "INSERT INTO ? (nick, ident, host, realname) VALUES (?,?,?,?)", "Tssss", "fakeusers", newnick->nick, newnick->ident, newnick->host->name->content, newnick->realname->name->content);
8ac0e8a7
CP
467 controlreply(sender, "Added fake user %s", newnick->nick);
468 controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) added by %s/%s", newnick->nick, newnick->ident,
469 newnick->host->name->content, newnick->realname->name->content, ((nick*)sender)->nick, ((nick*)sender)->authname);
470#ifdef SIT_CHANNEL
471 {
472 channel *sitchannel;
473 if (!(sitchannel = findchannel(SIT_CHANNEL)))
474 sitchannel = createchannel(SIT_CHANNEL);
475 localjoinchannel(newnick, sitchannel);
476 }
477#endif
478 return CMD_OK;
479}
480
481//Usage: FAKELIST
482int fakelist(void *sender, int cargc, char **cargv)
483{
484 fakeuser *fake;
485 if (fakeusercount == 1)
486 controlreply(sender, "1 fakeuser is currently connected");
487 else
488 controlreply(sender, "%d fakeusers are currently connected", fakeusercount);
489 for(fake = fakeuserlist; fake; fake = fake->next)
490 controlreply(sender, "%s!%s@%s (%s)", fake->user->nick, fake->user->ident,
491 fake->user->host->name->content, fake->user->realname->name->content);
492 if (killeduserlist)
493 {
494 user_details *k_fake;
495 if (fakeusercount == 1)
496 controlreply(sender, "1 fakeuser is currently waiting to reconnect");
497 else
498 controlreply(sender, "%d fakeusers are currently waiting to reconnect", killedusercount);
499 for(k_fake = killeduserlist; k_fake; k_fake = k_fake->next)
500 controlreply(sender, "%s!%s@%s (%s)", k_fake->nick, k_fake->ident, k_fake->host, k_fake->realname);
501 }
502 return CMD_OK;
503}
504
505//Usage: FAKEKILL nick <reason>
506int fakekill(void *sender, int cargc, char **cargv)
507{
508 fakeuser *fake;
509 user_details *k_fake;
8ac0e8a7
CP
510 if (cargc == 0)
511 return CMD_USAGE;
512 if ((fake = ll_remove(cargv[0])))
513 {
6c5439b1 514 nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", fake->user->nick);
8ac0e8a7
CP
515 controlreply(sender, "Killed fake user %s", fake->user->nick);
516 controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) removed by %s/%s", fake->user->nick, fake->user->ident,
517 fake->user->host->name->content, fake->user->realname->name->content, ((nick*)sender)->nick, ((nick*)sender)->authname);
518 if (cargc > 1)
519 deregisterlocaluser(fake->user, cargv[1]);
520 else
521 deregisterlocaluser(fake->user, "Signing off");
522 free(fake);
523 return CMD_OK;
524 }
525 if ((k_fake = kll_remove(cargv[0]))) //Fakeuser might be waiting to rejoin
526 {
6c5439b1 527 nofudb->squery(nofudb, "DELETE FROM ? WHERE nick = ?", "Ts", "fakeusers", k_fake->nick);
8ac0e8a7
CP
528 controlreply(sender, "Killed fake user %s", k_fake->nick);
529 controlwall(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) removed by %s/%s", k_fake->nick,
530 k_fake->ident, k_fake->host, k_fake->realname, ((nick*)sender)->nick, ((nick*)sender)->authname);
531 free(k_fake);
532 return CMD_OK;
533 }
534 controlreply(sender, "No fakeuser with that nick exists");
535 return CMD_ERROR;
536}
537
538void reconnectfake(void *details)
15167802 539//Called after the timeout period has expired since a fakeuser was killed, or on load
8ac0e8a7
CP
540{
541 fakeuser *fake;
542 user_details *u_details = details;
543 if (u_details->schedule)
544 kll_remove(u_details->nick); //Fakeuser was /kill'd
545 fake = ll_add(u_details);
546 if (u_details->schedule)
547 free(u_details);
548 if (!fake)
549 return;
550#ifdef SIT_CHANNEL
551 {
552 channel *sitchannel;
553 if (!(sitchannel = findchannel(SIT_CHANNEL)))
554 sitchannel = createchannel(SIT_CHANNEL);
555 localjoinchannel(fake->user, sitchannel);
556 }
557#endif
558}