]> jfr.im git - irc/quakenet/newserv.git/blame - fakeusers/fakeusers.c
TRUSTS: require sqlite
[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 KILL_WAIT 10
25#define KILL_TIME 60
26
27typedef 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 37static fakeuser *fakeuserlist;
6c5439b1
P
38static DBAPIConn *nofudb;
39
710f0af8
GB
40static void reconnectfakeuser(void *arg);
41
42static 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
52static 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
70static 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
76static 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
104static 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
120static 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
144static 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
158static 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
174static 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
198static 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 246static 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 266static 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
288void _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
299void _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}