]>
jfr.im git - irc/quakenet/newserv.git/blob - noperserv/noperserv_fakeuser.c
2 * NOperserv Fakeuser module
4 * Allows fakeusers to be added so as to block nicks, for example.
6 * Copyright (c) Tim Gordon 2006.
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"
16 #include "../dbapi/dbapi.h"
17 #include "../lib/strlfunc.h"
18 #include "../lib/version.h"
24 /* #define SIT_CHANNEL "#qnet.fakeusers" */
28 typedef struct fakeuser
{
31 struct fakeuser
*next
;
34 typedef struct user_details
{
35 char nick
[NICKLEN
+ 1];
36 char ident
[USERLEN
+ 1];
37 char host
[HOSTLEN
+ 1];
38 char realname
[REALLEN
+ 1];
40 struct user_details
*next
;
44 fakeuser
*fakeuserlist
= NULL
;
45 user_details
*killeduserlist
= NULL
;
46 int fakeusercount
= 0;
47 int killedusercount
= 0;
49 void fakeuser_cleanup();
50 int fakeuser_loaddb();
51 void fakeusers_load(DBConn
*dbconn
, void *tag
);
52 void fakeuser_handler(nick
*user
, int command
, void **params
);
53 int fakeadd(void *sender
, int cargc
, char **cargv
);
54 int fakelist(void *sender
, int cargc
, char **cargv
);
55 int fakekill(void *sender
, int cargc
, char **cargv
);
56 void reconnectfake(void *details
);
59 if (!fakeuser_loaddb())
61 Error("noperserv_fakeuser", ERR_FATAL
, "Cannot load database");
64 registercontrolhelpcmd("fakeuser", NO_OPER
, 4, &fakeadd
, "Usage: FAKEUSER nick <ident> <host> <realname>\nCreates a fake user.");
65 registercontrolhelpcmd("fakelist", NO_OPER
, 0, &fakelist
, "Usage: FAKELIST\nLists all fake users.");
66 registercontrolhelpcmd("fakekill", NO_OPER
, 2, &fakekill
, "Usage: FAKEKILL nick <reason>\nRemoves a fake user");
71 deregistercontrolcmd("fakeuser", &fakeadd
);
72 deregistercontrolcmd("fakelist", &fakelist
);
73 deregistercontrolcmd("fakekill", &fakekill
);
76 void fakeuser_cleanup()
81 for (fake
= fakeuserlist
; fake
; fake
= next
)
83 deregisterlocaluser(fake
->user
, "Signing off");
87 for (killed
= killeduserlist
; killed
; killed
= next
)
89 deleteschedule(killed
->schedule
, &reconnectfake
, killed
);
96 killeduserlist
= NULL
;
105 dbcreatequery("CREATE TABLE noperserv.fakeusers ("
106 "nick VARCHAR(%d) NOT NULL,"
107 "ident VARCHAR(%d) NOT NULL,"
108 "host VARCHAR(%d) NOT NULL,"
109 "realname VARCHAR(%d) NOT NULL,"
110 "PRIMARY KEY (nick))", NICKLEN
, USERLEN
, HOSTLEN
, REALLEN
);
111 dbasyncquery(&fakeusers_load
, NULL
, "SELECT nick, ident, host, realname FROM noperserv.fakeusers");
115 void fakeusers_load(DBConn
*dbconn
, void *tag
)
116 // Called automatically when the async database query finishes
118 DBResult
*pgres
= dbgetresult(dbconn
);
119 user_details details
;
121 if (!dbquerysuccessful(pgres
)) {
122 Error("noperserv_fakeuser", ERR_FATAL
, "Error loading fakeuser list.");
127 details
.lastkill
= 0;
128 details
.schedule
= NULL
;
129 while(dbfetchrow(pgres
)) {
130 strlcpy(details
.nick
, dbgetvalue(pgres
, 0), NICKLEN
+ 1);
131 strlcpy(details
.ident
, dbgetvalue(pgres
, 1), USERLEN
+ 1);
132 strlcpy(details
.host
, dbgetvalue(pgres
, 2), HOSTLEN
+ 1);
133 strlcpy(details
.realname
, dbgetvalue(pgres
, 3), REALLEN
+ 1);
134 reconnectfake(&details
);
139 user_details
*getdetails(nick
*user
)
141 user_details
*details
;
142 details
= malloc(sizeof(user_details
));
145 strlcpy(details
->nick
, user
->nick
, NICKLEN
+ 1);
146 strlcpy(details
->ident
, user
->ident
, USERLEN
+ 1);
147 strlcpy(details
->host
, user
->host
->name
->content
, HOSTLEN
+ 1);
148 strlcpy(details
->realname
, user
->realname
->name
->content
, REALLEN
+ 1);
149 details
->schedule
= NULL
;
150 details
->lastkill
= 0;
156 #define ERR_WONTKILL 3
159 nick
*register_fakeuser(user_details
*details
)
162 if ((user
= getnickbynick(details
->nick
)) && (IsOper(user
) || IsService(user
) || IsXOper(user
))) {
163 err_code
= ERR_WONTKILL
;
168 return registerlocaluser(details
->nick
, details
->ident
, details
->host
, details
->realname
,
169 NULL
, UMODE_INV
| UMODE_DEAF
, &fakeuser_handler
);
172 fakeuser
*ll_add(user_details
*details
)
173 // Adds to the (sorted) linked list
175 fakeuser
*fake
, *newfake
;
180 cmp
= ircd_strcmp(details
->nick
, fakeuserlist
->user
->nick
);
183 err_code
= ERR_EXISTS
;
191 newfake
= malloc(sizeof(fakeuser
));
197 newfake
->user
= register_fakeuser(details
);
201 return NULL
; //errcode already set by register_fakeuser
203 newfake
->lastkill
= details
->lastkill
;
204 newfake
->next
= fakeuserlist
;
205 fakeuserlist
= newfake
;
209 for (fake
= fakeuserlist
; fake
->next
; fake
= fake
->next
)
211 cmp
= ircd_strcmp(details
->nick
, fake
->next
->user
->nick
);
214 err_code
= ERR_EXISTS
;
219 newfake
= malloc(sizeof(fakeuser
));
225 newfake
->user
= register_fakeuser(details
);
229 return NULL
; //errcode already set by register_fakeuser
231 newfake
->lastkill
= details
->lastkill
;
232 newfake
->next
= fake
->next
;
233 fake
->next
= newfake
;
238 newfake
= malloc(sizeof(fakeuser
));
244 newfake
->user
= register_fakeuser(details
);
248 return NULL
; //errcode already set by register_fakeuser
250 newfake
->lastkill
= details
->lastkill
;
251 newfake
->next
= NULL
;
252 fake
->next
= newfake
;
257 void kll_add(user_details
*details
)
258 //Adds to the (sorted) linked list of killed users
261 user_details
*killed
;
264 cmp
= ircd_strcmp(details
->nick
, killeduserlist
->nick
);
267 if (cmp
< 0) //Add to the start of the list
269 details
->next
= killeduserlist
;
270 killeduserlist
= details
;
274 for (killed
= killeduserlist
; killed
->next
; killed
= killed
->next
)
276 cmp
= ircd_strcmp(details
->nick
, killed
->next
->nick
);
279 details
->next
= killed
->next
;
280 killed
->next
= details
;
285 details
->next
= NULL
;
286 killed
->next
= details
;
291 fakeuser
*ll_remove(char *nickname
)
292 //Removes from the linked list
294 fakeuser
*fake
, *rmfake
;
299 cmp
= ircd_strcmp(nickname
, fakeuserlist
->user
->nick
);
304 rmfake
= fakeuserlist
;
305 fakeuserlist
= fakeuserlist
->next
;
310 for (fake
= fakeuserlist
; fake
->next
; fake
= fake
->next
)
313 cmp
= ircd_strcmp(nickname
, rmfake
->user
->nick
);
318 fake
->next
= rmfake
->next
;
327 user_details
*kll_remove(char *nickname
) //Removes from the killed user linked list
329 user_details
*details
, *rmdetails
;
334 cmp
= ircd_strcmp(nickname
, killeduserlist
->nick
);
339 rmdetails
= killeduserlist
;
340 killeduserlist
= killeduserlist
->next
;
341 rmdetails
->next
= NULL
;
345 for (details
= killeduserlist
; details
->next
; details
= details
->next
)
347 rmdetails
= details
->next
;
348 cmp
= ircd_strcmp(nickname
, rmdetails
->nick
);
353 details
->next
= rmdetails
->next
;
354 rmdetails
->next
= NULL
;
362 void fakeuser_handler(nick
*user
, int command
, void **params
)
364 if (command
== LU_KILLED
)
366 user_details
*details
;
368 time_t timenow
= time(NULL
);
370 details
= getdetails(user
);
371 item
= ll_remove(details
->nick
);
374 controlwall(NO_OPER
, NL_FAKEUSERS
, "Error: A fakeuser was killed, but wasn't found in the list");
375 Error("noperserv_fakeuser", ERR_ERROR
, "A fakeuser was killed, but wasn't found in the list");
379 details
->lastkill
= item
->lastkill
;
382 if (timenow
- details
->lastkill
< KILL_TIME
) {
383 char escnick
[NICKLEN
* 2 + 1];
384 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
);
385 dbescapestring(escnick
, details
->nick
, strlen(details
->nick
));
386 dbquery("DELETE FROM noperserv.fakeusers WHERE nick = '%s'", escnick
);
389 details
->lastkill
= timenow
;
392 controlwalls(NO_OPER, NL_FAKEUSERS, "Fake user %s!%s@%s (%s) was KILL'ed", details->nick,
393 details->ident, details->host, details->realname);
395 details
->schedule
= scheduleoneshot(time(NULL
) + KILL_WAIT
, &reconnectfake
, details
);
396 if (!details
->schedule
)
398 Error("noperserv_fakeuser", ERR_ERROR
, "Couldn't reschedule fakeuser for reconnect");
406 //Usage: FAKEUSER nick <ident> <host> <realname>
407 int fakeadd(void *sender
, int cargc
, char **cargv
)
409 user_details details
, *killed
;
410 char escnick
[NICKLEN
* 2 + 1], escident
[USERLEN
* 2 + 1], eschost
[HOSTLEN
* 2 + 1], escreal
[REALLEN
* 2 + 1];
416 strlcpy(details
.nick
, cargv
[0], NICKLEN
+ 1);
418 strlcpy(details
.realname
, cargv
[0], REALLEN
+ 1);
420 strlcpy(details
.realname
, cargv
[3], REALLEN
+ 1);
423 strlcpy(details
.host
, cargv
[0], NICKLEN
+ 1);
424 strlcat(details
.host
, ".fakeusers.quakenet.org", HOSTLEN
+ 1);
427 strlcpy(details
.host
, cargv
[2], HOSTLEN
+ 1);
429 strlcpy(details
.ident
, cargv
[0], USERLEN
+ 1);
431 strlcpy(details
.ident
, cargv
[1], USERLEN
+ 1);
433 details
.lastkill
= 0;
435 newfake
= ll_add(&details
);
438 if (err_code
== ERR_EXISTS
)
439 controlreply(sender
, "Error: fakeuser already exists");
440 else if (err_code
== ERR_MEM
)
442 controlreply(sender
, "Error: memory error!!");
443 Error("noperserv_fakeuser", ERR_STOP
, "malloc error");
445 else if (err_code
== ERR_WONTKILL
)
446 controlreply(sender
, "Nick already exists and I won't kill it");
449 controlreply(sender
, "Unknown error when adding fakeuser");
450 Error("noperserv_fakeuser", ERR_ERROR
, "Unknown error when adding fakeuser");
454 newnick
= newfake
->user
;
455 dbescapestring(escnick
, newnick
->nick
, strlen(newnick
->nick
));
456 dbescapestring(escident
, newnick
->ident
, strlen(newnick
->ident
));
457 dbescapestring(eschost
, newnick
->host
->name
->content
, newnick
->host
->name
->length
);
458 dbescapestring(escreal
, newnick
->realname
->name
->content
, newnick
->realname
->name
->length
);
459 if ((killed
= kll_remove(newnick
->nick
))) //Is this nickname scheduled to reconnect?
461 deleteschedule(killed
->schedule
, &reconnectfake
, killed
);
463 dbquery("UPDATE noperserv.fakeusers SET ident = '%s', host = '%s', realname = '%s' WHERE nick = '%s'",
464 escident
, eschost
, escreal
, escnick
);
467 dbquery("INSERT INTO noperserv.fakeusers (nick, ident, host, realname) VALUES ('%s', '%s', '%s', '%s')",
468 escnick
, escident
, eschost
, escreal
);
469 controlreply(sender
, "Added fake user %s", newnick
->nick
);
470 controlwall(NO_OPER
, NL_FAKEUSERS
, "Fake user %s!%s@%s (%s) added by %s/%s", newnick
->nick
, newnick
->ident
,
471 newnick
->host
->name
->content
, newnick
->realname
->name
->content
, ((nick
*)sender
)->nick
, ((nick
*)sender
)->authname
);
475 if (!(sitchannel
= findchannel(SIT_CHANNEL
)))
476 sitchannel
= createchannel(SIT_CHANNEL
);
477 localjoinchannel(newnick
, sitchannel
);
484 int fakelist(void *sender
, int cargc
, char **cargv
)
487 if (fakeusercount
== 1)
488 controlreply(sender
, "1 fakeuser is currently connected");
490 controlreply(sender
, "%d fakeusers are currently connected", fakeusercount
);
491 for(fake
= fakeuserlist
; fake
; fake
= fake
->next
)
492 controlreply(sender
, "%s!%s@%s (%s)", fake
->user
->nick
, fake
->user
->ident
,
493 fake
->user
->host
->name
->content
, fake
->user
->realname
->name
->content
);
496 user_details
*k_fake
;
497 if (fakeusercount
== 1)
498 controlreply(sender
, "1 fakeuser is currently waiting to reconnect");
500 controlreply(sender
, "%d fakeusers are currently waiting to reconnect", killedusercount
);
501 for(k_fake
= killeduserlist
; k_fake
; k_fake
= k_fake
->next
)
502 controlreply(sender
, "%s!%s@%s (%s)", k_fake
->nick
, k_fake
->ident
, k_fake
->host
, k_fake
->realname
);
507 //Usage: FAKEKILL nick <reason>
508 int fakekill(void *sender
, int cargc
, char **cargv
)
511 user_details
*k_fake
;
512 char escnick
[NICKLEN
* 2 + 1];
515 if ((fake
= ll_remove(cargv
[0])))
517 dbescapestring(escnick
, fake
->user
->nick
, strlen(fake
->user
->nick
));
518 dbquery("DELETE FROM noperserv.fakeusers WHERE nick = '%s'", escnick
);
519 controlreply(sender
, "Killed fake user %s", fake
->user
->nick
);
520 controlwall(NO_OPER
, NL_FAKEUSERS
, "Fake user %s!%s@%s (%s) removed by %s/%s", fake
->user
->nick
, fake
->user
->ident
,
521 fake
->user
->host
->name
->content
, fake
->user
->realname
->name
->content
, ((nick
*)sender
)->nick
, ((nick
*)sender
)->authname
);
523 deregisterlocaluser(fake
->user
, cargv
[1]);
525 deregisterlocaluser(fake
->user
, "Signing off");
529 if ((k_fake
= kll_remove(cargv
[0]))) //Fakeuser might be waiting to rejoin
531 dbescapestring(escnick
, k_fake
->nick
, strlen(k_fake
->nick
));
532 dbquery("DELETE FROM noperserv.fakeusers WHERE nick = '%s'", escnick
);
533 controlreply(sender
, "Killed fake user %s", k_fake
->nick
);
534 controlwall(NO_OPER
, NL_FAKEUSERS
, "Fake user %s!%s@%s (%s) removed by %s/%s", k_fake
->nick
,
535 k_fake
->ident
, k_fake
->host
, k_fake
->realname
, ((nick
*)sender
)->nick
, ((nick
*)sender
)->authname
);
539 controlreply(sender
, "No fakeuser with that nick exists");
543 void reconnectfake(void *details
)
544 //Called after the timeout period has expired since a fakeuser was killed, or on load
547 user_details
*u_details
= details
;
548 if (u_details
->schedule
)
549 kll_remove(u_details
->nick
); //Fakeuser was /kill'd
550 fake
= ll_add(u_details
);
551 if (u_details
->schedule
)
558 if (!(sitchannel
= findchannel(SIT_CHANNEL
)))
559 sitchannel
= createchannel(SIT_CHANNEL
);
560 localjoinchannel(fake
->user
, sitchannel
);