]> jfr.im git - irc/quakenet/newserv.git/blob - control/control.c
Fix a buffer overflow in newsearch.
[irc/quakenet/newserv.git] / control / control.c
1 /*
2 * This is the first client module for newserv :)
3 *
4 * A very simple bot which should give people some ideas for how to
5 * implement stuff on this thing
6 */
7
8 #include "../irc/irc_config.h"
9 #include "../parser/parser.h"
10 #include "../localuser/localuser.h"
11 #include "../localuser/localuserchannel.h"
12 #include "../nick/nick.h"
13 #include "../lib/sstring.h"
14 #include "../core/config.h"
15 #include "../irc/irc.h"
16 #include "../lib/splitline.h"
17 #include "../channel/channel.h"
18 #include "../lib/flags.h"
19 #include "../core/schedule.h"
20 #include "../lib/base64.h"
21 #include "../core/modules.h"
22 #include "../lib/version.h"
23 #include "control.h"
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdarg.h>
28
29 MODULE_VERSION("");
30
31 nick *hooknick;
32
33 nick *mynick;
34
35 CommandTree *controlcmds;
36 ControlMsg controlreply;
37 ControlWall controlwall;
38
39 void handlemessages(nick *target, int messagetype, void **args);
40 int controlstatus(void *sender, int cargc, char **cargv);
41 void controlconnect(void *arg);
42 int controlwhois(void *sender, int cargc, char **cargv);
43 int controlchannel(void *sender, int cargc, char **cargv);
44 int relink(void *sender, int cargc, char **cargv);
45 int die(void *sender, int cargc, char **cargv);
46 int controlinsmod(void *sender, int cargc, char **cargv);
47 int controllsmod(void *sender, int cargc, char **cargv);
48 int controlrehash(void *sender, int cargc, char **cargv);
49 int controlreload(void *sender, int cargc, char **cargv);
50 int controlhelpcmd(void *sender, int cargc, char **cargv);
51 void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...);
52
53 void _init() {
54 controlcmds=newcommandtree();
55 controlreply=&controlmessage;
56 controlwall=&controlnoticeopers;
57
58 registercontrolhelpcmd("status",NO_DEVELOPER,1,&controlstatus,"Usage: status ?level?\nDisplays status information, increasing level gives more verbose information.");
59 registercontrolhelpcmd("whois",NO_OPERED,1,&controlwhois,"Usage: whois <nickname|#numeric>\nDisplays lots of information about the specified nickname or numeric.");
60 registercontrolhelpcmd("channel",NO_OPER,1,&controlchannel,"Usage: channel <#channel>\nDisplays channel information.");
61 registercontrolhelpcmd("relink",NO_DEVELOPER,1,&relink,"Usage: relink\nRelinks service to the network.");
62 registercontrolhelpcmd("die",NO_DEVELOPER,1,&die,"Usage: die <reason>\nTerminates the service.");
63 registercontrolhelpcmd("insmod",NO_DEVELOPER,1,&controlinsmod,"Usage: insmod <module>\nAdds a module to the running instance.");
64 registercontrolhelpcmd("rmmod",NO_DEVELOPER,1,&controlrmmod,"Usage: rmmod <module>\nRemoves a module from the running instance.");
65 registercontrolhelpcmd("lsmod",NO_DEVELOPER,0,&controllsmod,"Usage: lsmod\nLists currently running modules.");
66 registercontrolhelpcmd("rehash",NO_DEVELOPER,1,&controlrehash,"Usage: rehash\nReloads configuration file.");
67 registercontrolhelpcmd("showcommands",NO_ACCOUNT,0,&controlshowcommands,"Usage: showcommands\nShows all registered commands.");
68 registercontrolhelpcmd("reload",NO_DEVELOPER,1,&controlreload,"Usage: reload <module>\nReloads specified module.");
69 registercontrolhelpcmd("help",NO_ANYONE,1,&controlhelpcmd,"Usage: help <command>\nShows help for specified command.");
70
71 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
72 }
73
74 void _fini() {
75 deleteallschedules(&controlconnect);
76 if (mynick) {
77 deregisterlocaluser(mynick,"Leaving");
78 }
79
80 deregistercontrolcmd("status",&controlstatus);
81 deregistercontrolcmd("whois",&controlwhois);
82 deregistercontrolcmd("channel",&controlchannel);
83 deregistercontrolcmd("relink",&relink);
84 deregistercontrolcmd("die",&die);
85 deregistercontrolcmd("insmod",&controlinsmod);
86 deregistercontrolcmd("rmmod",&controlrmmod);
87 deregistercontrolcmd("lsmod",&controllsmod);
88 deregistercontrolcmd("rehash",&controlrehash);
89 deregistercontrolcmd("showcommands",&controlshowcommands);
90 deregistercontrolcmd("reload",&controlreload);
91 deregistercontrolcmd("help",&controlhelpcmd);
92
93 destroycommandtree(controlcmds);
94 }
95
96 void registercontrolhelpcmd(const char *name, int level, int maxparams, CommandHandler handler, char *help) {
97 addcommandhelptotree(controlcmds,name,level,maxparams,handler,help);
98 }
99
100 int deregistercontrolcmd(const char *name, CommandHandler handler) {
101 return deletecommandfromtree(controlcmds, name, handler);
102 }
103
104 void controlconnect(void *arg) {
105 sstring *cnick, *myident, *myhost, *myrealname, *myauthname;
106 channel *cp;
107
108 cnick=getcopyconfigitem("control","nick","C",NICKLEN);
109 myident=getcopyconfigitem("control","ident","control",NICKLEN);
110 myhost=getcopyconfigitem("control","hostname",myserver->content,HOSTLEN);
111 myrealname=getcopyconfigitem("control","realname","NewServ Control Service",REALLEN);
112 myauthname=getcopyconfigitem("control","authname","C",ACCOUNTLEN);
113
114 mynick=registerlocaluser(cnick->content,myident->content,myhost->content,myrealname->content,myauthname->content,UMODE_SERVICE|UMODE_DEAF|UMODE_OPER|UMODE_ACCOUNT|UMODE_INV,&handlemessages);
115 triggerhook(HOOK_CONTROL_REGISTERED, mynick);
116 cp=findchannel("#twilightzone");
117 if (!cp) {
118 localcreatechannel(mynick,"#twilightzone");
119 } else {
120 localjoinchannel(mynick,cp);
121 localgetops(mynick,cp);
122 }
123
124 freesstring(cnick);
125 freesstring(myident);
126 freesstring(myhost);
127 freesstring(myrealname);
128 freesstring(myauthname);
129 }
130
131 void handlestats(int hooknum, void *arg) {
132 controlreply(hooknick,"%s",(char *)arg);
133 }
134
135 int controlstatus(void *sender, int cargc, char **cargv) {
136 unsigned long level=5;
137
138 hooknick=(nick *)sender;
139
140 if (cargc>0) {
141 level=strtoul(cargv[0],NULL,10);
142 }
143
144 registerhook(HOOK_CORE_STATSREPLY,&handlestats);
145 triggerhook(HOOK_CORE_STATSREQUEST,(void *)level);
146 deregisterhook(HOOK_CORE_STATSREPLY,&handlestats);
147 return CMD_OK;
148 }
149
150 int controlrehash(void *sender, int cargc, char **cargv) {
151 nick *np=(nick *)sender;
152
153 controlreply(np,"Rehashing the config file.");
154
155 rehashconfig();
156 triggerhook(HOOK_CORE_REHASH,(void *)0);
157 return CMD_OK;
158 }
159
160 void handlewhois(int hooknum, void *arg) {
161 controlreply(hooknick,"%s",(char *)arg);
162 }
163
164 int controlwhois(void *sender, int cargc, char **cargv) {
165 nick *target;
166 channel **channels;
167 char buf[BUFSIZE];
168 int i;
169
170 if (cargc<1)
171 return CMD_USAGE;
172
173 if (cargv[0][0]=='#') {
174 if (!(target=getnickbynumericstr(cargv[0]+1))) {
175 controlreply(sender,"Sorry, couldn't find numeric %s",cargv[0]+1);
176 return CMD_ERROR;
177 }
178 } else {
179 if ((target=getnickbynick(cargv[0]))==NULL) {
180 controlreply((nick *)sender,"Sorry, couldn't find that user");
181 return CMD_ERROR;
182 }
183 }
184
185 controlreply((nick *)sender,"Nick : %s",target->nick);
186 controlreply((nick *)sender,"Numeric : %s",longtonumeric(target->numeric,5));
187 controlreply((nick *)sender,"User@Host : %s@%s (%d user(s) on this host)",target->ident,target->host->name->content,target->host->clonecount);
188 if (IsSetHost(target)) {
189 if (target->shident) {
190 controlreply((nick *)sender,"Fakehost : %s@%s",target->shident->content, target->sethost->content);
191 } else {
192 controlreply((nick *)sender,"Fakehost : %s",target->sethost->content);
193 }
194 }
195 controlreply((nick *)sender,"Timestamp : %lu",target->timestamp);
196 controlreply((nick *)sender,"IP address: %s",IPtostr(target->p_ipaddr));
197 controlreply((nick *)sender,"Realname : %s (%d user(s) have this realname)",target->realname->name->content,target->realname->usercount);
198 if (target->umodes) {
199 controlreply((nick *)sender,"Umode(s) : %s",printflags(target->umodes,umodeflags));
200 }
201 if (IsAccount(target)) {
202 controlreply((nick *)sender,"Account : %s",target->authname);
203 if (target->accountts)
204 controlreply((nick *)sender,"AccountTS : %ld",target->accountts);
205 }
206
207 hooknick=(nick *)sender;
208 registerhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
209 triggerhook(HOOK_CONTROL_WHOISREQUEST,target);
210 deregisterhook(HOOK_CONTROL_WHOISREPLY,&handlewhois);
211
212 if (target->channels->cursi==0) {
213 controlreply((nick *)sender,"Channels : none");
214 } else if (target->channels->cursi>50) {
215 controlreply((nick *)sender,"Channels : - (total: %d)",target->channels->cursi);
216 } else {
217 buf[0]='\0';
218 channels=(channel **)target->channels->content;
219 for (i=0;i<=target->channels->cursi;i++) {
220 if (!((i==target->channels->cursi) || ((70-strlen(buf))<channels[i]->index->name->length && strlen(buf)>0))) {
221 strcat(buf,channels[i]->index->name->content);
222 strcat(buf," ");
223 } else {
224 if (strlen(buf)==0) {
225 break;
226 } else {
227 controlreply((nick *)sender,"Channels : %s",buf);
228 buf[0]='\0';
229 i--;
230 }
231 }
232 }
233 }
234
235 return CMD_OK;
236 }
237
238 int controlinsmod(void *sender, int cargc, char **cargv) {
239 if (cargc<1)
240 return CMD_USAGE;
241
242 switch(insmod(cargv[0])) {
243 case -1:
244 controlreply((nick *)sender,"Unable to load module %s",cargv[0]);
245 return CMD_ERROR;
246
247 case 1:
248 controlreply((nick *)sender,"Module %s already loaded, or name not valid",cargv[0]);
249 return CMD_ERROR;
250
251 case 0:
252 controlreply((nick *)sender,"Module %s loaded.",cargv[0]);
253 return CMD_OK;
254
255 default:
256 controlreply((nick *)sender,"An unknown error occured.");
257 return CMD_ERROR;
258 }
259 }
260
261 int controlrmmod(void *sender, int cargc, char **cargv) {
262 if (cargc<1)
263 return CMD_USAGE;
264
265 switch(rmmod(cargv[0])) {
266 case 1:
267 controlreply((nick *)sender,"Module %s is not loaded.",cargv[0]);
268 return CMD_ERROR;
269
270 case 0:
271 controlreply((nick *)sender,"Module %s unloaded.",cargv[0]);
272 return CMD_OK;
273
274 default:
275 controlreply((nick *)sender,"An unknown error occured.");
276 return CMD_ERROR;
277 }
278 }
279
280 int controllsmod(void *sender, int cargc, char **cargv) {
281 int i=0;
282 char *ptr;
283
284 if (cargc < 1) { /* list all loaded modules */
285 ptr = lsmod(i);
286 controlreply((nick *)sender,"Module");
287 while (ptr != NULL) {
288 const char *ver = lsmodver(i);
289 controlreply((nick *)sender,"%s%s%s%s", ptr, ver?" (":"", ver?ver:"", ver?")":"");
290 ptr = lsmod(++i);
291 }
292 } else {
293 ptr = lsmod(getindex(cargv[0]));
294 controlreply((nick *)sender,"Module \"%s\" %s", cargv[0], (ptr ? "is loaded." : "is NOT loaded."));
295 }
296 return CMD_OK;
297 }
298
299 int controlreload(void *sender, int cargc, char **cargv) {
300 if (cargc<1)
301 return CMD_USAGE;
302
303 controlreply((nick *)sender,"Imma gonna try and reload %s",cargv[0]);
304
305 safereload(cargv[0]);
306
307 return CMD_OK;
308 }
309
310 int relink(void *sender, int cargc, char **cargv) {
311 if (cargc<1) {
312 controlreply((nick *)sender,"You must give a reason.");
313 return CMD_USAGE;
314 }
315
316 irc_send("%s SQ %s 0 :%s",mynumeric->content,myserver->content,cargv[0]);
317 irc_disconnected();
318
319 return CMD_OK;
320 }
321
322 int die(void *sender, int cargc, char **cargv) {
323 if (cargc<1) {
324 controlreply((nick *)sender,"You must give a reason.");
325 return CMD_USAGE;
326 }
327
328 controlwall(0,0,"DIE from %s: %s",((nick *)sender)->nick, cargv[0]);
329
330 newserv_shutdown_pending=1;
331
332 return CMD_OK;
333 }
334
335 int controlchannel(void *sender, int cargc, char **cargv) {
336 channel *cp;
337 nick *np;
338 chanban *cbp;
339 char buf[BUFSIZE];
340 char buf2[12];
341 int i,j;
342 char timebuf[30];
343
344 if (cargc<1)
345 return CMD_USAGE;
346
347 if ((cp=findchannel(cargv[0]))==NULL) {
348 controlreply((nick *)sender,"Couldn't find channel: %s",cargv[0]);
349 return CMD_ERROR;
350 }
351
352 if (IsLimit(cp)) {
353 sprintf(buf2,"%d",cp->limit);
354 }
355
356 controlreply((nick *)sender,"Channel : %s",cp->index->name->content);
357 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(cp->timestamp)));
358 controlreply((nick *)sender,"C-time : %ld [%s]",cp->timestamp,timebuf);
359 if (cp->topic) {
360 controlreply((nick *)sender,"Topic : %s",cp->topic->content);
361 strftime(timebuf, 30, "%d/%m/%y %H:%M", localtime(&(cp->topictime)));
362 controlreply((nick *)sender,"T-time : %ld [%s]",cp->topictime,timebuf);
363 }
364 controlreply((nick *)sender,"Mode(s) : %s %s%s%s",printflags(cp->flags,cmodeflags),IsLimit(cp)?buf2:"",
365 IsLimit(cp)?" ":"",IsKey(cp)?cp->key->content:"");
366 controlreply((nick *)sender,"Users : %d (hash size %d, utilisation %.1f%%); %d unique hosts",
367 cp->users->totalusers,cp->users->hashsize,((float)(100*cp->users->totalusers)/cp->users->hashsize),
368 countuniquehosts(cp));
369 i=0;
370 memset(buf,' ',90);
371 buf[72]='\0';
372 for (j=0;j<=cp->users->hashsize;j++) {
373 if (i==4 || j==cp->users->hashsize) {
374 if(i>0) {
375 controlreply((nick *)sender,"Users : %s",buf);
376 }
377 i=0;
378 memset(buf,' ',72);
379 if (j==cp->users->hashsize)
380 break;
381 }
382 if (cp->users->content[j]!=nouser) {
383 np=getnickbynumeric(cp->users->content[j]);
384 sprintf(&buf[i*18],"%c%c%-15s ",cp->users->content[j]&CUMODE_VOICE?'+':' ',
385 cp->users->content[j]&CUMODE_OP?'@':' ', np?np->nick:"!BUG-NONICK!");
386 i++;
387 if (i<4)
388 buf[i*18]=' ';
389 }
390 }
391
392
393 for (cbp=cp->bans;cbp;cbp=cbp->next) {
394 controlreply((nick *)sender,"Ban : %s",bantostringdebug(cbp));
395 }
396 return CMD_OK;
397 }
398
399 int controlshowcommands(void *sender, int cargc, char **cargv) {
400 nick *np=(nick *)sender;
401 Command *cmdlist[100];
402 int i,n;
403
404 n=getcommandlist(controlcmds,cmdlist,100);
405
406 controlreply(np,"The following commands are registered at present:");
407
408 for(i=0;i<n;i++) {
409 controlreply(np,"%s",cmdlist[i]->command->content);
410 }
411
412 controlreply(np,"End of list.");
413 return CMD_OK;
414 }
415
416 void handlemessages(nick *target, int messagetype, void **args) {
417 Command *cmd;
418 char *cargv[50];
419 int cargc;
420 nick *sender;
421
422 switch(messagetype) {
423 case LU_PRIVMSG:
424 case LU_SECUREMSG:
425 /* If it's a message, first arg is nick and second is message */
426 sender=(nick *)args[0];
427
428 Error("control",ERR_INFO,"From: %s!%s@%s: %s",sender->nick,sender->ident,sender->host->name->content, (char *)args[1]);
429
430 /* Split the line into params */
431 cargc=splitline((char *)args[1],cargv,50,0);
432
433 if (!cargc) {
434 /* Blank line */
435 return;
436 }
437
438 cmd=findcommandintree(controlcmds,cargv[0],1);
439 if (cmd==NULL) {
440 controlreply(sender,"Unknown command.");
441 return;
442 }
443
444 if (cmd->level>0 && !IsOper(sender)) {
445 controlreply(sender,"You need to be opered to use this command.");
446 return;
447 }
448
449 /* If we were doing "authed user tracking" here we'd put a check in for authlevel */
450
451 /* Check the maxargs */
452 if (cmd->maxparams<(cargc-1)) {
453 /* We need to do some rejoining */
454 rejoinline(cargv[cmd->maxparams],cargc-(cmd->maxparams));
455 cargc=(cmd->maxparams)+1;
456 }
457
458 if((cmd->handler)((void *)sender,cargc-1,&(cargv[1])) == CMD_USAGE)
459 controlhelp(sender, cmd);
460 break;
461
462 case LU_KILLED:
463 /* someone killed me? Bastards */
464 scheduleoneshot(time(NULL)+1,&controlconnect,NULL);
465 mynick=NULL;
466 break;
467
468 default:
469 break;
470 }
471 }
472
473 void controlmessage(nick *target, char *message, ... ) {
474 char buf[512];
475 va_list va;
476
477 if (mynick==NULL) {
478 return;
479 }
480
481 va_start(va,message);
482 vsnprintf(buf,512,message,va);
483 va_end(va);
484
485 sendmessagetouser(mynick,target,"%s",buf);
486 }
487
488 void controlchanmsg(channel *cp, char *message, ...) {
489 char buf[512];
490 va_list va;
491
492 if (mynick==NULL) {
493 return;
494 }
495
496 va_start(va,message);
497 vsnprintf(buf,512,message,va);
498 va_end(va);
499
500 sendmessagetochannel(mynick,cp,"%s",buf);
501 }
502
503 void controlnotice(nick *target, char *message, ... ) {
504 char buf[512];
505 va_list va;
506
507 if (mynick==NULL) {
508 return;
509 }
510
511 va_start(va,message);
512 vsnprintf(buf,512,message,va);
513 va_end(va);
514
515 sendnoticetouser(mynick,target,"%s",buf);
516 }
517
518 void controlspecialrmmod(void *arg) {
519 struct specialsched *a = (struct specialsched *)arg;
520
521 a->schedule = NULL;
522 sstring *froo = a->modulename;
523
524 rmmod(froo->content);
525 freesstring(froo);
526 }
527
528 void controlspecialreloadmod(void *arg) {
529 struct specialsched *a = (struct specialsched *)arg;
530
531 a->schedule = NULL;
532 sstring *froo = a->modulename;
533
534 safereload(froo->content);
535 freesstring(froo);
536 }
537
538 void controlhelp(nick *np, Command *cmd) {
539 char *cp = cmd->help, *sp = cp;
540 if(!cp || !*cp) {
541 controlreply(np, "Sorry, no help for this command.");
542 } else {
543 int finished = 0;
544 for(;;cp++) {
545 if(*cp == '\0' || *cp == '\n') {
546 if(*cp == '\0') {
547 finished = 1;
548 } else {
549 *cp = '\0';
550 }
551
552 if(sp != cp)
553 controlreply(np, "%s", sp);
554
555 if(finished)
556 break;
557
558 *cp = '\n';
559
560 sp = cp + 1;
561 }
562 }
563 }
564 }
565
566 int controlhelpcmd(void *sender, int cargc, char **cargv) {
567 Command *cmd;
568 nick *np = (nick *)sender;
569
570 if (cargc<1)
571 return CMD_USAGE;
572
573 cmd=findcommandintree(controlcmds,cargv[0],1);
574 if (cmd==NULL) {
575 controlreply(np,"Unknown command.");
576 return CMD_ERROR;
577 }
578
579 controlhelp(np, cmd);
580 return CMD_OK;
581 }
582
583 void controlnoticeopers(flag_t permissionlevel, flag_t noticelevel, char *format, ...) {
584 int i;
585 nick *np;
586 char broadcast[512];
587 va_list va;
588
589 va_start(va, format);
590 vsnprintf(broadcast, sizeof(broadcast), format, va);
591 va_end(va);
592
593 for(i=0;i<NICKHASHSIZE;i++)
594 for(np=nicktable[i];np;np=np->next)
595 if (IsOper(np))
596 controlnotice(np, "%s", broadcast);
597 }