]> jfr.im git - irc/rqf/shadowircd.git/blame - src/parse.c
mkpasswd: Default to SHA512 instead of inherently insecure DES.
[irc/rqf/shadowircd.git] / src / parse.c
CommitLineData
212380e3 1/*
8ac75529 2 * charybdis: an advanced ircd.
212380e3 3 * parse.c: The message parser.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8ac75529 8 * Copyright (C) 2007 William Pitcock
212380e3 9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
212380e3 25 */
26
27#include "stdinc.h"
28#include "parse.h"
29#include "client.h"
30#include "channel.h"
31#include "common.h"
32#include "hash.h"
13ae2f4b 33#include "match.h"
212380e3 34#include "ircd.h"
35#include "numeric.h"
d3455e2c 36#include "logger.h"
212380e3 37#include "s_stats.h"
38#include "send.h"
39#include "msg.h"
40#include "s_conf.h"
212380e3 41#include "s_serv.h"
42#include "packet.h"
43
8ac75529
WP
44static struct Dictionary *cmd_dict = NULL;
45struct Dictionary *alias_dict = NULL;
46
212380e3 47/*
48 * NOTE: parse() should not be called recursively by other functions!
49 */
50static char *sender;
51
ac408af6 52/* parv[0] is not used, and parv[LAST] == NULL */
212380e3 53static char *para[MAXPARA + 2];
54
55static void cancel_clients(struct Client *, struct Client *, char *);
56static void remove_unknown(struct Client *, char *, char *);
57
58static void do_numeric(char[], struct Client *, struct Client *, int, char **);
59static void do_alias(struct alias_entry *, struct Client *, char *);
60
61static int handle_command(struct Message *, struct Client *, struct Client *, int, const char**);
62
212380e3 63static char buffer[1024];
64
212380e3 65/* turn a string into a parc/parv pair */
66
67
68static inline int
69string_to_array(char *string, char **parv)
70{
71 char *p, *buf = string;
72 int x = 1;
73
74 parv[x] = NULL;
75 while (*buf == ' ') /* skip leading spaces */
76 buf++;
77 if(*buf == '\0') /* ignore all-space args */
78 return x;
79
80 do
81 {
82 if(*buf == ':') /* Last parameter */
83 {
84 buf++;
85 parv[x++] = buf;
86 parv[x] = NULL;
87 return x;
88 }
89 else
90 {
91 parv[x++] = buf;
92 parv[x] = NULL;
93 if((p = strchr(buf, ' ')) != NULL)
94 {
95 *p++ = '\0';
96 buf = p;
97 }
98 else
99 return x;
100 }
101 while (*buf == ' ')
102 buf++;
103 if(*buf == '\0')
104 return x;
105 }
ac408af6 106 /* we can go upto parv[MAXPARA], as parv[0] is skipped */
212380e3 107 while (x < MAXPARA);
108
109 if(*p == ':')
110 p++;
111
112 parv[x++] = p;
113 parv[x] = NULL;
114 return x;
115}
116
117/* parse()
118 *
119 * given a raw buffer, parses it and generates parv, parc and sender
120 */
121void
122parse(struct Client *client_p, char *pbuffer, char *bufend)
123{
124 struct Client *from = client_p;
125 char *ch;
126 char *s;
127 char *end;
128 int i = 1;
129 char *numeric = 0;
130 struct Message *mptr;
131
132 s_assert(MyConnect(client_p));
6d4df0e3 133 s_assert(client_p->localClient->F != NULL);
212380e3 134 if(IsAnyDead(client_p))
135 return;
136
137 for (ch = pbuffer; *ch == ' '; ch++) /* skip spaces */
138 /* null statement */ ;
139
140 para[0] = from->name;
141
142 if(*ch == ':')
143 {
144 ch++;
145
146 /* point sender to the sender param */
147 sender = ch;
148
149 if((s = strchr(ch, ' ')))
150 {
151 *s = '\0';
152 s++;
153 ch = s;
154 }
155
156 if(*sender && IsServer(client_p))
157 {
f42e9ceb 158 from = find_client(sender);
212380e3 159
160 /* didnt find any matching client, issue a kill */
161 if(from == NULL)
162 {
83251205 163 ServerStats.is_unpf++;
212380e3 164 remove_unknown(client_p, sender, pbuffer);
165 return;
166 }
167
168 para[0] = from->name;
169
170 /* fake direction, hmm. */
171 if(from->from != client_p)
172 {
83251205 173 ServerStats.is_wrdi++;
212380e3 174 cancel_clients(client_p, from, pbuffer);
175 return;
176 }
177 }
178 while (*ch == ' ')
179 ch++;
180 }
181
182 if(*ch == '\0')
183 {
83251205 184 ServerStats.is_empt++;
212380e3 185 return;
186 }
187
188 /* at this point there must be some sort of command parameter */
189
190 /*
191 * Extract the command code from the packet. Point s to the end
192 * of the command code and calculate the length using pointer
193 * arithmetic. Note: only need length for numerics and *all*
194 * numerics must have parameters and thus a space after the command
195 * code. -avalon
196 */
197
198 /* EOB is 3 chars long but is not a numeric */
199
200 if(*(ch + 3) == ' ' && /* ok, lets see if its a possible numeric.. */
201 IsDigit(*ch) && IsDigit(*(ch + 1)) && IsDigit(*(ch + 2)))
202 {
203 mptr = NULL;
204 numeric = ch;
83251205 205 ServerStats.is_num++;
212380e3 206 s = ch + 3; /* I know this is ' ' from above if */
207 *s++ = '\0'; /* blow away the ' ', and point s to next part */
208 }
209 else
210 {
211 int ii = 0;
212
213 if((s = strchr(ch, ' ')))
214 *s++ = '\0';
215
90187f21 216 mptr = irc_dictionary_retrieve(cmd_dict, ch);
212380e3 217
218 /* no command or its encap only, error */
219 if(!mptr || !mptr->cmd)
220 {
221 /*
222 * Note: Give error message *only* to recognized
223 * persons. It's a nightmare situation to have
224 * two programs sending "Unknown command"'s or
225 * equivalent to each other at full blast....
226 * If it has got to person state, it at least
227 * seems to be well behaving. Perhaps this message
228 * should never be generated, though... --msa
229 * Hm, when is the buffer empty -- if a command
230 * code has been found ?? -Armin
231 */
232 if(pbuffer[0] != '\0')
233 {
234 if (IsPerson(client_p))
235 {
8ac75529 236 struct alias_entry *aptr = irc_dictionary_retrieve(alias_dict, ch);
212380e3 237 if (aptr != NULL)
238 {
239 do_alias(aptr, client_p, s);
240 return;
241 }
242 }
243 if(IsPerson(from))
244 {
245 sendto_one(from, form_str(ERR_UNKNOWNCOMMAND),
246 me.name, from->name, ch);
247 }
248 }
83251205 249 ServerStats.is_unco++;
212380e3 250 return;
251 }
252
253 ii = bufend - ((s) ? s : ch);
254 mptr->bytes += ii;
255 }
256
257 end = bufend - 1;
258
259 /* XXX this should be done before parse() is called */
260 if(*end == '\n')
261 *end-- = '\0';
262 if(*end == '\r')
263 *end = '\0';
264
265 if(s != NULL)
266 i = string_to_array(s, para);
267
268 if(mptr == NULL)
269 {
270 do_numeric(numeric, client_p, from, i, para);
271 return;
272 }
273
274 if(handle_command(mptr, client_p, from, i, /* XXX discards const!!! */ (const char **)para) < -1)
275 {
276 char *p;
277 for (p = pbuffer; p <= end; p += 8)
278 {
279 /* HACK HACK */
280 /* Its expected this nasty code can be removed
281 * or rewritten later if still needed.
282 */
283 if((unsigned long) (p + 8) > (unsigned long) end)
284 {
285 for (; p <= end; p++)
286 {
287 ilog(L_MAIN, "%02x |%c", p[0], p[0]);
288 }
289 }
290 else
291 ilog(L_MAIN,
292 "%02x %02x %02x %02x %02x %02x %02x %02x |%c%c%c%c%c%c%c%c",
293 p[0], p[1], p[2], p[3], p[4], p[5],
294 p[6], p[7], p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
295 }
296 }
297
298}
299
300/*
301 * handle_command
302 *
303 * inputs - pointer to message block
304 * - pointer to client
305 * - pointer to client message is from
306 * - count of number of args
307 * - pointer to argv[] array
308 * output - -1 if error from server
309 * side effects -
310 */
311static int
312handle_command(struct Message *mptr, struct Client *client_p,
313 struct Client *from, int i, const char** hpara)
314{
315 struct MessageEntry ehandler;
316 MessageHandler handler = 0;
317 char squitreason[80];
318
319 if(IsAnyDead(client_p))
320 return -1;
321
322 if(IsServer(client_p))
323 mptr->rcount++;
324
325 mptr->count++;
326
327 /* New patch to avoid server flooding from unregistered connects
328 - Pie-Man 07/27/2000 */
329
330 if(!IsRegistered(client_p))
331 {
332 /* if its from a possible server connection
333 * ignore it.. more than likely its a header thats sneaked through
334 */
335
336 if(IsAnyServer(client_p) && !(mptr->flags & MFLG_UNREG))
337 return (1);
338 }
339
340 ehandler = mptr->handlers[from->handler];
341 handler = ehandler.handler;
342
343 /* check right amount of params is passed... --is */
344 if(i < ehandler.min_para ||
345 (ehandler.min_para && EmptyString(hpara[ehandler.min_para - 1])))
346 {
347 if(!IsServer(client_p))
348 {
349 sendto_one(client_p, form_str(ERR_NEEDMOREPARAMS),
350 me.name,
351 EmptyString(client_p->name) ? "*" : client_p->name,
352 mptr->cmd);
353 if(MyClient(client_p))
354 return (1);
355 else
356 return (-1);
357 }
358
359 sendto_realops_snomask(SNO_GENERAL, L_ALL,
360 "Dropping server %s due to (invalid) command '%s'"
361 " with only %d arguments (expecting %d).",
362 client_p->name, mptr->cmd, i, ehandler.min_para);
363 ilog(L_SERVER,
364 "Insufficient parameters (%d < %d) for command '%s' from %s.",
365 i, ehandler.min_para, mptr->cmd, client_p->name);
5b0a5279 366 rb_snprintf(squitreason, sizeof squitreason,
212380e3 367 "Insufficient parameters (%d < %d) for command '%s'",
368 i, ehandler.min_para, mptr->cmd);
369 exit_client(client_p, client_p, client_p, squitreason);
370 return (-1);
371 }
372
373 (*handler) (client_p, from, i, hpara);
374 return (1);
375}
376
377void
378handle_encap(struct Client *client_p, struct Client *source_p,
379 const char *command, int parc, const char *parv[])
380{
381 struct Message *mptr;
382 struct MessageEntry ehandler;
383 MessageHandler handler = 0;
384
385 parv[0] = source_p->name;
386
8ac75529 387 mptr = irc_dictionary_retrieve(cmd_dict, command);
212380e3 388
389 if(mptr == NULL || mptr->cmd == NULL)
390 return;
391
392 ehandler = mptr->handlers[ENCAP_HANDLER];
393 handler = ehandler.handler;
394
395 if(parc < ehandler.min_para ||
396 (ehandler.min_para && EmptyString(parv[ehandler.min_para - 1])))
397 return;
398
399 (*handler) (client_p, source_p, parc, parv);
400}
401
402/*
403 * clear_hash_parse()
404 *
405 * inputs -
406 * output - NONE
407 * side effects - MUST MUST be called at startup ONCE before
408 * any other keyword hash routine is used.
409 *
410 */
411void
412clear_hash_parse()
413{
8ac75529 414 cmd_dict = irc_dictionary_create(strcasecmp);
212380e3 415}
416
417/* mod_add_cmd
418 *
419 * inputs - command name
420 * - pointer to struct Message
421 * output - none
422 * side effects - load this one command name
423 * msg->count msg->bytes is modified in place, in
424 * modules address space. Might not want to do that...
425 */
426void
427mod_add_cmd(struct Message *msg)
428{
212380e3 429 s_assert(msg != NULL);
430 if(msg == NULL)
431 return;
432
8ac75529
WP
433 if (irc_dictionary_find(cmd_dict, msg->cmd) != NULL)
434 return;
212380e3 435
436 msg->count = 0;
437 msg->rcount = 0;
438 msg->bytes = 0;
439
8ac75529 440 irc_dictionary_add(cmd_dict, msg->cmd, msg);
212380e3 441}
442
443/* mod_del_cmd
444 *
445 * inputs - command name
446 * output - none
447 * side effects - unload this one command name
448 */
449void
450mod_del_cmd(struct Message *msg)
451{
212380e3 452 s_assert(msg != NULL);
453 if(msg == NULL)
454 return;
455
8ac75529 456 irc_dictionary_delete(cmd_dict, msg->cmd);
212380e3 457}
458
459/*
460 * report_messages
461 *
462 * inputs - pointer to client to report to
463 * output - NONE
464 * side effects - NONE
465 */
466void
467report_messages(struct Client *source_p)
468{
8ac75529
WP
469 struct DictionaryIter iter;
470 struct Message *msg;
471 struct alias_entry *amsg;
212380e3 472
90187f21 473 DICTIONARY_FOREACH(msg, &iter, cmd_dict)
212380e3 474 {
8ac75529
WP
475 s_assert(msg->cmd != NULL);
476 sendto_one_numeric(source_p, RPL_STATSCOMMANDS,
477 form_str(RPL_STATSCOMMANDS),
478 msg->cmd, msg->count,
479 msg->bytes, msg->rcount);
480 }
212380e3 481
90187f21 482 DICTIONARY_FOREACH(amsg, &iter, alias_dict)
8ac75529
WP
483 {
484 s_assert(amsg->name != NULL);
485 sendto_one_numeric(source_p, RPL_STATSCOMMANDS,
486 form_str(RPL_STATSCOMMANDS),
487 amsg->name, amsg->hits, 0, 0);
212380e3 488 }
489}
490
491/* cancel_clients()
492 *
493 * inputs - client who sent us the message, client with fake
494 * direction, command
495 * outputs - a given warning about the fake direction
496 * side effects -
497 */
498static void
499cancel_clients(struct Client *client_p, struct Client *source_p, char *cmd)
500{
501 /* ok, fake prefix happens naturally during a burst on a nick
502 * collision with TS5, we cant kill them because one client has to
503 * survive, so we just send an error.
504 */
505 if(IsServer(source_p) || IsMe(source_p))
506 {
507 sendto_realops_snomask(SNO_DEBUG, L_ALL,
508 "Message for %s[%s] from %s",
509 source_p->name, source_p->from->name,
715b28fe 510 client_p->name);
212380e3 511 }
512 else
513 {
514 sendto_realops_snomask(SNO_DEBUG, L_ALL,
515 "Message for %s[%s@%s!%s] from %s (TS, ignored)",
516 source_p->name,
517 source_p->username,
518 source_p->host,
519 source_p->from->name,
715b28fe 520 client_p->name);
212380e3 521 }
522}
523
524/* remove_unknown()
525 *
526 * inputs - client who gave us message, supposed sender, buffer
527 * output -
528 * side effects - kills issued for clients, squits for servers
529 */
530static void
531remove_unknown(struct Client *client_p, char *lsender, char *lbuffer)
532{
533 int slen = strlen(lsender);
8d03179e
JT
534 char sid[4];
535 struct Client *server;
212380e3 536
3fde0c14 537 /* meepfoo is a nickname (ignore)
212380e3 538 * #XXXXXXXX is a UID (KILL)
539 * #XX is a SID (SQUIT)
540 * meep.foo is a server (SQUIT)
541 */
542 if((IsDigit(lsender[0]) && slen == 3) ||
543 (strchr(lsender, '.') != NULL))
544 {
545 sendto_realops_snomask(SNO_DEBUG, L_ALL,
546 "Unknown prefix (%s) from %s, Squitting %s",
715b28fe 547 lbuffer, client_p->name, lsender);
212380e3 548
549 sendto_one(client_p,
550 ":%s SQUIT %s :(Unknown prefix (%s) from %s)",
551 get_id(&me, client_p), lsender,
552 lbuffer, client_p->name);
553 }
8d03179e
JT
554 else if(!IsDigit(lsender[0]))
555 ;
556 else if(slen != 9)
557 sendto_realops_snomask(SNO_DEBUG, L_ALL,
558 "Invalid prefix (%s) from %s",
559 lbuffer, client_p->name);
560 else
561 {
562 memcpy(sid, lsender, 3);
563 sid[3] = '\0';
564 server = find_server(NULL, sid);
565 if (server != NULL && server->from == client_p)
566 sendto_one(client_p, ":%s KILL %s :%s (Unknown Client)",
567 get_id(&me, client_p), lsender, me.name);
568 }
212380e3 569}
570
571
572
573/*
574 *
575 * parc number of arguments ('sender' counted as one!)
212380e3 576 * parv[1]..parv[parc-1]
577 * pointers to additional parameters, this is a NULL
578 * terminated list (parv[parc] == NULL).
579 *
580 * *WARNING*
581 * Numerics are mostly error reports. If there is something
582 * wrong with the message, just *DROP* it! Don't even think of
583 * sending back a neat error message -- big danger of creating
584 * a ping pong error message...
585 */
586static void
587do_numeric(char numeric[], struct Client *client_p, struct Client *source_p, int parc, char *parv[])
588{
589 struct Client *target_p;
590 struct Channel *chptr;
591
592 if(parc < 2 || !IsServer(source_p))
593 return;
594
595 /* Remap low number numerics. */
596 if(numeric[0] == '0')
597 numeric[0] = '1';
598
599 /*
600 * Prepare the parameter portion of the message into 'buffer'.
601 * (Because the buffer is twice as large as the message buffer
602 * for the socket, no overflow can occur here... ...on current
603 * assumptions--bets are off, if these are changed --msa)
604 * Note: if buffer is non-empty, it will begin with SPACE.
605 */
606 if(parc > 1)
607 {
608 char *t = buffer; /* Current position within the buffer */
609 int i;
610 int tl; /* current length of presently being built string in t */
611 for (i = 2; i < (parc - 1); i++)
612 {
38e6acdd 613 tl = rb_sprintf(t, " %s", parv[i]);
212380e3 614 t += tl;
615 }
38e6acdd 616 rb_sprintf(t, " :%s", parv[parc - 1]);
212380e3 617 }
618
619 if((target_p = find_client(parv[1])) != NULL)
620 {
621 if(IsMe(target_p))
622 {
623 /*
624 * We shouldn't get numerics sent to us,
625 * any numerics we do get indicate a bug somewhere..
626 */
627 /* ugh. this is here because of nick collisions. when two servers
628 * relink, they burst each other their nicks, then perform collides.
629 * if there is a nick collision, BOTH servers will kill their own
630 * nicks, and BOTH will kill the other servers nick, which wont exist,
631 * because it will have been already killed by the local server.
632 *
633 * unfortunately, as we cant guarantee other servers will do the
634 * "right thing" on a nick collision, we have to keep both kills.
635 * ergo we need to ignore ERR_NOSUCHNICK. --fl_
636 */
637 /* quick comment. This _was_ tried. i.e. assume the other servers
638 * will do the "right thing" and kill a nick that is colliding.
639 * unfortunately, it did not work. --Dianora
640 */
641 /* note, now we send PING on server connect, we can
642 * also get ERR_NOSUCHSERVER..
643 */
644 if(atoi(numeric) != ERR_NOSUCHNICK &&
645 atoi(numeric) != ERR_NOSUCHSERVER)
646 sendto_realops_snomask(SNO_GENERAL, L_ADMIN,
647 "*** %s(via %s) sent a %s numeric to me: %s",
648 source_p->name,
649 client_p->name, numeric, buffer);
650 return;
651 }
652 else if(target_p->from == client_p)
653 {
654 /* This message changed direction (nick collision?)
655 * ignore it.
656 */
657 return;
658 }
659
660 /* csircd will send out unknown umode flag for +a (admin), drop it here. */
661 if((atoi(numeric) == ERR_UMODEUNKNOWNFLAG) && MyClient(target_p))
662 return;
663
664 /* Fake it for server hiding, if its our client */
665 sendto_one(target_p, ":%s %s %s%s",
666 get_id(source_p, target_p), numeric,
667 get_id(target_p, target_p), buffer);
668 return;
669 }
670 else if((chptr = find_channel(parv[1])) != NULL)
d23bc305
JT
671 sendto_channel_flags(client_p, ALL_MEMBERS, source_p, chptr,
672 "%s %s%s",
673 numeric, chptr->chname, buffer);
212380e3 674}
675
676static void do_alias(struct alias_entry *aptr, struct Client *source_p, char *text)
677{
678 char *p;
679 struct Client *target_p;
680
681 if (!IsFloodDone(source_p) && source_p->localClient->receiveM > 20)
682 flood_endgrace(source_p);
683
684 p = strchr(aptr->target, '@');
685 if (p != NULL)
686 {
687 /* user@server */
688 target_p = find_server(NULL, p + 1);
689 if (target_p != NULL && IsMe(target_p))
690 target_p = NULL;
691 }
692 else
693 {
694 /* nick, must be +S */
695 target_p = find_named_person(aptr->target);
696 if (target_p != NULL && !IsService(target_p))
697 target_p = NULL;
698 }
699
700 if (target_p == NULL)
701 {
702 sendto_one_numeric(source_p, ERR_SERVICESDOWN, form_str(ERR_SERVICESDOWN), aptr->target);
703 return;
704 }
705
706 if (text != NULL && *text == ':')
707 text++;
708 if (text == NULL || *text == '\0')
709 {
710 sendto_one(source_p, form_str(ERR_NOTEXTTOSEND), me.name, source_p->name);
711 return;
712 }
713
714 /* increment the hitcounter on this alias */
715 aptr->hits++;
716
717 sendto_one(target_p, ":%s PRIVMSG %s :%s",
718 get_id(source_p, target_p),
719 p != NULL ? aptr->target : get_id(target_p, target_p),
720 text);
721}
722
723int
724m_not_oper(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
725{
726 sendto_one_numeric(source_p, ERR_NOPRIVILEGES, form_str(ERR_NOPRIVILEGES));
727 return 0;
728}
729
730int
731m_unregistered(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
732{
733 /* bit of a hack.
734 * I don't =really= want to waste a bit in a flag
735 * number_of_nick_changes is only really valid after the client
736 * is fully registered..
737 */
738 if(client_p->localClient->number_of_nick_changes == 0)
739 {
740 sendto_one(client_p, form_str(ERR_NOTREGISTERED), me.name);
741 client_p->localClient->number_of_nick_changes++;
742 }
743
744 return 0;
745}
746
747int
748m_registered(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
749{
750 sendto_one(client_p, form_str(ERR_ALREADYREGISTRED), me.name, source_p->name);
751 return 0;
752}
753
754int
755m_ignore(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
756{
757 return 0;
758}