]> jfr.im git - irc/quakenet/newserv.git/blame - noperserv/noperserv_hooks.c
Implement authext/user support for NOperserv.
[irc/quakenet/newserv.git] / noperserv / noperserv_hooks.c
CommitLineData
3e3692bf
CP
1#include "../control/control.h"
2#include "../localuser/localuser.h"
3#include "../core/schedule.h"
43e82ceb 4#include "../core/modules.h"
3e3692bf
CP
5#include "../lib/splitline.h"
6#include "../lib/flags.h"
7#include "../lib/irc_string.h"
8#include "../lib/strlfunc.h"
9
10#include "noperserv.h"
11#include "noperserv_db.h"
12#include "noperserv_hooks.h"
13#include "noperserv_policy.h"
14
15#include <stdlib.h>
16#include <string.h>
17#include <stdarg.h>
18
19struct storedhook {
20 CommandHandler old;
21 sstring *name;
6ebc9d2f
P
22 cmdhelp *oldhelp;
23 cmdhelp *newhelp;
3e3692bf
CP
24 struct storedhook *next;
25} storedhook;
26
27struct storedhook *storedhooks = NULL;
28
29int firsttime = 0;
30nick *replynick = NULL;
31
32UserMessageHandler oldhandler;
33ControlMsg oldreply;
34ControlWall oldwall;
6ebc9d2f 35ControlPermitted oldpermitted;
3e3692bf
CP
36
37void noperserv_trap_registration(int hooknum, void *arg);
38int noperserv_showcommands(void *sender, int cargc, char **cargv);
39int noperserv_rmmod(void *sender, int cargc, char **cargv);
40int noperserv_reload(void *sender, int cargc, char **cargv);
41int noperserv_whois(void *sender, int cargc, char **cargv);
42int noperserv_help(void *sender, int cargc, char **cargv);
43void noperserv_whois_handler(int hooknum, void *arg);
44void noperserv_whois_account_handler(int hooknum, void *arg);
45void noperserv_handle_messages(nick *target, int messagetype, void **args);
bb4b25ee 46void noperserv_reply(nick *np, char *format, ...) __attribute__ ((format (printf, 2, 3)));
3e3692bf
CP
47void noperserv_wall(flag_t permissionlevel, flag_t noticelevel, char *format, ...);
48
49struct specialsched special;
50
51#define HOOK_CONTROL_WHOISREQUEST_AUTHNAME -1
52#define HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER -2
53
54void noperserv_setup_hooks(void) {
55 oldreply = controlreply;
56 controlreply = &noperserv_reply;
57
58 oldwall = controlwall;
59 controlwall = &noperserv_wall;
60
6ebc9d2f
P
61 oldpermitted = controlpermitted;
62 controlpermitted = &noperserv_policy_command_permitted;
63
62a602c3 64 memset(&special, 0, sizeof(struct specialsched));
3e3692bf
CP
65
66 if(!mynick) {
67 registerhook(HOOK_CONTROL_REGISTERED, &noperserv_trap_registration);
68 } else {
69 noperserv_trap_registration(0, (void *)mynick);
70 }
71
72 registerhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
73}
74
75int noperserv_hook_command(char *command, CommandHandler newcommand, char *newhelp) {
76 struct storedhook *newhook;
77 Command *fetchcommand = findcommandintree(controlcmds, command, 1);
78
79 if(!fetchcommand)
80 return 1;
81
82 newhook = (struct storedhook *)malloc(sizeof(struct storedhook));
83 if(!newhook)
84 return 1;
85
86 newhook->name = getsstring(command, strlen(command));
87 if(!newhook->name) {
88 free(newhook);
89 return 1;
90 }
91
92 newhook->old = fetchcommand->handler;
93 if(newhelp) {
6ebc9d2f
P
94 newhook->newhelp = (cmdhelp *)malloc(sizeof(cmdhelp));
95 memset(newhook->newhelp,0,sizeof(cmdhelp));
3e3692bf
CP
96 if(!newhook->newhelp) {
97 freesstring(newhook->name);
98 free(newhook);
6ebc9d2f
P
99 } else {
100 int len = strlen(newhelp) + 1;
101 newhook->newhelp->helpstr = (char *)malloc(len);
102 if (newhook->newhelp->helpstr) {
103 strlcpy(newhook->newhelp->helpstr, newhelp, len);
104 }
105 newhook->oldhelp = fetchcommand->ext;
106 fetchcommand->ext = newhook->newhelp;
3e3692bf 107 }
3e3692bf
CP
108 } else {
109 newhook->newhelp = NULL;
110 }
111
112 newhook->next = storedhooks;
113 storedhooks = newhook;
114
115 fetchcommand->handler = newcommand;
116
117 return 0;
118}
119
120void noperserv_unhook_all_commands(void) {
121 struct storedhook *nh, *ch = storedhooks;
122 Command *fetchcommand;
123
124 while(ch) {
125 if(ch->old && (fetchcommand = findcommandintree(controlcmds, ch->name->content, 1))) {
126 fetchcommand->handler = ch->old;
127 if(ch->newhelp) {
6ebc9d2f
P
128 fetchcommand->ext = ch->oldhelp;
129 if ( ((cmdhelp *)ch->newhelp)->helpstr)
130 free( ((cmdhelp *)ch->newhelp)->helpstr);
3e3692bf
CP
131 free(ch->newhelp);
132 }
133 }
134 nh = ch->next;
135 freesstring(ch->name);
136 free(ch);
137 ch = nh;
138 }
139}
140
141void noperserv_cleanup_hooks(void) {
142 deregisterhook(HOOK_CONTROL_WHOISREQUEST, &noperserv_whois_handler);
143 deregisterhook(HOOK_CONTROL_REGISTERED, &noperserv_trap_registration);
144
145 if(firsttime) {
146 noperserv_unhook_all_commands();
147 firsttime = 0;
148 }
149
4c551b15 150 if(oldhandler && mynick)
3e3692bf
CP
151 hooklocaluserhandler(mynick, oldhandler);
152
153 controlwall = oldwall;
154 controlreply = oldreply;
6ebc9d2f 155 controlpermitted = oldpermitted;
3e3692bf
CP
156}
157
158void noperserv_trap_registration(int hooknum, void *arg) {
4c551b15
CP
159 nick *np = (nick *)arg;
160 if(!np)
161 return;
162
3e3692bf
CP
163 oldhandler = hooklocaluserhandler((nick *)arg, &noperserv_handle_messages);
164 if(!oldhandler)
165 return;
166
167 if(!firsttime) {
168 firsttime = 1;
169 noperserv_hook_command("rmmod", &noperserv_rmmod, NULL);
170 noperserv_hook_command("reload", &noperserv_reload, NULL);
171 noperserv_hook_command("showcommands", &noperserv_showcommands, NULL);
172 noperserv_hook_command("whois", &noperserv_whois, "Usage: whois <nickname|#authname|*numeric>\nDisplays lots of information about the specified nickname, auth name or numeric.");
173 noperserv_hook_command("help", &noperserv_help, NULL);
174 }
175}
176
177CommandHandler noperserv_find_hook(char *command) {
178 struct storedhook *hh = storedhooks;
179 for(;hh;hh=hh->next)
180 if(!ircd_strcmp(hh->name->content, command))
181 return hh->old;
182
183 return NULL;
184}
185
43e82ceb
CP
186int noperserv_modules_loaded(char *mask) {
187 int i;
188 char *ptr;
189
2fb74c5e 190 for(i=0,ptr=lsmod(i,NULL,NULL,NULL);ptr;ptr=lsmod(++i,NULL,NULL,NULL))
43e82ceb
CP
191 if(match2strings(mask, ptr))
192 return 1;
193
194 return 0;
195}
196
3e3692bf
CP
197int noperserv_specialmod(nick *np, char *command, ScheduleCallback reloadhandler, int cargc, char **cargv) {
198 CommandHandler oldcommand = noperserv_find_hook(command);
199 if(cargc < 1) {
200 if(oldcommand)
201 return oldcommand(np, cargc, cargv);
202 return CMD_ERROR;
203 }
204
205 if(!strcmp(cargv[0], "noperserv")) {
206 if(special.schedule) {
207 controlreply(np, "Previous attempt at un/reload still in progress.");
208 return CMD_OK;
209 } else {
210 special.modulename = getsstring(cargv[0], strlen(cargv[0]));
211 if(!special.modulename) {
212 controlreply(np, "Unable to copy module name. Seek cow herd to trample on server.");
213 return CMD_ERROR;
214 } else {
215 special.schedule = scheduleoneshot(time(NULL) + 1, reloadhandler, &special);
216 if(!special.schedule) {
217 freesstring(special.modulename);
218 special.modulename = NULL;
219 controlreply(np, "Unable to allocate schedule. Seek cow herd to trample on server.");
220 return CMD_ERROR;
221 }
222 controlreply(np, "Special case un/reload in <1 second, no response will be sent, standby. . .");
223 return CMD_OK;
224 }
225 }
226 } else {
227 if(oldcommand)
228 return oldcommand(np, cargc, cargv);
229 return CMD_ERROR;
230 }
231}
232
233int noperserv_rmmod(void *sender, int cargc, char **cargv) {
234 return noperserv_specialmod(sender, "rmmod", &controlspecialrmmod, cargc, cargv);
235}
236
237int noperserv_reload(void *sender, int cargc, char **cargv) {
238 return noperserv_specialmod(sender, "reload", &controlspecialreloadmod, cargc, cargv);
239}
240
241void noperserv_whois_hook(int hooknum, void *arg) {
242 controlreply(replynick, "%s", (char *)arg);
243}
244
245int noperserv_whois(void *sender, int cargc, char **cargv) {
7078aa50 246 authname *an;
3e3692bf
CP
247 no_autheduser *au;
248 nick *np = (nick *)sender;
249 CommandHandler oldwhois = noperserv_find_hook("whois");
250
251 if(cargc < 1) {
252 if(oldwhois)
253 return oldwhois(sender, cargc, cargv);
254 return CMD_ERROR;
255 }
256
257 if(cargv[0][0] != '#') {
258 if(cargv[0][0] == '*')
259 cargv[0][0] = '#';
260 if(oldwhois)
261 return oldwhois(sender, cargc, cargv);
262 return CMD_ERROR;
263 }
7078aa50
GB
264
265 an = findauthnamebyname(cargv[0] + 1);
266 if(!an) {
3e3692bf
CP
267 controlreply(np, "Account not registered.");
268 return CMD_OK;
7078aa50
GB
269 }
270
271 au = noperserv_get_autheduser(an);
272 if(!au) {
273 controlreply(np, "User does not have a NOperserv account.");
274 return CMD_OK;
3e3692bf
CP
275 }
276
7078aa50 277 controlreply(np, "Account : %s", au->authname->name);
3e3692bf
CP
278
279 replynick = np;
280
281 registerhook(HOOK_CONTROL_WHOISREPLY, &noperserv_whois_hook);
282 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
283 deregisterhook(HOOK_CONTROL_WHOISREPLY, &noperserv_whois_hook);
284
285 controlreply(np, "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
286
287 return CMD_OK;
288}
289
290int noperserv_showcommands(void *sender, int cargc, char **cargv) {
291 nick *np = (nick *)sender;
292 Command *cmdlist[100];
293 int i, n;
294
295 n = getcommandlist(controlcmds, cmdlist, 100);
296
297 controlreply(np, "The following commands are registered at present:");
298
299 for(i=0;i<n;i++)
ad4fd3ca 300 if(noperserv_policy_command_permitted(cmdlist[i]->level, np))
331b52e3 301 controlreply(np, " %-25s %s", cmdlist[i]->command->content, printflags(cmdlist[i]->level, no_commandflags));
3e3692bf
CP
302
303 controlreply(np, "End of list.");
304 return CMD_OK;
305}
306
307void noperserv_whois_handler(int hooknum, void *arg) {
308 char message[100];
309 nick *np = (nick *)arg;
310 no_autheduser *au;
311 if(!np)
312 return;
313
314 if(IsAccount(np)) {
315 au = NOGetAuthedUser(np);
316 if(au) {
317 snprintf(message, sizeof(message), "Flags : %s", printflags(NOGetAuthLevel(au), no_userflags));
318 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER, (void *)au);
319 } else {
320 snprintf(message, sizeof(message), "Flags : (user not known)");
321 noperserv_whois_account_handler(HOOK_CONTROL_WHOISREQUEST_AUTHNAME, (void *)np->authname);
322 }
323 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
324 }
325}
326
327/* mmm, hacky */
328void noperserv_whois_account_handler(int hooknum, void *arg) {
329 int count = 0, found = 0;
330 char nickbuffer[(NICKLEN + 2) * NO_NICKS_PER_WHOIS_LINE - 1]; /* since we don't need space or comma for the first item we're fine NULL wise */
331 char accountspace[NICKLEN + 3]; /* space, comma, null */
332 char message[1024];
7078aa50 333 nick *np;
3e3692bf
CP
334
335 nickbuffer[0] = '\0';
336 if(hooknum == HOOK_CONTROL_WHOISREQUEST_AUTHEDUSER) {
337 /* we can just read out the authed user linked list */
338 no_autheduser *au = (void *)arg;
3e3692bf 339
7078aa50 340 if(au->authname->nicks)
3e3692bf
CP
341 found = 1;
342
7078aa50
GB
343 for(np=au->authname->nicks;np;np=np->nextbyauthname) {
344 snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", np->nick);
3e3692bf
CP
345 strlcat(nickbuffer, accountspace, sizeof(nickbuffer));
346
347 if(count >= NO_NICKS_PER_WHOIS_LINE) {
348 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
349 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
350 nickbuffer[0] = '\0';
351 count = 0;
352 }
353 }
354 } else {
355 /* inefficient way */
356 char *authname = (char *)arg;
357 int i = 0;
358 nick *sp;
359
360 for(;i<NICKHASHSIZE;i++)
361 for(sp=nicktable[i];sp;sp=sp->next)
362 if(IsAccount(sp) && !ircd_strcmp(sp->authname, authname)) {
363 found = 1;
364
365 snprintf(accountspace, sizeof(accountspace), "%s%s", count++?", ":"", sp->nick);
366 strlcat(nickbuffer, accountspace, sizeof(nickbuffer));
367
368 if(count >= NO_NICKS_PER_WHOIS_LINE) {
369 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
370 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
371 nickbuffer[0] = '\0';
372 count = 0;
373 }
374 }
375 }
376
377 if(!found) {
378 snprintf(message, sizeof(message), "Authed : (no nicks authed)");
379 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
380 } else if(nickbuffer[0]) {
381 snprintf(message, sizeof(message), "Authed : %s", nickbuffer);
382 triggerhook(HOOK_CONTROL_WHOISREPLY, message);
383 }
384}
385
386/* Obviously pinched from control.c */
387void noperserv_handle_messages(nick *target, int messagetype, void **args) {
388 Command *cmd;
389 char *cargv[50];
390 int cargc;
391 nick *sender;
392
393 switch(messagetype) {
394 case LU_PRIVMSG: /* override these two commands only */
395 case LU_SECUREMSG:
396 /* If it's a message, first arg is nick and second is message */
397 sender = (nick *)args[0];
398
399 controlwall(NO_DEVELOPER, NL_ALL_COMMANDS, "From: %s!%s@%s%s%s: %s", sender->nick, sender->ident, sender->host->name->content, IsAccount(sender)?"/":"", IsAccount(sender)?sender->authname:"", (char *)args[1]);
400
401 /* Split the line into params */
402 cargc = splitline((char *)args[1], cargv, 50, 0);
403
404 if(!cargc) /* Blank line */
405 return;
406
407 cmd = findcommandintree(controlcmds,cargv[0],1);
408 if(!cmd) {
b2896776 409 controlreply(sender, "Unknown command or access denied.");
3e3692bf
CP
410 return;
411 }
412
413 /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
414 /* Here it is! */
415 if (!noperserv_policy_command_permitted(cmd->level, sender)) {
b2896776 416 controlreply(sender, "Unknown command or access denied.");
3e3692bf
CP
417 return;
418 }
419
420 /* Check the maxargs */
421 if(cmd->maxparams < (cargc - 1)) {
422 /* We need to do some rejoining */
423 rejoinline(cargv[cmd->maxparams], cargc - (cmd->maxparams));
424 cargc = (cmd->maxparams) + 1;
425 }
426
427 if((cmd->handler)((void *)sender,cargc-1,&(cargv[1])) == CMD_USAGE)
428 controlhelp(sender, cmd);
429
430 break;
431 default:
432 if(oldhandler)
433 oldhandler(target, messagetype, args);
434 break;
435 }
436}
437
438void noperserv_reply(nick *np, char *format, ...) {
439 char buf[512];
440 va_list va;
441 no_autheduser *au = NOGetAuthedUser(np);
442
443 va_start(va, format);
444 vsnprintf(buf, sizeof(buf), format, va);
445 va_end(va);
446
447 if(au && !(NOGetNoticeLevel(au) & NL_NOTICES)) {
448 controlmessage(np, "%s", buf);
449 } else {
450 controlnotice(np, "%s", buf);
451 }
452}
453
454int noperserv_help(void *sender, int cargc, char **cargv) {
455 Command *cmd;
456 nick *np = (nick *)sender;
457
458 if(cargc < 1)
459 return CMD_USAGE;
460
461 cmd = findcommandintree(controlcmds, cargv[0], 1);
be515900
CP
462 if(!cmd || !noperserv_policy_command_permitted(cmd->level, np)) {
463 controlreply(np, "Unknown command or access denied.");
3e3692bf
CP
464 return CMD_ERROR;
465 }
466
467 controlhelp(np, cmd);
468 return CMD_OK;
469}
470
471void noperserv_wall(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
472 char buf[512];
473 va_list va;
3e3692bf 474 char *flags = printflags(noticelevel, no_noticeflags) + 1;
7078aa50
GB
475 int i;
476 authname *anp;
477 no_autheduser *au;
478 nick *np;
3e3692bf
CP
479
480 va_start(va, format);
481 vsnprintf(buf, sizeof(buf), format, va);
482 va_end(va);
483
484 Error("noperserv", ERR_INFO, "$%s$ %s", flags, buf);
485
7078aa50
GB
486 for (i=0;i<AUTHNAMEHASHSIZE;i++) {
487 for (anp=authnametable[i];anp;anp=anp->next) {
488 au = noperserv_get_autheduser(anp);
489 if(!au)
490 continue;
491 if((NOGetNoticeLevel(au) & noticelevel) && !(NOGetAuthLevel(au) & __NO_RELAY)) {
492 for(np=anp->nicks;np;np=np->nextbyauthname)
493 if(noperserv_policy_command_permitted(permissionlevel, np))
494 controlreply(np, "$%s$ %s", flags, buf);
495 }
3e3692bf
CP
496 }
497 }
498}