Blame


1 6e07fb41 2001-12-21 alex /*
2 6e07fb41 2001-12-21 alex * ngIRCd -- The Next Generation IRC Daemon
3 8644cbf1 2008-05-30 alex * Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
4 6e07fb41 2001-12-21 alex *
5 490f28ff 2002-12-12 alex * This program is free software; you can redistribute it and/or modify
6 490f28ff 2002-12-12 alex * it under the terms of the GNU General Public License as published by
7 490f28ff 2002-12-12 alex * the Free Software Foundation; either version 2 of the License, or
8 490f28ff 2002-12-12 alex * (at your option) any later version.
9 490f28ff 2002-12-12 alex * Please read the file COPYING, README and AUTHORS for more information.
10 6e07fb41 2001-12-21 alex */
11 6e07fb41 2001-12-21 alex
12 ca33cbda 2002-03-12 alex #include "portab.h"
13 490f28ff 2002-12-12 alex
14 45404a16 2005-06-01 alex /**
15 45404a16 2005-06-01 alex * @file
16 45404a16 2005-06-01 alex * IRC command parser and validator.
17 45404a16 2005-06-01 alex */
18 45404a16 2005-06-01 alex
19 ca33cbda 2002-03-12 alex #include "imp.h"
20 6e07fb41 2001-12-21 alex #include <assert.h>
21 1c8c92af 2002-01-05 alex #include <stdlib.h>
22 6e07fb41 2001-12-21 alex #include <stdio.h>
23 6e07fb41 2001-12-21 alex #include <string.h>
24 57c7e236 2004-01-17 alex #include <strings.h>
25 6e07fb41 2001-12-21 alex
26 d79a7d28 2002-01-18 alex #include "ngircd.h"
27 ca33cbda 2002-03-12 alex #include "defines.h"
28 b8d7dcec 2003-12-30 alex #include "conn-func.h"
29 c2f60abe 2002-05-27 alex #include "client.h"
30 c2f60abe 2002-05-27 alex #include "channel.h"
31 c2f60abe 2002-05-27 alex #include "log.h"
32 c2f60abe 2002-05-27 alex #include "messages.h"
33 c2f60abe 2002-05-27 alex #include "tool.h"
34 c2f60abe 2002-05-27 alex
35 c2f60abe 2002-05-27 alex #include "exp.h"
36 c2f60abe 2002-05-27 alex #include "parse.h"
37 c2f60abe 2002-05-27 alex
38 c2f60abe 2002-05-27 alex #include "imp.h"
39 76c4f066 2001-12-23 alex #include "irc.h"
40 14aba7c1 2002-03-03 alex #include "irc-channel.h"
41 0c471b84 2002-11-30 alex #include "irc-info.h"
42 b56eb4d8 2002-02-27 alex #include "irc-login.h"
43 b56eb4d8 2002-02-27 alex #include "irc-mode.h"
44 c2f60abe 2002-05-27 alex #include "irc-op.h"
45 14aba7c1 2002-03-03 alex #include "irc-oper.h"
46 14aba7c1 2002-03-03 alex #include "irc-server.h"
47 b56eb4d8 2002-02-27 alex #include "irc-write.h"
48 47ca178a 2007-11-21 alex #include "numeric.h"
49 6e07fb41 2001-12-21 alex
50 ca33cbda 2002-03-12 alex #include "exp.h"
51 1e59617d 2002-11-30 alex
52 4add9c29 2008-01-13 fw struct _NUMERIC {
53 4add9c29 2008-01-13 fw int numeric;
54 4add9c29 2008-01-13 fw bool (*function) PARAMS(( CLIENT *Client, REQUEST *Request ));
55 4add9c29 2008-01-13 fw };
56 1e59617d 2002-11-30 alex
57 4add9c29 2008-01-13 fw
58 4add9c29 2008-01-13 fw static COMMAND My_Commands[] =
59 1e59617d 2002-11-30 alex {
60 17f7c6d3 2002-12-18 alex { "ADMIN", IRC_ADMIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
61 17f7c6d3 2002-12-18 alex { "AWAY", IRC_AWAY, CLIENT_USER, 0, 0, 0 },
62 17f7c6d3 2002-12-18 alex { "CONNECT", IRC_CONNECT, CLIENT_USER, 0, 0, 0 },
63 17f7c6d3 2002-12-18 alex { "DIE", IRC_DIE, CLIENT_USER, 0, 0, 0 },
64 a7956f33 2003-12-31 alex { "DISCONNECT", IRC_DISCONNECT, CLIENT_USER, 0, 0, 0 },
65 17f7c6d3 2002-12-18 alex { "ERROR", IRC_ERROR, 0xFFFF, 0, 0, 0 },
66 2152e377 2003-01-15 alex { "HELP", IRC_HELP, CLIENT_USER, 0, 0, 0 },
67 ddecfcd8 2008-02-26 fw { "INFO", IRC_INFO, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
68 17f7c6d3 2002-12-18 alex { "INVITE", IRC_INVITE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
69 17f7c6d3 2002-12-18 alex { "ISON", IRC_ISON, CLIENT_USER, 0, 0, 0 },
70 17f7c6d3 2002-12-18 alex { "JOIN", IRC_JOIN, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
71 17f7c6d3 2002-12-18 alex { "KICK", IRC_KICK, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
72 17f7c6d3 2002-12-18 alex { "KILL", IRC_KILL, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
73 17f7c6d3 2002-12-18 alex { "LINKS", IRC_LINKS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
74 17f7c6d3 2002-12-18 alex { "LIST", IRC_LIST, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
75 17f7c6d3 2002-12-18 alex { "LUSERS", IRC_LUSERS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
76 17f7c6d3 2002-12-18 alex { "MODE", IRC_MODE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
77 17f7c6d3 2002-12-18 alex { "MOTD", IRC_MOTD, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
78 17f7c6d3 2002-12-18 alex { "NAMES", IRC_NAMES, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
79 17f7c6d3 2002-12-18 alex { "NICK", IRC_NICK, 0xFFFF, 0, 0, 0 },
80 17f7c6d3 2002-12-18 alex { "NJOIN", IRC_NJOIN, CLIENT_SERVER, 0, 0, 0 },
81 17f7c6d3 2002-12-18 alex { "NOTICE", IRC_NOTICE, 0xFFFF, 0, 0, 0 },
82 17f7c6d3 2002-12-18 alex { "OPER", IRC_OPER, CLIENT_USER, 0, 0, 0 },
83 17f7c6d3 2002-12-18 alex { "PART", IRC_PART, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
84 17f7c6d3 2002-12-18 alex { "PASS", IRC_PASS, 0xFFFF, 0, 0, 0 },
85 17f7c6d3 2002-12-18 alex { "PING", IRC_PING, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
86 17f7c6d3 2002-12-18 alex { "PONG", IRC_PONG, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
87 17f7c6d3 2002-12-18 alex { "PRIVMSG", IRC_PRIVMSG, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
88 17f7c6d3 2002-12-18 alex { "QUIT", IRC_QUIT, 0xFFFF, 0, 0, 0 },
89 17f7c6d3 2002-12-18 alex { "REHASH", IRC_REHASH, CLIENT_USER, 0, 0, 0 },
90 17f7c6d3 2002-12-18 alex { "RESTART", IRC_RESTART, CLIENT_USER, 0, 0, 0 },
91 17f7c6d3 2002-12-18 alex { "SERVER", IRC_SERVER, 0xFFFF, 0, 0, 0 },
92 4e56e534 2008-05-05 alex { "SERVICE", IRC_SERVICE, 0xFFFF, 0, 0, 0 },
93 4e56e534 2008-05-05 alex { "SERVLIST", IRC_SERVLIST, CLIENT_USER, 0, 0, 0 },
94 4e56e534 2008-05-05 alex { "SQUERY", IRC_SQUERY, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
95 17f7c6d3 2002-12-18 alex { "SQUIT", IRC_SQUIT, CLIENT_SERVER, 0, 0, 0 },
96 17f7c6d3 2002-12-18 alex { "STATS", IRC_STATS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
97 ddecfcd8 2008-02-26 fw { "SUMMON", IRC_SUMMON, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
98 17f7c6d3 2002-12-18 alex { "TIME", IRC_TIME, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
99 17f7c6d3 2002-12-18 alex { "TOPIC", IRC_TOPIC, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
100 42c4e6c7 2003-01-13 alex { "TRACE", IRC_TRACE, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
101 17f7c6d3 2002-12-18 alex { "USER", IRC_USER, 0xFFFF, 0, 0, 0 },
102 17f7c6d3 2002-12-18 alex { "USERHOST", IRC_USERHOST, CLIENT_USER, 0, 0, 0 },
103 ddecfcd8 2008-02-26 fw { "USERS", IRC_USERS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
104 17f7c6d3 2002-12-18 alex { "VERSION", IRC_VERSION, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
105 4b9e52eb 2007-08-02 fw { "WALLOPS", IRC_WALLOPS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
106 17f7c6d3 2002-12-18 alex { "WHO", IRC_WHO, CLIENT_USER, 0, 0, 0 },
107 17f7c6d3 2002-12-18 alex { "WHOIS", IRC_WHOIS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
108 17f7c6d3 2002-12-18 alex { "WHOWAS", IRC_WHOWAS, CLIENT_USER|CLIENT_SERVER, 0, 0, 0 },
109 17f7c6d3 2002-12-18 alex #ifdef IRCPLUS
110 17f7c6d3 2002-12-18 alex { "CHANINFO", IRC_CHANINFO, CLIENT_SERVER, 0, 0, 0 },
111 1e59617d 2002-11-30 alex #endif
112 17f7c6d3 2002-12-18 alex { NULL, NULL, 0x0, 0, 0, 0 } /* Ende-Marke */
113 47ca178a 2007-11-21 alex };
114 47ca178a 2007-11-21 alex
115 77f54693 2005-07-31 alex static void Init_Request PARAMS(( REQUEST *Req ));
116 6e07fb41 2001-12-21 alex
117 77f54693 2005-07-31 alex static bool Validate_Prefix PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
118 77f54693 2005-07-31 alex static bool Validate_Command PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
119 77f54693 2005-07-31 alex static bool Validate_Args PARAMS(( CONN_ID Idx, REQUEST *Req, bool *Closed ));
120 6e07fb41 2001-12-21 alex
121 77f54693 2005-07-31 alex static bool Handle_Request PARAMS(( CONN_ID Idx, REQUEST *Req ));
122 6e07fb41 2001-12-21 alex
123 4add9c29 2008-01-13 fw #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
124 6e07fb41 2001-12-21 alex
125 45404a16 2005-06-01 alex /**
126 45404a16 2005-06-01 alex * Return the pointer to the global "IRC command structure".
127 45404a16 2005-06-01 alex * This structure, an array of type "COMMAND" describes all the IRC commands
128 45404a16 2005-06-01 alex * implemented by ngIRCd and how to handle them.
129 45404a16 2005-06-01 alex * @return Pointer to the global command structure.
130 45404a16 2005-06-01 alex */
131 17f7c6d3 2002-12-18 alex GLOBAL COMMAND *
132 8adff592 2005-03-19 fw Parse_GetCommandStruct( void )
133 17f7c6d3 2002-12-18 alex {
134 17f7c6d3 2002-12-18 alex return My_Commands;
135 17f7c6d3 2002-12-18 alex } /* Parse_GetCommandStruct */
136 17f7c6d3 2002-12-18 alex
137 17f7c6d3 2002-12-18 alex
138 45404a16 2005-06-01 alex /**
139 45404a16 2005-06-01 alex * Parse a command ("request") received from a client.
140 45404a16 2005-06-01 alex *
141 45404a16 2005-06-01 alex * This function is called after the connection layer received a valid CR+LF
142 45404a16 2005-06-01 alex * terminated line of text: we asume that this is a valid IRC command and
143 45404a16 2005-06-01 alex * try to do something useful with it :-)
144 45404a16 2005-06-01 alex *
145 45404a16 2005-06-01 alex * All errors are reported to the client from which the command has been
146 45404a16 2005-06-01 alex * received, and if the error is fatal this connection is closed down.
147 45404a16 2005-06-01 alex *
148 45404a16 2005-06-01 alex * This function is able to parse the syntax as described in RFC 2812,
149 45404a16 2005-06-01 alex * section 2.3.
150 45404a16 2005-06-01 alex *
151 45404a16 2005-06-01 alex * @param Idx Index of the connection from which the command has been received.
152 45404a16 2005-06-01 alex * @param Request NULL terminated line of text (the "command").
153 45404a16 2005-06-01 alex * @return true on success (valid command or "regular" error), false if a
154 45404a16 2005-06-01 alex * fatal error occured and the connection has been shut down.
155 45404a16 2005-06-01 alex */
156 8adff592 2005-03-19 fw GLOBAL bool
157 8adff592 2005-03-19 fw Parse_Request( CONN_ID Idx, char *Request )
158 6e07fb41 2001-12-21 alex {
159 6e07fb41 2001-12-21 alex REQUEST req;
160 8adff592 2005-03-19 fw char *start, *ptr;
161 8adff592 2005-03-19 fw bool closed;
162 6e07fb41 2001-12-21 alex
163 6e07fb41 2001-12-21 alex assert( Idx >= 0 );
164 6e07fb41 2001-12-21 alex assert( Request != NULL );
165 76c4f066 2001-12-23 alex
166 d4a60bd4 2001-12-25 alex #ifdef SNIFFER
167 d79a7d28 2002-01-18 alex if( NGIRCd_Sniffer ) Log( LOG_DEBUG, " <- connection %d: '%s'.", Idx, Request );
168 76c4f066 2001-12-23 alex #endif
169 e0ed3aa1 2002-07-26 alex
170 6e07fb41 2001-12-21 alex Init_Request( &req );
171 6e07fb41 2001-12-21 alex
172 363a03b8 2001-12-29 alex /* Fuehrendes und folgendes "Geraffel" verwerfen */
173 363a03b8 2001-12-29 alex ngt_TrimStr( Request );
174 363a03b8 2001-12-29 alex
175 6e07fb41 2001-12-21 alex /* gibt es ein Prefix? */
176 6e07fb41 2001-12-21 alex if( Request[0] == ':' )
177 6e07fb41 2001-12-21 alex {
178 6e07fb41 2001-12-21 alex /* Prefix vorhanden */
179 6e07fb41 2001-12-21 alex req.prefix = Request + 1;
180 6e07fb41 2001-12-21 alex ptr = strchr( Request, ' ' );
181 e0ed3aa1 2002-07-26 alex if( ! ptr )
182 e0ed3aa1 2002-07-26 alex {
183 e0ed3aa1 2002-07-26 alex Log( LOG_DEBUG, "Connection %d: Parse error: prefix without command!?", Idx );
184 e0ed3aa1 2002-07-26 alex return Conn_WriteStr( Idx, "ERROR :Prefix without command!?" );
185 e0ed3aa1 2002-07-26 alex }
186 6e07fb41 2001-12-21 alex *ptr = '\0';
187 3543c222 2002-01-09 alex #ifndef STRICT_RFC
188 3543c222 2002-01-09 alex /* multiple Leerzeichen als Trenner zwischen
189 3543c222 2002-01-09 alex * Prefix und Befehl ignorieren */
190 3543c222 2002-01-09 alex while( *(ptr + 1) == ' ' ) ptr++;
191 3543c222 2002-01-09 alex #endif
192 6e07fb41 2001-12-21 alex start = ptr + 1;
193 6e07fb41 2001-12-21 alex }
194 6e07fb41 2001-12-21 alex else start = Request;
195 6e07fb41 2001-12-21 alex
196 6e07fb41 2001-12-21 alex /* Befehl */
197 6e07fb41 2001-12-21 alex ptr = strchr( start, ' ' );
198 3543c222 2002-01-09 alex if( ptr )
199 3543c222 2002-01-09 alex {
200 3543c222 2002-01-09 alex *ptr = '\0';
201 3543c222 2002-01-09 alex #ifndef STRICT_RFC
202 3543c222 2002-01-09 alex /* multiple Leerzeichen als Trenner vor
203 fc1118cb 2003-01-12 alex * Parametern ignorieren */
204 3543c222 2002-01-09 alex while( *(ptr + 1) == ' ' ) ptr++;
205 3543c222 2002-01-09 alex #endif
206 3543c222 2002-01-09 alex }
207 6e07fb41 2001-12-21 alex req.command = start;
208 6e07fb41 2001-12-21 alex
209 6e07fb41 2001-12-21 alex /* Argumente, Parameter */
210 6e07fb41 2001-12-21 alex if( ptr )
211 6e07fb41 2001-12-21 alex {
212 6e07fb41 2001-12-21 alex /* Prinzipiell gibt es welche :-) */
213 6e07fb41 2001-12-21 alex start = ptr + 1;
214 6e07fb41 2001-12-21 alex while( start )
215 6e07fb41 2001-12-21 alex {
216 6e07fb41 2001-12-21 alex /* Parameter-String "zerlegen" */
217 76c4f066 2001-12-23 alex if( start[0] == ':' )
218 76c4f066 2001-12-23 alex {
219 76c4f066 2001-12-23 alex req.argv[req.argc] = start + 1;
220 76c4f066 2001-12-23 alex ptr = NULL;
221 76c4f066 2001-12-23 alex }
222 76c4f066 2001-12-23 alex else
223 76c4f066 2001-12-23 alex {
224 76c4f066 2001-12-23 alex req.argv[req.argc] = start;
225 76c4f066 2001-12-23 alex ptr = strchr( start, ' ' );
226 3543c222 2002-01-09 alex if( ptr )
227 3543c222 2002-01-09 alex {
228 3543c222 2002-01-09 alex *ptr = '\0';
229 3543c222 2002-01-09 alex #ifndef STRICT_RFC
230 3543c222 2002-01-09 alex /* multiple Leerzeichen als
231 3543c222 2002-01-09 alex * Parametertrenner ignorieren */
232 3543c222 2002-01-09 alex while( *(ptr + 1) == ' ' ) ptr++;
233 3543c222 2002-01-09 alex #endif
234 3543c222 2002-01-09 alex }
235 76c4f066 2001-12-23 alex }
236 e0ed3aa1 2002-07-26 alex
237 6e07fb41 2001-12-21 alex req.argc++;
238 6e07fb41 2001-12-21 alex
239 6e07fb41 2001-12-21 alex if( start[0] == ':' ) break;
240 6e07fb41 2001-12-21 alex if( req.argc > 14 ) break;
241 e0ed3aa1 2002-07-26 alex
242 6e07fb41 2001-12-21 alex if( ptr ) start = ptr + 1;
243 6e07fb41 2001-12-21 alex else start = NULL;
244 6e07fb41 2001-12-21 alex }
245 6e07fb41 2001-12-21 alex }
246 93aa0dbf 2002-01-03 alex
247 b0b797b3 2002-11-28 alex /* Daten validieren */
248 b0b797b3 2002-11-28 alex if( ! Validate_Prefix( Idx, &req, &closed )) return ! closed;
249 b0b797b3 2002-11-28 alex if( ! Validate_Command( Idx, &req, &closed )) return ! closed;
250 e0ed3aa1 2002-07-26 alex if( ! Validate_Args( Idx, &req, &closed )) return ! closed;
251 e0ed3aa1 2002-07-26 alex
252 6e07fb41 2001-12-21 alex return Handle_Request( Idx, &req );
253 6e07fb41 2001-12-21 alex } /* Parse_Request */
254 6e07fb41 2001-12-21 alex
255 6e07fb41 2001-12-21 alex
256 45404a16 2005-06-01 alex /**
257 45404a16 2005-06-01 alex * Initialize request structure.
258 45404a16 2005-06-01 alex * @param Req Request structure to be initialized.
259 45404a16 2005-06-01 alex */
260 77f54693 2005-07-31 alex static void
261 c2f60abe 2002-05-27 alex Init_Request( REQUEST *Req )
262 6e07fb41 2001-12-21 alex {
263 6e07fb41 2001-12-21 alex /* Neue Request-Struktur initialisieren */
264 6e07fb41 2001-12-21 alex
265 8adff592 2005-03-19 fw int i;
266 e0ed3aa1 2002-07-26 alex
267 6e07fb41 2001-12-21 alex assert( Req != NULL );
268 6e07fb41 2001-12-21 alex
269 6e07fb41 2001-12-21 alex Req->prefix = NULL;
270 6e07fb41 2001-12-21 alex Req->command = NULL;
271 6e07fb41 2001-12-21 alex for( i = 0; i < 15; Req->argv[i++] = NULL );
272 6e07fb41 2001-12-21 alex Req->argc = 0;
273 6e07fb41 2001-12-21 alex } /* Init_Request */
274 6e07fb41 2001-12-21 alex
275 6e07fb41 2001-12-21 alex
276 77f54693 2005-07-31 alex static bool
277 8adff592 2005-03-19 fw Validate_Prefix( CONN_ID Idx, REQUEST *Req, bool *Closed )
278 6e07fb41 2001-12-21 alex {
279 5063de59 2002-07-29 alex CLIENT *client, *c;
280 6e07fb41 2001-12-21 alex
281 e0ed3aa1 2002-07-26 alex assert( Idx >= 0 );
282 e0ed3aa1 2002-07-26 alex assert( Req != NULL );
283 6e07fb41 2001-12-21 alex
284 8adff592 2005-03-19 fw *Closed = false;
285 5063de59 2002-07-29 alex
286 e0ed3aa1 2002-07-26 alex /* ist ueberhaupt ein Prefix vorhanden? */
287 8adff592 2005-03-19 fw if( ! Req->prefix ) return true;
288 6e07fb41 2001-12-21 alex
289 5063de59 2002-07-29 alex /* Client-Struktur der Connection ermitteln */
290 87f4b1c6 2006-04-23 fw client = Conn_GetClient( Idx );
291 5063de59 2002-07-29 alex assert( client != NULL );
292 5063de59 2002-07-29 alex
293 5063de59 2002-07-29 alex /* nur validieren, wenn bereits registrierte Verbindung */
294 5063de59 2002-07-29 alex if(( Client_Type( client ) != CLIENT_USER ) && ( Client_Type( client ) != CLIENT_SERVER ) && ( Client_Type( client ) != CLIENT_SERVICE ))
295 5063de59 2002-07-29 alex {
296 5063de59 2002-07-29 alex /* noch nicht registrierte Verbindung.
297 5063de59 2002-07-29 alex * Das Prefix wird ignoriert. */
298 5063de59 2002-07-29 alex Req->prefix = NULL;
299 8adff592 2005-03-19 fw return true;
300 5063de59 2002-07-29 alex }
301 5063de59 2002-07-29 alex
302 e0ed3aa1 2002-07-26 alex /* pruefen, ob der im Prefix angegebene Client bekannt ist */
303 e0ed3aa1 2002-07-26 alex c = Client_Search( Req->prefix );
304 e0ed3aa1 2002-07-26 alex if( ! c )
305 e0ed3aa1 2002-07-26 alex {
306 e0ed3aa1 2002-07-26 alex /* im Prefix angegebener Client ist nicht bekannt */
307 b0b797b3 2002-11-28 alex Log( LOG_ERR, "Invalid prefix \"%s\", client not known (connection %d, command %s)!?", Req->prefix, Idx, Req->command );
308 8adff592 2005-03-19 fw if( ! Conn_WriteStr( Idx, "ERROR :Invalid prefix \"%s\", client not known!?", Req->prefix )) *Closed = true;
309 8adff592 2005-03-19 fw return false;
310 e0ed3aa1 2002-07-26 alex }
311 5063de59 2002-07-29 alex
312 e0ed3aa1 2002-07-26 alex /* pruefen, ob der Client mit dem angegebenen Prefix in Richtung
313 e0ed3aa1 2002-07-26 alex * des Senders liegt, d.h. sicherstellen, dass das Prefix nicht
314 e0ed3aa1 2002-07-26 alex * gefaelscht ist */
315 5063de59 2002-07-29 alex if( Client_NextHop( c ) != client )
316 e0ed3aa1 2002-07-26 alex {
317 e0ed3aa1 2002-07-26 alex /* das angegebene Prefix ist aus dieser Richtung, also
318 e0ed3aa1 2002-07-26 alex * aus der gegebenen Connection, ungueltig! */
319 87f4b1c6 2006-04-23 fw Log( LOG_ERR, "Spoofed prefix \"%s\" from \"%s\" (connection %d, command %s)!", Req->prefix, Client_Mask( Conn_GetClient( Idx )), Idx, Req->command );
320 8adff592 2005-03-19 fw Conn_Close( Idx, NULL, "Spoofed prefix", true);
321 8adff592 2005-03-19 fw *Closed = true;
322 8adff592 2005-03-19 fw return false;
323 e0ed3aa1 2002-07-26 alex }
324 e0ed3aa1 2002-07-26 alex
325 8adff592 2005-03-19 fw return true;
326 6e07fb41 2001-12-21 alex } /* Validate_Prefix */
327 6e07fb41 2001-12-21 alex
328 6e07fb41 2001-12-21 alex
329 77f54693 2005-07-31 alex static bool
330 74cb2e27 2005-07-22 alex Validate_Command( UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed )
331 6e07fb41 2001-12-21 alex {
332 e0ed3aa1 2002-07-26 alex assert( Idx >= 0 );
333 6e07fb41 2001-12-21 alex assert( Req != NULL );
334 8adff592 2005-03-19 fw *Closed = false;
335 e0ed3aa1 2002-07-26 alex
336 8adff592 2005-03-19 fw return true;
337 6e07fb41 2001-12-21 alex } /* Validate_Comman */
338 6e07fb41 2001-12-21 alex
339 6e07fb41 2001-12-21 alex
340 77f54693 2005-07-31 alex static bool
341 e5cf73b9 2008-07-27 alex #ifdef STRICT_RFC
342 8644cbf1 2008-05-30 alex Validate_Args(CONN_ID Idx, REQUEST *Req, bool *Closed)
343 e5cf73b9 2008-07-27 alex #else
344 e5cf73b9 2008-07-27 alex Validate_Args(UNUSED CONN_ID Idx, UNUSED REQUEST *Req, bool *Closed)
345 e5cf73b9 2008-07-27 alex #endif
346 6e07fb41 2001-12-21 alex {
347 a84f7dce 2008-06-11 alex #ifdef STRICT_RFC
348 8644cbf1 2008-05-30 alex int i;
349 a84f7dce 2008-06-11 alex #endif
350 8644cbf1 2008-05-30 alex
351 8adff592 2005-03-19 fw *Closed = false;
352 e0ed3aa1 2002-07-26 alex
353 a84f7dce 2008-06-11 alex #ifdef STRICT_RFC
354 e5cf73b9 2008-07-27 alex assert( Idx >= 0 );
355 e5cf73b9 2008-07-27 alex assert( Req != NULL );
356 e5cf73b9 2008-07-27 alex
357 a84f7dce 2008-06-11 alex /* CR and LF are never allowed in command parameters.
358 a84f7dce 2008-06-11 alex * But since we do accept lines terminated only with CR or LF in
359 a84f7dce 2008-06-11 alex * "non-RFC-compliant mode" (besides the correct CR+LF combination),
360 a84f7dce 2008-06-11 alex * this check can only trigger in "strict RFC" mode; therefore we
361 a84f7dce 2008-06-11 alex * optimize it away otherwise ... */
362 8644cbf1 2008-05-30 alex for (i = 0; i < Req->argc; i++) {
363 8644cbf1 2008-05-30 alex if (strchr(Req->argv[i], '\r') || strchr(Req->argv[i], '\n')) {
364 8644cbf1 2008-05-30 alex Log(LOG_ERR,
365 8644cbf1 2008-05-30 alex "Invalid character(s) in parameter (connection %d, command %s)!?",
366 8644cbf1 2008-05-30 alex Idx, Req->command);
367 8644cbf1 2008-05-30 alex if (!Conn_WriteStr(Idx,
368 8644cbf1 2008-05-30 alex "ERROR :Invalid character(s) in parameter!"))
369 8644cbf1 2008-05-30 alex *Closed = true;
370 8644cbf1 2008-05-30 alex return false;
371 8644cbf1 2008-05-30 alex }
372 8644cbf1 2008-05-30 alex }
373 a84f7dce 2008-06-11 alex #endif
374 a84f7dce 2008-06-11 alex
375 8adff592 2005-03-19 fw return true;
376 6e07fb41 2001-12-21 alex } /* Validate_Args */
377 6e07fb41 2001-12-21 alex
378 6e07fb41 2001-12-21 alex
379 4add9c29 2008-01-13 fw /* Command is a status code ("numeric") from another server */
380 77f54693 2005-07-31 alex static bool
381 4add9c29 2008-01-13 fw Handle_Numeric(CLIENT *client, REQUEST *Req)
382 4add9c29 2008-01-13 fw {
383 4add9c29 2008-01-13 fw static const struct _NUMERIC Numerics[] = {
384 4add9c29 2008-01-13 fw { 005, IRC_Num_ISUPPORT },
385 4add9c29 2008-01-13 fw { 376, IRC_Num_ENDOFMOTD }
386 4add9c29 2008-01-13 fw };
387 4add9c29 2008-01-13 fw int i, num;
388 4add9c29 2008-01-13 fw char str[LINE_LEN];
389 4add9c29 2008-01-13 fw CLIENT *prefix, *target = NULL;
390 4add9c29 2008-01-13 fw
391 4add9c29 2008-01-13 fw /* Determine target */
392 4add9c29 2008-01-13 fw if (Req->argc > 0)
393 4add9c29 2008-01-13 fw target = Client_Search(Req->argv[0]);
394 4add9c29 2008-01-13 fw
395 4add9c29 2008-01-13 fw if (!target) {
396 4add9c29 2008-01-13 fw /* Status code without target!? */
397 4add9c29 2008-01-13 fw if (Req->argc > 0)
398 4add9c29 2008-01-13 fw Log(LOG_WARNING,
399 4add9c29 2008-01-13 fw "Unknown target for status code %s: \"%s\"",
400 4add9c29 2008-01-13 fw Req->command, Req->argv[0]);
401 4add9c29 2008-01-13 fw else
402 4add9c29 2008-01-13 fw Log(LOG_WARNING,
403 4add9c29 2008-01-13 fw "Unknown target for status code %s!",
404 4add9c29 2008-01-13 fw Req->command);
405 4add9c29 2008-01-13 fw return true;
406 4add9c29 2008-01-13 fw }
407 4add9c29 2008-01-13 fw if (target == Client_ThisServer()) {
408 4add9c29 2008-01-13 fw /* This server is the target of the numeric */
409 4add9c29 2008-01-13 fw num = atoi(Req->command);
410 4add9c29 2008-01-13 fw
411 4add9c29 2008-01-13 fw for (i = 0; i < (int) ARRAY_SIZE(Numerics); i++) {
412 4add9c29 2008-01-13 fw if (num == Numerics[i].numeric)
413 4add9c29 2008-01-13 fw return Numerics[i].function(client, Req);
414 4add9c29 2008-01-13 fw }
415 4add9c29 2008-01-13 fw
416 4add9c29 2008-01-13 fw LogDebug("Ignored status code %s from \"%s\".",
417 4add9c29 2008-01-13 fw Req->command, Client_ID(client));
418 4add9c29 2008-01-13 fw return true;
419 4add9c29 2008-01-13 fw }
420 4add9c29 2008-01-13 fw
421 4add9c29 2008-01-13 fw /* Determine source */
422 4add9c29 2008-01-13 fw if (! Req->prefix[0]) {
423 4add9c29 2008-01-13 fw /* Oops, no prefix!? */
424 4add9c29 2008-01-13 fw Log(LOG_WARNING, "Got status code %s from \"%s\" without prefix!?",
425 4add9c29 2008-01-13 fw Req->command, Client_ID(client));
426 4add9c29 2008-01-13 fw return true;
427 4add9c29 2008-01-13 fw }
428 4add9c29 2008-01-13 fw
429 4add9c29 2008-01-13 fw prefix = Client_Search(Req->prefix);
430 4add9c29 2008-01-13 fw if (! prefix) { /* Oops, unknown prefix!? */
431 4add9c29 2008-01-13 fw Log(LOG_WARNING, "Got status code %s from unknown source: \"%s\"", Req->command, Req->prefix);
432 4add9c29 2008-01-13 fw return true;
433 4add9c29 2008-01-13 fw }
434 4add9c29 2008-01-13 fw
435 4add9c29 2008-01-13 fw /* Forward status code */
436 4add9c29 2008-01-13 fw strlcpy(str, Req->command, sizeof(str));
437 4add9c29 2008-01-13 fw for (i = 0; i < Req->argc; i++) {
438 4add9c29 2008-01-13 fw if (i < Req->argc - 1)
439 4add9c29 2008-01-13 fw strlcat(str, " ", sizeof(str));
440 4add9c29 2008-01-13 fw else
441 4add9c29 2008-01-13 fw strlcat(str, " :", sizeof(str));
442 4add9c29 2008-01-13 fw strlcat(str, Req->argv[i], sizeof(str));
443 4add9c29 2008-01-13 fw }
444 4add9c29 2008-01-13 fw return IRC_WriteStrClientPrefix(target, prefix, "%s", str);
445 4add9c29 2008-01-13 fw }
446 4add9c29 2008-01-13 fw
447 4add9c29 2008-01-13 fw
448 4add9c29 2008-01-13 fw static bool
449 c2f60abe 2002-05-27 alex Handle_Request( CONN_ID Idx, REQUEST *Req )
450 6e07fb41 2001-12-21 alex {
451 76c4f066 2001-12-23 alex /* Client-Request verarbeiten. Bei einem schwerwiegenden Fehler
452 8adff592 2005-03-19 fw * wird die Verbindung geschlossen und false geliefert. */
453 4add9c29 2008-01-13 fw CLIENT *client;
454 4add9c29 2008-01-13 fw bool result = true;
455 3022d7cf 2008-02-26 fw int client_type;
456 1e59617d 2002-11-30 alex COMMAND *cmd;
457 76c4f066 2001-12-23 alex
458 6e07fb41 2001-12-21 alex assert( Idx >= 0 );
459 6e07fb41 2001-12-21 alex assert( Req != NULL );
460 6e07fb41 2001-12-21 alex assert( Req->command != NULL );
461 6e07fb41 2001-12-21 alex
462 87f4b1c6 2006-04-23 fw client = Conn_GetClient( Idx );
463 76c4f066 2001-12-23 alex assert( client != NULL );
464 1c8c92af 2002-01-05 alex
465 47ca178a 2007-11-21 alex /* Numeric? */
466 3022d7cf 2008-02-26 fw client_type = Client_Type(client);
467 3022d7cf 2008-02-26 fw if ((client_type == CLIENT_SERVER ||
468 3022d7cf 2008-02-26 fw client_type == CLIENT_UNKNOWNSERVER)
469 4add9c29 2008-01-13 fw && strlen(Req->command) == 3 && atoi(Req->command) > 1)
470 4add9c29 2008-01-13 fw return Handle_Numeric(client, Req);
471 47ca178a 2007-11-21 alex
472 1e59617d 2002-11-30 alex cmd = My_Commands;
473 4add9c29 2008-01-13 fw while (cmd->name) {
474 1e59617d 2002-11-30 alex /* Befehl suchen */
475 4add9c29 2008-01-13 fw if (strcasecmp(Req->command, cmd->name) != 0) {
476 4add9c29 2008-01-13 fw cmd++;
477 4add9c29 2008-01-13 fw continue;
478 1e59617d 2002-11-30 alex }
479 1e59617d 2002-11-30 alex
480 3022d7cf 2008-02-26 fw if (!(client_type & cmd->type))
481 4add9c29 2008-01-13 fw return IRC_WriteStrClient(client, ERR_NOTREGISTERED_MSG, Client_ID(client));
482 17f7c6d3 2002-12-18 alex
483 4add9c29 2008-01-13 fw /* Command is allowed for this client: call it and count produced bytes */
484 4add9c29 2008-01-13 fw Conn_ResetWCounter();
485 4add9c29 2008-01-13 fw result = (cmd->function)(client, Req);
486 4add9c29 2008-01-13 fw cmd->bytes += Conn_WCounter();
487 17f7c6d3 2002-12-18 alex
488 4add9c29 2008-01-13 fw /* Adjust counters */
489 3022d7cf 2008-02-26 fw if (client_type != CLIENT_SERVER)
490 4add9c29 2008-01-13 fw cmd->lcount++;
491 1e59617d 2002-11-30 alex else
492 4add9c29 2008-01-13 fw cmd->rcount++;
493 4add9c29 2008-01-13 fw return result;
494 1e59617d 2002-11-30 alex }
495 162338b8 2005-06-24 alex
496 3022d7cf 2008-02-26 fw if (client_type != CLIENT_USER &&
497 3022d7cf 2008-02-26 fw client_type != CLIENT_SERVER &&
498 3022d7cf 2008-02-26 fw client_type != CLIENT_SERVICE )
499 162338b8 2005-06-24 alex return true;
500 4add9c29 2008-01-13 fw
501 162338b8 2005-06-24 alex /* Unknown command and registered connection: generate error: */
502 4add9c29 2008-01-13 fw LogDebug("Connection %d: Unknown command \"%s\", %d %s,%s prefix.",
503 162338b8 2005-06-24 alex Client_Conn( client ), Req->command, Req->argc,
504 162338b8 2005-06-24 alex Req->argc == 1 ? "parameter" : "parameters",
505 162338b8 2005-06-24 alex Req->prefix ? "" : " no" );
506 162338b8 2005-06-24 alex
507 4d18ac83 2005-09-04 alex if (Client_Type(client) != CLIENT_SERVER) {
508 4d18ac83 2005-09-04 alex result = IRC_WriteStrClient(client, ERR_UNKNOWNCOMMAND_MSG,
509 4d18ac83 2005-09-04 alex Client_ID(client), Req->command);
510 4d18ac83 2005-09-04 alex Conn_SetPenalty(Idx, 1);
511 4d18ac83 2005-09-04 alex }
512 4add9c29 2008-01-13 fw return result;
513 6e07fb41 2001-12-21 alex } /* Handle_Request */
514 6e07fb41 2001-12-21 alex
515 6e07fb41 2001-12-21 alex
516 6e07fb41 2001-12-21 alex /* -eof- */