]>
jfr.im git - solanum.git/blob - ircd/parse.c
bef6be15e37581d75344b74648a11f23ee27d312
2 * Solanum: a slightly advanced ircd
3 * parse.c: The message parser.
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
8 * Copyright (C) 2007-2016 Ariadne Conill <ariadne@dereferenced.org>
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.
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.
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
44 rb_dictionary
*cmd_dict
= NULL
;
45 rb_dictionary
*alias_dict
= NULL
;
47 static void cancel_clients(struct Client
*, struct Client
*);
48 static void remove_unknown(struct Client
*, const char *, char *);
50 static void do_numeric(int, struct Client
*, struct Client
*, int, const char **);
52 static int handle_command(struct Message
*, struct MsgBuf
*, struct Client
*, struct Client
*);
54 static char buffer
[1024];
56 /* turn a string into a parc/parv pair */
58 char *reconstruct_parv(int parc
, const char *parv
[])
60 static char tmpbuf
[BUFSIZE
]; int i
;
62 rb_strlcpy(tmpbuf
, parv
[0], BUFSIZE
);
63 for (i
= 1; i
< parc
; i
++)
65 rb_strlcat(tmpbuf
, " ", BUFSIZE
);
66 rb_strlcat(tmpbuf
, parv
[i
], BUFSIZE
);
73 * given a raw buffer, parses it and generates parv and parc
76 parse(struct Client
*client_p
, char *pbuffer
, char *bufend
)
78 struct Client
*from
= client_p
;
85 s_assert(MyConnect(client_p
) &&
86 (client_p
->localClient
->F
!= NULL
||
87 client_p
->localClient
->localflags
& LFLAGS_FAKE
));
88 if(IsAnyDead(client_p
))
93 /* XXX this should be done before parse() is called */
99 res
= msgbuf_parse(&msgbuf
, pbuffer
);
102 ServerStats
.is_empt
++;
106 if (msgbuf
.origin
!= NULL
&& IsServer(client_p
))
108 from
= find_client(msgbuf
.origin
);
110 /* didnt find any matching client, issue a kill */
113 ServerStats
.is_unpf
++;
114 remove_unknown(client_p
, msgbuf
.origin
, pbuffer
);
118 /* fake direction, hmm. */
119 if(from
->from
!= client_p
)
121 ServerStats
.is_wrdi
++;
122 cancel_clients(client_p
, from
);
127 if(IsDigit(*msgbuf
.cmd
) && IsDigit(*(msgbuf
.cmd
+ 1)) && IsDigit(*(msgbuf
.cmd
+ 2)))
130 numeric
= atoi(msgbuf
.cmd
);
131 ServerStats
.is_num
++;
135 mptr
= rb_dictionary_retrieve(cmd_dict
, msgbuf
.cmd
);
137 /* no command or its encap only, error */
138 if(!mptr
|| !mptr
->cmd
)
142 sendto_one(from
, form_str(ERR_UNKNOWNCOMMAND
),
143 me
.name
, from
->name
, msgbuf
.cmd
);
145 ServerStats
.is_unco
++;
152 do_numeric(numeric
, client_p
, from
, msgbuf
.n_para
, msgbuf
.para
);
156 if(handle_command(mptr
, &msgbuf
, client_p
, from
) < -1)
159 for (p
= pbuffer
; p
<= end
; p
+= 8)
162 /* Its expected this nasty code can be removed
163 * or rewritten later if still needed.
167 for (; p
<= end
; p
++)
169 ilog(L_MAIN
, "%02x |%c", p
[0], p
[0]);
174 "%02x %02x %02x %02x %02x %02x %02x %02x |%c%c%c%c%c%c%c%c",
175 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5],
176 p
[6], p
[7], p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);
185 * inputs - pointer to message block
186 * - pointer to message buffer
187 * - pointer to client
188 * - pointer to client message is from
189 * output - -1 if error from server
193 handle_command(struct Message
*mptr
, struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*from
)
195 struct MessageEntry ehandler
;
196 MessageHandler handler
= 0;
197 char squitreason
[80];
199 if(IsAnyDead(client_p
))
202 if(IsServer(client_p
))
207 ehandler
= mptr
->handlers
[from
->handler
];
208 handler
= ehandler
.handler
;
210 /* check right amount of params is passed... --is */
211 if(msgbuf_p
->n_para
< ehandler
.min_para
||
212 (ehandler
.min_para
&& EmptyString(msgbuf_p
->para
[ehandler
.min_para
- 1])))
214 if(!IsServer(client_p
))
216 sendto_one(client_p
, form_str(ERR_NEEDMOREPARAMS
),
218 EmptyString(client_p
->name
) ? "*" : client_p
->name
,
220 if(MyClient(client_p
))
226 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
227 "Dropping server %s due to (invalid) command '%s'"
228 " with only %zu arguments (expecting %zu).",
229 client_p
->name
, mptr
->cmd
, msgbuf_p
->n_para
, ehandler
.min_para
);
231 "Insufficient parameters (%zu < %zu) for command '%s' from %s.",
232 msgbuf_p
->n_para
, ehandler
.min_para
, mptr
->cmd
, client_p
->name
);
233 snprintf(squitreason
, sizeof squitreason
,
234 "Insufficient parameters (%zu < %zu) for command '%s'",
235 msgbuf_p
->n_para
, ehandler
.min_para
, mptr
->cmd
);
236 exit_client(client_p
, client_p
, client_p
, squitreason
);
240 (*handler
) (msgbuf_p
, client_p
, from
, msgbuf_p
->n_para
, msgbuf_p
->para
);
245 handle_encap(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
,
246 const char *command
, int parc
, const char *parv
[])
248 struct Message
*mptr
;
249 struct MessageEntry ehandler
;
250 MessageHandler handler
= 0;
252 mptr
= rb_dictionary_retrieve(cmd_dict
, command
);
254 if(mptr
== NULL
|| mptr
->cmd
== NULL
)
257 ehandler
= mptr
->handlers
[ENCAP_HANDLER
];
258 handler
= ehandler
.handler
;
260 if((size_t)parc
< ehandler
.min_para
||
261 (ehandler
.min_para
&& EmptyString(parv
[ehandler
.min_para
- 1])))
264 (*handler
) (msgbuf_p
, client_p
, source_p
, parc
, parv
);
272 * side effects - MUST MUST be called at startup ONCE before
273 * any other keyword hash routine is used.
278 cmd_dict
= rb_dictionary_create("command", rb_strcasecmp
);
283 * inputs - command name
284 * - pointer to struct Message
286 * side effects - load this one command name
287 * msg->count msg->bytes is modified in place, in
288 * modules address space. Might not want to do that...
291 mod_add_cmd(struct Message
*msg
)
293 s_assert(msg
!= NULL
);
297 if (rb_dictionary_find(cmd_dict
, msg
->cmd
) != NULL
) {
298 ilog(L_MAIN
, "Add command: %s already exists", msg
->cmd
);
307 rb_dictionary_add(cmd_dict
, msg
->cmd
, msg
);
312 * inputs - command name
314 * side effects - unload this one command name
317 mod_del_cmd(struct Message
*msg
)
319 s_assert(msg
!= NULL
);
323 if (rb_dictionary_delete(cmd_dict
, msg
->cmd
) == NULL
) {
324 ilog(L_MAIN
, "Delete command: %s not found", msg
->cmd
);
331 * inputs - client who sent us the message, client with fake
333 * outputs - a given warning about the fake direction
337 cancel_clients(struct Client
*client_p
, struct Client
*source_p
)
339 /* ok, fake prefix happens naturally during a burst on a nick
340 * collision with TS5, we cant kill them because one client has to
341 * survive, so we just send an error.
343 if(IsServer(source_p
) || IsMe(source_p
))
345 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
346 "Message for %s[%s] from %s",
347 source_p
->name
, source_p
->from
->name
,
352 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
353 "Message for %s[%s@%s!%s] from %s (TS, ignored)",
357 source_p
->from
->name
,
364 * inputs - client who gave us message, supposed sender, buffer
366 * side effects - kills issued for clients, squits for servers
369 remove_unknown(struct Client
*client_p
, const char *lsender
, char *lbuffer
)
371 int slen
= strlen(lsender
);
373 struct Client
*server
;
375 /* meepfoo is a nickname (ignore)
376 * #XXXXXXXX is a UID (KILL)
377 * #XX is a SID (SQUIT)
378 * meep.foo is a server (SQUIT)
380 if((IsDigit(lsender
[0]) && slen
== 3) ||
381 (strchr(lsender
, '.') != NULL
))
383 sendto_realops_snomask(SNO_DEBUG
, L_NETWIDE
,
384 "Unknown prefix (%s) from %s, Squitting %s",
385 lbuffer
, client_p
->name
, lsender
);
388 ":%s SQUIT %s :(Unknown prefix (%s) from %s)",
389 get_id(&me
, client_p
), lsender
,
390 lbuffer
, client_p
->name
);
392 else if(!IsDigit(lsender
[0]))
395 sendto_realops_snomask(SNO_DEBUG
, L_NETWIDE
,
396 "Invalid prefix (%s) from %s",
397 lbuffer
, client_p
->name
);
400 memcpy(sid
, lsender
, 3);
402 server
= find_server(NULL
, sid
);
403 if (server
!= NULL
&& server
->from
== client_p
)
404 sendto_one(client_p
, ":%s KILL %s :%s (Unknown Client)",
405 get_id(&me
, client_p
), lsender
, me
.name
);
413 * parc number of arguments ('sender' counted as one!)
414 * parv[1]..parv[parc-1]
415 * pointers to additional parameters, this is a NULL
416 * terminated list (parv[parc] == NULL).
419 * Numerics are mostly error reports. If there is something
420 * wrong with the message, just *DROP* it! Don't even think of
421 * sending back a neat error message -- big danger of creating
422 * a ping pong error message...
425 do_numeric(int numeric
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
427 struct Client
*target_p
;
428 struct Channel
*chptr
;
430 if(parc
< 2 || !IsServer(source_p
))
433 /* Remap low number numerics. */
438 * Prepare the parameter portion of the message into 'buffer'.
439 * (Because the buffer is twice as large as the message buffer
440 * for the socket, no overflow can occur here... ...on current
441 * assumptions--bets are off, if these are changed --msa)
442 * Note: if buffer is non-empty, it will begin with SPACE.
446 char *t
= buffer
; /* Current position within the buffer */
448 int tl
; /* current length of presently being built string in t */
449 for (i
= 2; i
< (parc
- 1); i
++)
451 tl
= sprintf(t
, " %s", parv
[i
]);
454 sprintf(t
, " :%s", parv
[parc
- 1]);
457 if((target_p
= find_client(parv
[1])) != NULL
)
462 * We shouldn't get numerics sent to us,
463 * any numerics we do get indicate a bug somewhere..
465 /* ugh. this is here because of nick collisions. when two servers
466 * relink, they burst each other their nicks, then perform collides.
467 * if there is a nick collision, BOTH servers will kill their own
468 * nicks, and BOTH will kill the other servers nick, which wont exist,
469 * because it will have been already killed by the local server.
471 * unfortunately, as we cant guarantee other servers will do the
472 * "right thing" on a nick collision, we have to keep both kills.
473 * ergo we need to ignore ERR_NOSUCHNICK. --fl_
475 /* quick comment. This _was_ tried. i.e. assume the other servers
476 * will do the "right thing" and kill a nick that is colliding.
477 * unfortunately, it did not work. --Dianora
479 /* note, now we send PING on server connect, we can
480 * also get ERR_NOSUCHSERVER..
482 if(numeric
!= ERR_NOSUCHNICK
&&
483 numeric
!= ERR_NOSUCHSERVER
)
484 sendto_realops_snomask(SNO_GENERAL
, L_NETWIDE
,
485 "*** %s(via %s) sent a %03d numeric to me: %s",
487 client_p
->name
, numeric
, buffer
);
490 else if(target_p
->from
== client_p
)
492 /* This message changed direction (nick collision?)
498 /* csircd will send out unknown umode flag for +a (admin), drop it here. */
499 if(numeric
== ERR_UMODEUNKNOWNFLAG
&& MyClient(target_p
))
502 /* Fake it for server hiding, if its our client */
503 sendto_one(target_p
, ":%s %03d %s%s",
504 get_id(source_p
, target_p
), numeric
,
505 get_id(target_p
, target_p
), buffer
);
508 else if((chptr
= find_channel(parv
[1])) != NULL
)
509 sendto_channel_flags(client_p
, ALL_MEMBERS
, source_p
, chptr
,
511 numeric
, chptr
->chname
, buffer
);
515 m_not_oper(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
517 sendto_one_numeric(source_p
, ERR_NOPRIVILEGES
, form_str(ERR_NOPRIVILEGES
));
521 m_unregistered(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
523 if(IsAnyServer(client_p
))
527 * I don't =really= want to waste a bit in a flag
528 * number_of_nick_changes is only really valid after the client
529 * is fully registered..
531 if(client_p
->localClient
->number_of_nick_changes
== 0)
533 sendto_one(client_p
, form_str(ERR_NOTREGISTERED
), me
.name
);
534 client_p
->localClient
->number_of_nick_changes
++;
539 m_registered(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
541 sendto_one(client_p
, form_str(ERR_ALREADYREGISTRED
), me
.name
, source_p
->name
);
545 m_ignore(struct MsgBuf
*msgbuf_p
, struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])