1 /*
2 * ----------------------------------------------------------------
3 * ircproxy - Client Parser Functions
4 * ----------------------------------------------------------------
5 * Copyright (C) 1997-2009 Jonas Kvinge
6 *
7 * This file is part of ircproxy.
8 *
9 * ircproxy is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * ircproxy is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ircproxy. If not, see <http://www.gnu.org/licenses/>.
21 *
22 * Additional permission under GNU GPL version 3 section 7
23 *
24 * If you modify ircproxy, or any covered work, by linking or
25 * combining it with openssl (or a modified version of that library),
26 * containing parts covered by the terms of the OpenSSL License and the
27 * SSLeay License, the licensors of ircproxy grant you additional
28 * permission to convey the resulting work.
29 *
30 * $Id: client_parser.c 54 2009-03-18 18:23:29Z jonasio $
31 *
32 */
33
34 #define CLIENT_PARSER_C
35
36 #define NEED_SYS_TYPES_H 1 /* Extra types */
37 #define NEED_SYS_PARAM_H 1 /* Some systems need this */
38 #define NEED_LIMITS_H 0 /* Kernel limits */
39 #define NEED_STDARG_H 1 /* va_list, etc */
40 #define NEED_ERRNO_H 1 /* errno */
41 #define NEED_CTYPE_H 1 /* isdigit(), etc */
42 #define NEED_NETINET_IN_H 1 /* in_addr, sockaddr_in, etc */
43 #define NEED_ARPA_INET_H 0 /* inet_ntoa(), inet_aton(), etc */
44 #define NEED_STDIO_H 1 /* Standard C UNIX functions */
45 #define NEED_STDLIB_H 1 /* malloc(), exit(), atoi(), etc */
46 #define NEED_TIME_H 1 /* time(), etc */
47 #define NEED_SYSCTL_H 0 /* sysctl(), etc */
48 #define NEED_SYS_STAT_H 0 /* chmod(), mkdir(), etc */
49 #define NEED_SYS_UIO_H 0 /* iovec, etc */
50 #define NEED_FCNTL_H 1 /* open(), creat(), fcntl(), etc */
51 #define NEED_SYS_IOCTL_H 0 /* ioctl(), etc */
52 #define NEED_SYS_FILIO_H 0 /* Solaris need this for ioctl(), etc */
53 #define NEED_UNISTD_H 1 /* Unix standard functions */
54 #define NEED_STRING_H 1 /* C string functions */
55 #define NEED_SIGNAL_H 0 /* Signal functions */
56 #define NEED_SYS_SOCKET_H 0 /* Socket functions */
57 #define NEED_NETDB_H 0 /* Network database functions */
58 #define NEED_ARPA_NAMESER_H 0 /* Nameserver definitions */
59 #define NEED_GETUSERPW_HEADERS 0 /* Functions to retrive system passwords */
60 #define NEED_ARES 1 /* Functions needed for ares */
61 #define NEED_SSL 1 /* Needed for SSL support */
62
63 #include "includes.h"
64 #include "irc.h"
65
66 #include "conf.h"
67
68 #if MEMDEBUG
69 #include "memleaks.h"
70 #endif
71
72 #include "access_conf.h"
73 #include "conn_conf.h"
74
75 #include "listen.h"
76
77 #include "client.h"
78 #include "client_connection.h"
79 #include "client_parser.h"
80 #include "client_auth.h"
81 #include "client_handle.h"
82 #include "client_notice.h"
83
84 #include "conn.h"
85 #include "conn_connection.h"
86 #include "conn_sendq.h"
87 #include "conn_log.h"
88
89 #include "chan.h"
90 #include "chan_user.h"
91
92 /* VARIABLES - JONAS (31.07.2001) */
93
94 #if MEMDEBUG
95 extern unsigned long int G_Leaks;
96 extern unsigned long int G_LeaksSize;
97 #endif
98
99 #if ARES
100 extern ares_channel Ares_Channel;
101 #endif
102
103 extern struct Conf_Struct ConfS;
104 extern struct Conn_Struct *Conn_Head;
105
106 /* CLIENT_PARSE FUNCTION - JONAS (18.07.2001) */
107
client_parse(struct Client_Struct * ClientS)108 void client_parse(struct Client_Struct *ClientS) {
109
110 char *BufferPT = NULL;
111 char *LinePT = NULL;
112 unsigned long int Count = 0;
113 unsigned long int Len = 0;
114 char *TempPT = NULL;
115
116 BufferPT = ClientS->RecvBuffer;
117
118 for (Count = 1 ; BufferPT != NULL ; Count++) {
119 TempPT = strchr(BufferPT, '\n');
120 if (TempPT == NULL) {
121 if (Count == 1) { return; }
122 Len = strlen(BufferPT) + 1;
123 memmove(ClientS->RecvBuffer, BufferPT, Len);
124 TempPT = realloc(ClientS->RecvBuffer, Len);
125 if (TempPT == NULL) {
126 client_close(ClientS, "Memory allocation failure: [%d] %s", errno, strerror(errno));
127 return;
128 }
129 ClientS->RecvBuffer = TempPT;
130 return;
131 }
132 LinePT = strtok(BufferPT, "\n");
133 BufferPT = strtok(NULL, "\0");
134 if (LinePT == NULL) { continue; }
135 Len = strlen(LinePT);
136 if (LinePT[Len-1] == '\r') { LinePT[Len-1] = '\0'; }
137 client_parse_message(ClientS, LinePT);
138 if (ClientS->RecvBuffer == NULL) { return; }
139 }
140 FREE(ClientS->RecvBuffer);
141
142 }
143
144 /* CLIENT_PARSE_MESSAGE FUNCTION - JONAS (17.07.2001) */
145
client_parse_message(struct Client_Struct * ClientS,char * MessagePT)146 void client_parse_message(struct Client_Struct *ClientS, char *MessagePT) {
147
148 char *PrefixPT = NULL;
149 char *LinePT = NULL;
150 char *CommandPT = NULL;
151 char **ParamsPT = NULL;
152 char **TempPT = NULL;
153 unsigned short int Index = 0;
154 unsigned short int Params = 0;
155 time_t Duration = 0;
156
157 Duration = (NOW - ClientS->LineTime);
158 if (Duration >= ConfS.ClientLineFloodTTL) { ClientS->Lines = 0; }
159
160 ++ClientS->Lines;
161 if (ClientS->Lines >= ConfS.ClientMaxLines) {
162 client_close(ClientS, ACCESS_CONF_USERFLOOD);
163 access_conf_adddeny(ClientS->HostName, ACCESS_CONF_USERFLOOD);
164 return;
165 }
166 ClientS->LineTime = NOW;
167
168 while (MessagePT[0] == ' ') { MessagePT++; }
169 if (MessagePT[0] == '\0') { return; }
170
171 if (MessagePT[0] == ':') {
172 MessagePT++;
173 PrefixPT = MessagePT;
174 MessagePT = strchr(MessagePT, ' ');
175 if (MessagePT == NULL) { return; }
176 MessagePT[0] = '\0';
177 MessagePT++;
178 while (MessagePT[0] == ' ') { MessagePT++; }
179 if (MessagePT[0] == '\0') { return; }
180 }
181 else {
182 if (ClientS->User == NULL) { PrefixPT = "*"; }
183 else { PrefixPT = ClientS->User; }
184 }
185
186 LinePT = strdup(MessagePT);
187 if (LinePT == NULL) {
188 client_close(ClientS, "Memory allocation failure: [%d] %s", errno, strerror(errno));
189 return;
190 }
191
192 CommandPT = MessagePT;
193 MessagePT = strchr(MessagePT, ' ');
194 if (MessagePT != NULL) {
195 MessagePT[0] = '\0';
196 MessagePT++;
197 while (MessagePT[0] == ' ') { MessagePT++; }
198 if (MessagePT[0] == '\0') {
199 free(LinePT);
200 return;
201 }
202
203 FOREVERLOOP {
204 if (MessagePT[0] == ':') {
205 MessagePT++;
206 ++Params;
207 TempPT = realloc(ParamsPT, (sizeof(char *) * Params));
208 if (TempPT == NULL) {
209 client_close(ClientS, "Memory allocation failure: [%d] %s", errno, strerror(errno));
210 free(ParamsPT);
211 free(LinePT);
212 return;
213 }
214 ParamsPT = TempPT;
215 ParamsPT[Index] = MessagePT;
216 break;
217 }
218 else {
219 ++Params;
220 TempPT = realloc(ParamsPT, (sizeof(char *) * Params));
221 if (TempPT == NULL) {
222 client_close(ClientS, "Memory allocation failure: [%d] %s", errno, strerror(errno));
223 free(ParamsPT);
224 free(LinePT);
225 return;
226 }
227 ParamsPT = TempPT;
228 ParamsPT[Index] = MessagePT;
229 ++Index;
230 MessagePT = strchr(MessagePT, ' ');
231 if (MessagePT == NULL) { break; }
232 MessagePT[0] = '\0';
233 MessagePT++;
234 while (MessagePT[0] == ' ') { MessagePT++; }
235 if (MessagePT[0] == '\0') { break; }
236 }
237 }
238 }
239
240 strupper(CommandPT);
241
242 client_parse_command(ClientS, LinePT, CommandPT, ParamsPT, Params);
243
244 free(LinePT);
245 free(ParamsPT);
246
247 }
248
249 /* CLIENT_PARSE_COMMAND FUNCTION - JONAS (17.07.2001) */
250
client_parse_command(struct Client_Struct * ClientS,char * LinePT,char * CommandPT,char ** ParamsPT,const unsigned short int Params)251 void client_parse_command(struct Client_Struct *ClientS, char *LinePT, char *CommandPT, char **ParamsPT, const unsigned short int Params) {
252
253 if (!Client_IsVerified(ClientS)) {
254 if (strcasecmp(CommandPT, "PASS") == FALSE) {
255 if (Params < 1) { client_notice(ClientS, "%s :Not enough parameters.", CommandPT); return; }
256 ClientS->Pass = strrealloc(ClientS->Pass, ParamsPT[0]);
257 }
258 else if (strcasecmp(CommandPT, "NICK") == FALSE) {
259 if (Params < 1) { client_notice(ClientS, "%s :Not enough parameters.", CommandPT); return; }
260 ClientS->Nick = strrealloc(ClientS->Nick, ParamsPT[0]);
261 if ((ClientS->Pass == NULL) && (ClientS->User != NULL)) {
262 client_notice(ClientS, "Your IRC client did not send a password, type: /PASS <password> to connect.");
263 }
264 }
265 else if (strcasecmp(CommandPT, "USER") == FALSE) {
266 if (Params < 4) { client_notice(ClientS, "%s :Not enough parameters.", CommandPT); return; }
267 ClientS->User = strrealloc(ClientS->User, ParamsPT[0]);
268 if ((ClientS->Pass == NULL) && (ClientS->Nick != NULL)) {
269 client_notice(ClientS, "Your IRC client did not send a password, type: /PASS <password> to connect.");
270 }
271 }
272 else { client_addsend(ClientS, ":%s %.3d * :You have not registered.", IRCP_USER_HOST(ClientS), IRC_RFC1459_ERR_NOTREGISTERED); }
273
274 if ((ClientS->User != NULL) && (ClientS->Pass != NULL)) {
275
276 assert(geteuid() != 0);
277 client_authcheck(ClientS->User, ClientS->Pass);
278 assert(geteuid() != 0);
279 if (aerrno != AESUCCESS) {
280 client_close(ClientS, "USER / PASS is incorrect.");
281 return;
282 }
283
284 sysprint(BITMASK_MAIN, "Client %s (%s) sucessfully authenticated as \"%s\".", ClientS->HostName, ClientS->HostIPS, ClientS->User);
285 client_noticeallbutone(ClientS, "Client %s (%s) authenticated as \"%s\".", ClientS->HostName, ClientS->HostIPS, ClientS->User);
286
287 Client_SetVerified(ClientS);
288 client_welcome(ClientS);
289
290 return;
291 }
292 return;
293 }
294
295 if (strcasecmp(CommandPT, "PCONNLIST") == FALSE) {
296
297 struct Conn_Struct *ConnS = NULL;
298 struct ConnServer_Struct *ConnServer = NULL;
299 unsigned short int Count = 0;
300
301 for (ConnS = Conn_Head ; ConnS != NULL ; ConnS = ConnS->Next) {
302
303 if (strcmp(ConnS->User, ClientS->User) != FALSE) { continue; }
304 ++Count;
305
306 client_notice(ClientS, "\2Connection: %s Host: %s\2", ConnS->Name, ConnS->Host);
307
308 if (Host_IsResolving(ConnS->ResolveFlags)) { client_notice(ClientS, "--- Status: Resolving local hostname %s to IP-address.", ConnS->HostName); }
309 else if (Host_IsResolving(ConnS->ServerResolveFlags)) { client_notice(ClientS, "--- Status: Resolving server nostname %s to IP-address.", ConnS->ServerHostName); }
310 else if (Conn_IsConnecting(ConnS)) { client_notice(ClientS, "--- Status: Connecting to %s(%s):%ld.", ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH); }
311 else if (Conn_IsWelcome(ConnS)) { client_notice(ClientS, "--- Status: Connected to %s(%s):%ld \"%s\".", ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, ConnS->ServerName); }
312 else if (Conn_IsConnected(ConnS)) { client_notice(ClientS, "--- Status: Socket connected to %s(%s):%ld.", ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH); }
313 else { client_notice(ClientS, "--- Status: Disconnected."); }
314
315 if (ConnS->Server_Head == NULL) { client_notice(ClientS, "--- No servers!"); }
316 else {
317 for (ConnServer = ConnS->Server_Head ; ConnServer != NULL ; ConnServer = ConnServer->Next) {
318 client_notice(ClientS, "--- Server: %s Port: %ld", ConnServer->Host, ConnServer->Port);
319 }
320 }
321
322 }
323
324 if (Count == 0) {
325 client_notice(ClientS, "You have no connections.");
326 }
327
328 return;
329
330 }
331 else if (strcasecmp(CommandPT, "PCONNECT") == FALSE) {
332
333 struct Conn_Struct *ConnS = NULL;
334
335 if (Params < 1) {
336 if (ClientS->ConnS == NULL) { client_notice(ClientS, "Usage: PCONNECT <Connection name> [Connection server]."); return; }
337 ConnS = ClientS->ConnS;
338 }
339 else { ConnS = conn_get(ParamsPT[0]); }
340
341 if (ConnS == NULL) { client_notice(ClientS, "No such connection, use /PCONNLIST to list your connections."); return; }
342
343 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
344
345 if (Params >= 2) {
346 for (ConnS->ConnServerTry = ConnS->Server_Head ; ConnS->ConnServerTry != NULL ; ConnS->ConnServerTry = ConnS->ConnServerTry->Next) {
347 if (strwm(ParamsPT[1], ConnS->ConnServerTry->Host) == TRUE) { break; }
348 }
349 if (ConnS->ConnServerTry == NULL) { client_notice(ClientS, "No such server for that connection."); return; }
350 }
351 if (Host_IsResolving(ConnS->ResolveFlags)) {
352 if (ConnS->ConnServerTry == NULL) { client_notice(ClientS, "Connection %s: Resolving local hostname %s to IP-address.", ConnS->Name, ConnS->HostName); return; }
353 #if HAVE_ARES_CANCELQUERY
354 ares_cancelquery(Ares_Channel, ConnS);
355 #endif
356 return;
357 }
358 else if (Host_IsResolving(ConnS->ServerResolveFlags)) {
359 if (ConnS->ConnServerTry == NULL) { client_notice(ClientS, "Connection %s: Resolving server hostname %s to IP-address.", ConnS->Name, ConnS->ServerHostName); return; }
360 #if HAVE_ARES_CANCELQUERY
361 ares_cancelquery(Ares_Channel, ConnS);
362 #endif
363 return;
364 }
365 else if (Conn_IsConnecting(ConnS)) {
366 if (ConnS->ConnServerTry == NULL) { client_notice(ClientS, "%s: Connecting to %s(%s):%ld.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH); return; }
367 conn_disconnect(ConnS, "Connection %s: Connection attempt to %s(%s):%ld cancelled by user %s(%s).", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, ClientS->HostName, ClientS->HostIPS);
368 return;
369 }
370 else if (Conn_IsWelcome(ConnS)) {
371 if ((ConnS->ConnServerTry == NULL) || (strcasecmp(ConnS->ServerHostName, ConnS->ConnServerTry->Host) == FALSE)) { client_notice(ClientS, "Connection %s: Already connected to %s, use PQUIT to quit.", ConnS->Name, ConnS->ServerHostName); return; }
372 conn_quit(ConnS, "Changing server to %s.", ConnS->ConnServerTry->Host);
373 return;
374 }
375 else if (Conn_IsConnected(ConnS)) {
376 if (ConnS->ConnServerTry == NULL) { client_notice(ClientS, "Connection %s: Socket connected to %s(%s):%ld.", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH); return; }
377 conn_disconnect(ConnS, "Connection %s attempt to %s(%s):%ld cancelled by user %s(%s).", ConnS->Name, ConnS->ServerHostName, ConnS->ServerHostIPS, ConnS->ServerPortH, ClientS->HostName, ClientS->HostIPS);
378 return;
379 }
380
381 #if SSL_SUPPORT
382 conn_connect(ConnS);
383 #else
384 if (!ConnConf_IsSSL(ConnS)) { conn_connect(ConnS); }
385 else { client_notice(ClientS, "Connection %s: SSL is enabled for this connection, but %s is compiled without SSL support.", ConnS->Name, PACKAGE); }
386 #endif
387 return;
388
389 }
390 else if (strcasecmp(CommandPT, "PQUIT") == FALSE) {
391
392 struct Conn_Struct *ConnS = NULL;
393
394 if (Params >= 1) {
395 ConnS = conn_get(ParamsPT[0]);
396 if (ConnS == NULL) { client_notice(ClientS, "No such connection, eventually use /PCONNLIST to list your connections."); return; }
397 }
398 else {
399 ConnS = ClientS->ConnS;
400 if (ConnS == NULL) { client_notice(ClientS, "Usage: PQUIT <Connection name>"); return; }
401 }
402
403 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
404
405 if (Conn_IsConnect(ConnS)) {
406 if (Conn_IsWelcome(ConnS)) {
407 if (Conn_IsSentQuit(ConnS)) { conn_disconnect(ConnS, "Connection %s to server %s aborted by user %s (%s[%s]).", ConnS->Name, ConnS->ServerHostName, ClientS->User, ClientS->HostName, ClientS->HostIPS); return; }
408 else { conn_quit(ConnS, "%s (%s[%s]) requested QUIT.", ClientS->User, ClientS->HostName, ClientS->HostIPS); }
409 }
410 else { conn_disconnect(ConnS, "Connection %s to server %s aborted by user %s (%s[%s]).", ConnS->Name, ConnS->ServerHostName, ClientS->User, ClientS->HostName, ClientS->HostIPS); return; }
411 }
412 else { client_notice(ClientS, "Connection %s is not connected.", ConnS->Name); return; }
413
414 return;
415
416 }
417 else if ((strcasecmp(CommandPT, "PATTACH") == FALSE) || (strcasecmp(CommandPT, "PRESUME") == FALSE)) {
418
419 struct Conn_Struct *ConnS = NULL;
420
421 if (ClientS->ConnS != NULL) { client_notice(ClientS, "You are already attached on connection %s.", ClientS->ConnS->Name); return; }
422 if (Params < 1) { client_notice(ClientS, "Usage: PATTACH <Connection name>"); return; }
423 ConnS = conn_get(ParamsPT[0]);
424 if (ConnS == NULL) { client_notice(ClientS, "No such connection."); return; }
425 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
426 client_attach(ClientS, ConnS);
427
428 }
429 else if (strcasecmp(CommandPT, "PDETACH") == FALSE) {
430 if (ClientS->ConnS == NULL) { client_notice(ClientS, "You have no attached connection."); return; }
431 client_detach(ClientS);
432 }
433 else if (strcasecmp(CommandPT, "QUIT") == FALSE) {
434 client_close(ClientS, "Client sent QUIT.");
435 }
436 else if (strcasecmp(CommandPT, "PING") == FALSE) {
437 if (Params < 1) { client_notice(ClientS, "%s :Not enough parameters.", CommandPT); return; }
438 client_addsend(ClientS, ":%s PONG %s :%s", IRCP_USER_HOST(ClientS), IRCP_USER_HOST(ClientS), ParamsPT[0]);
439 /* client_addsend(ClientS, "PONG :%s", ParamsPT[0]); */
440 }
441 else if (strcasecmp(CommandPT, "PONG") == FALSE) {
442 Client_ClearSentPing(ClientS);
443 }
444 else if (strcasecmp(CommandPT, "QUOTE") == FALSE) {
445
446 char *DumbPT = NULL;
447
448 if (ClientS->ConnS == NULL) { client_notice(ClientS, "QUOTE: No attached connection."); return; }
449 if (!Conn_IsConnected(ClientS->ConnS)) { client_notice(ClientS, "Connection %s not established.", ClientS->ConnS->Name); return; }
450
451 DumbPT = strchr(LinePT, ' ');
452 DumbPT++;
453 conn_addsendq(ClientS->ConnS, "%s", DumbPT);
454 }
455
456 else if (strcasecmp(CommandPT, "LOGLIST") == FALSE) {
457
458 struct Conn_Struct *ConnS = NULL;
459 struct ConnLog_Struct *ConnLog = NULL;
460 unsigned long int LogFiles = 0;
461 char *LogFilePT = NULL;
462
463 if (Params < 2) {
464 ConnS = ClientS->ConnS;
465 if (Params < 1) LogFilePT = "*";
466 else LogFilePT = ParamsPT[0];
467 }
468 else {
469 ConnS = conn_get(ParamsPT[0]);
470 if (ConnS == NULL) { client_notice(ClientS, "No such connection, eventually use /PCONNLIST to list your connections."); return; }
471 LogFilePT = ParamsPT[1];
472 }
473
474 if (ConnS == NULL) { client_notice(ClientS, "Usage: READLOG <Connection name> <Logfile>"); return; }
475
476 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
477
478 if (ConnS->NumLogs == 0) { client_notice(ClientS, "No logs for connection %s.", ConnS->Name); return; }
479
480 for (ConnLog = ConnS->Log_Head ; ConnLog != NULL ; ConnLog = ConnLog->Next) {
481 if (((ConnLog->LogType != CONN_LOG_TYPE_PRIV) && (ConnLog->LogType != CONN_LOG_TYPE_CHAN)) || (strwm(LogFilePT, ConnLog->Name) == FALSE)) { continue; }
482 LogFiles++;
483 client_addsend(ClientS, ":%s PRIVMSG %s :%s", IRCP_USER_HOST(ClientS), IRCP_USER_NICK(ClientS), ConnLog->LogFile);
484 }
485
486 if (LogFiles == 0) { client_notice(ClientS, "No private logs for connection %s matching your query.", ConnS->Name); return; }
487 else { client_notice(ClientS, "%ld logfiles.", LogFiles); return; }
488
489 }
490
491 else if (strcasecmp(CommandPT, "READLOG") == FALSE) {
492
493 FILE *FilePT = NULL;
494 struct Conn_Struct *ConnS = NULL;
495 struct ConnLog_Struct *ConnLog = NULL;
496 unsigned long int LogFiles = 0;
497 unsigned long int LogLines = 0;
498 char *LogFilePT = NULL;
499
500 if (Params < 2) {
501 ConnS = ClientS->ConnS;
502 if (Params < 1) LogFilePT = "*";
503 else LogFilePT = ParamsPT[0];
504 }
505 else {
506 ConnS = conn_get(ParamsPT[0]);
507 if (ConnS == NULL) { client_notice(ClientS, "No such connection, eventually use /PCONNLIST to list your connections."); return; }
508 LogFilePT = ParamsPT[1];
509 }
510
511 if (ConnS == NULL) { client_notice(ClientS, "Usage: READLOG <Connection name> <Logfile>"); return; }
512
513 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
514
515 if (ConnS->NumLogs == 0) { client_notice(ClientS, "No logs for connection %s.", ConnS->Name); return; }
516
517 #if !WIN32
518 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidbyuser(ConnS->User); }
519 #endif
520
521 for (ConnLog = ConnS->Log_Head ; ConnLog != NULL ; ConnLog = ConnLog->Next) {
522 if ((ConnLog->LogType != CONN_LOG_TYPE_PRIV) || (strwm(LogFilePT, ConnLog->Name) == FALSE)) { continue; }
523 LogFiles++;
524
525 FilePT = fopen(ConnLog->LogFileFullPath, "r");
526 if (FilePT == NULL) {
527 sysprint(BITMASK_ERROR, "Unable to open %s for reading: [%d] %s", ConnLog->LogFileFullPath, errno, strerror(errno));
528 client_notice(ClientS, "Unable to open %s for reading: [%d] %s", ConnLog->LogFileFullPath, errno, strerror(errno));
529 #if !WIN32
530 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidnormal(); }
531 #endif
532 continue;
533 }
534
535 do {
536 char Line[LINELEN+1] = "";
537 char *LinePT = NULL;
538 char *TempPT = NULL;
539 memset(&Line, 0, LINELEN+1);
540 LinePT = fgets(Line, LINELEN, FilePT);
541 if (LinePT == NULL) { break; }
542 while ((TempPT = strchr(LinePT, '\r')) != NULL) { *TempPT = '\0'; }
543 while ((TempPT = strchr(LinePT, '\n')) != NULL) { *TempPT = '\0'; }
544 LogLines++;
545 client_addsend(ClientS, ":%s PRIVMSG %s :%s: %s", IRCP_USER_HOST(ClientS), IRCP_USER_NICK(ClientS), ConnLog->LogFile, LinePT);
546 } while(1);
547 fclose(FilePT);
548 }
549
550 #if !WIN32
551 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidnormal(); }
552 #endif
553
554 if (LogFiles == 0) { client_notice(ClientS, "No private logs for connection %s matching your query.", ConnS->Name); return; }
555 else { client_notice(ClientS, "Dumped %ld lines of %ld log files using PRIVMSG.", LogLines, LogFiles); return; }
556
557 }
558 else if (strcasecmp(CommandPT, "ERASELOG") == FALSE) {
559
560 struct Conn_Struct *ConnS = NULL;
561 struct ConnLog_Struct *ConnLog = NULL;
562 unsigned long int LogFiles = 0;
563 char *LogFilePT = NULL;
564 signed long int Result = 0;
565
566 if (Params < 2) {
567 ConnS = ClientS->ConnS;
568 if (Params < 1) LogFilePT = "*";
569 else LogFilePT = ParamsPT[0];
570 }
571 else {
572 ConnS = conn_get(ParamsPT[0]);
573 if (ConnS == NULL) { client_notice(ClientS, "No such connection, eventually use /PCONNLIST to list your connections."); return; }
574 LogFilePT = ParamsPT[1];
575 }
576
577 if (ConnS == NULL) { client_notice(ClientS, "Usage: ERASELOG <Connection name> <Logfile>"); return; }
578
579 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
580
581 if (ConnS->NumLogs == 0) { client_notice(ClientS, "No logs for connection %s.", ConnS->Name); return; }
582
583 #if !WIN32
584 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidbyuser(ConnS->User); }
585 #endif
586
587 for (ConnLog = ConnS->Log_Head ; ConnLog != NULL ;) {
588 char ResultStr[RECVBUFFERLEN+1] = "";
589 char RunCmd[LINELEN+1] = "";
590 char *TempPT = NULL;
591 if ((ConnLog->LogType != CONN_LOG_TYPE_PRIV) || (strwm(LogFilePT, ConnLog->LogFile) == FALSE)) {
592 ConnLog = ConnLog->Next;
593 continue;
594 }
595 LogFiles++;
596 if ((ConnS->PrivLogFile != NULL) && (strcasecmp(ConnLog->LogFile, ConnS->PrivLogFile) == FALSE)) {
597 FREE(ConnS->PrivLogFile);
598 fclose(ConnS->PrivLogFileFP);
599 ConnS->PrivLogFileFP = NULL;
600 }
601 snprintf(RunCmd, LINELEN+1, "rm %s", ConnLog->LogFileFullPath);
602 Result = sysrun(RunCmd, ResultStr, LINELEN);
603 while ((TempPT = strchr(ResultStr, '\n'))) { *TempPT = '\0'; }
604 if (Result <= ERROR) {
605 client_notice(ClientS, "Unable to remove logfile %s.: [%d] %s", ConnLog->LogFile, errno, strerror(errno));
606 ConnLog = ConnLog->Next;
607 }
608 else {
609 struct ConnLog_Struct *ConnLog_DEL = ConnLog;
610 ConnLog = ConnLog->Next;
611 client_notice(ClientS, "Removed logfile %s.", ConnLog_DEL->LogFile);
612 conn_remlog(ConnS, ConnLog_DEL);
613 }
614 }
615
616 #if !WIN32
617 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidnormal(); }
618 #endif
619
620 if (LogFiles == 0) { client_notice(ClientS, "No private logs for connection %s matching your query.", ConnS->Name); return; }
621
622 return;
623
624 }
625
626 else if (strcasecmp(CommandPT, "READCHANLOG") == FALSE) {
627
628 FILE *FilePT = NULL;
629 struct Conn_Struct *ConnS = NULL;
630 struct ConnLog_Struct *ConnLog = NULL;
631 unsigned long int LogFiles = 0;
632 unsigned long int LogLines = 0;
633 char *LogFilePT = NULL;
634
635 if (Params < 2) {
636 ConnS = ClientS->ConnS;
637 if (Params < 1) LogFilePT = "*";
638 else LogFilePT = ParamsPT[0];
639 }
640 else {
641 ConnS = conn_get(ParamsPT[0]);
642 if (ConnS == NULL) { client_notice(ClientS, "No such connection, eventually use /PCONNLIST to list your connections."); return; }
643 LogFilePT = ParamsPT[1];
644 }
645
646 if (ConnS == NULL) { client_notice(ClientS, "Usage: READCHANLOG <Connection name> <Logfile>"); return; }
647
648 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
649
650 if (ConnS->NumLogs == 0) { client_notice(ClientS, "No logs for connection %s.", ConnS->Name); return; }
651
652 #if !WIN32
653 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidbyuser(ConnS->User); }
654 #endif
655
656 for (ConnLog = ConnS->Log_Head ; ConnLog != NULL ; ConnLog = ConnLog->Next) {
657 if ((ConnLog->LogType != CONN_LOG_TYPE_CHAN) || (strwm(LogFilePT, ConnLog->Name) == FALSE)) { continue; }
658 LogFiles++;
659
660 FilePT = fopen(ConnLog->LogFileFullPath, "r");
661 if (FilePT == NULL) {
662 sysprint(BITMASK_ERROR, "Unable to open %s for reading: [%d] %s", ConnLog->LogFileFullPath, errno, strerror(errno));
663 client_notice(ClientS, "Unable to open %s for reading: [%d] %s", ConnLog->LogFileFullPath, errno, strerror(errno));
664 #if !WIN32
665 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidnormal(); }
666 #endif
667 continue;
668 }
669
670 do {
671 char Line[LINELEN+1] = "";
672 char *LinePT = NULL;
673 char *TempPT = NULL;
674 memset(&Line, 0, LINELEN+1);
675 LinePT = fgets(Line, LINELEN, FilePT);
676 if (LinePT == NULL) { break; }
677 while ((TempPT = strchr(LinePT, '\r')) != NULL) { *TempPT = '\0'; }
678 while ((TempPT = strchr(LinePT, '\n')) != NULL) { *TempPT = '\0'; }
679 LogLines++;
680 client_addsend(ClientS, ":%s PRIVMSG %s :%s: %s", IRCP_USER_HOST(ClientS), IRCP_USER_NICK(ClientS), ConnLog->LogFile, LinePT);
681 } while(1);
682 fclose(FilePT);
683 }
684
685 #if !WIN32
686 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidnormal(); }
687 #endif
688
689 if (LogFiles == 0) { client_notice(ClientS, "No private logs for connection %s matching your query.", ConnS->Name); return; }
690 else { client_notice(ClientS, "Dumped %ld lines of %ld log files using PRIVMSG.", LogLines, LogFiles); return; }
691
692 }
693 else if (strcasecmp(CommandPT, "ERASECHANLOG") == FALSE) {
694
695 struct Conn_Struct *ConnS = NULL;
696 struct ConnLog_Struct *ConnLog = NULL;
697 unsigned long int LogFiles = 0;
698 char *LogFilePT = NULL;
699 signed long int Result = 0;
700 struct Chan_Struct *ChanS = NULL;
701
702 if (Params < 2) {
703 ConnS = ClientS->ConnS;
704 if (Params < 1) LogFilePT = "*";
705 else LogFilePT = ParamsPT[0];
706 }
707 else {
708 ConnS = conn_get(ParamsPT[0]);
709 if (ConnS == NULL) { client_notice(ClientS, "No such connection, eventually use /PCONNLIST to list your connections."); return; }
710 LogFilePT = ParamsPT[1];
711 }
712
713 if (ConnS == NULL) { client_notice(ClientS, "Usage: ERASECHANLOG <Connection name> <Logfile>"); return; }
714
715 if (strcmp(ConnS->User, ClientS->User) != FALSE) { client_notice(ClientS, "Permission denied, You're not the owner of connection %s.", ConnS->Name); return; }
716
717 if (ConnS->NumLogs == 0) { client_notice(ClientS, "No logs for connection %s.", ConnS->Name); return; }
718
719 #if !WIN32
720 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidbyuser(ConnS->User); }
721 #endif
722
723 for (ConnLog = ConnS->Log_Head ; ConnLog != NULL ;) {
724 char ResultStr[RECVBUFFERLEN+1] = "";
725 char RunCmd[LINELEN+1] = "";
726 char *TempPT = NULL;
727 if ((ConnLog->LogType != CONN_LOG_TYPE_CHAN) || (strwm(LogFilePT, ConnLog->LogFile) == FALSE)) {
728 ConnLog = ConnLog->Next;
729 continue;
730 }
731 LogFiles++;
732 for (ChanS = ConnS->Chan_Head ; ChanS != NULL ; ChanS = ChanS->Next) {
733 if ((ConnLog->LogFile != NULL) && (ChanS->LogFile != NULL) && (strcasecmp(ConnLog->LogFile, ChanS->LogFile) == FALSE)) {
734 FREE(ChanS->LogFile);
735 fclose(ChanS->LogFileFP);
736 ChanS->LogFileFP = NULL;
737 }
738 }
739 snprintf(RunCmd, LINELEN+1, "rm %s", ConnLog->LogFileFullPath);
740 Result = sysrun(RunCmd, ResultStr, LINELEN);
741 while ((TempPT = strchr(ResultStr, '\n'))) { *TempPT = '\0'; }
742 if (Result <= ERROR) {
743 client_notice(ClientS, "Unable to remove logfile %s.: [%d] %s", ConnLog->LogFile, errno, strerror(errno));
744 ConnLog = ConnLog->Next;
745 }
746 else {
747 struct ConnLog_Struct *ConnLog_DEL = ConnLog;
748 ConnLog = ConnLog->Next;
749 client_notice(ClientS, "Removed logfile %s.", ConnLog_DEL->LogFile);
750 conn_remlog(ConnS, ConnLog_DEL);
751 }
752 }
753
754 #if !WIN32
755 if (Conn_IsLogHomeDir(ConnS)) { sysseteuidnormal(); }
756 #endif
757
758 if (LogFiles == 0) { client_notice(ClientS, "No channel logs for connection %s matching your query.", ConnS->Name); return; }
759
760 return;
761
762 }
763
764 #if MEMDEBUG
765 else if (strcasecmp(CommandPT, "MEMLEAKS") == FALSE) {
766 client_notice(ClientS, "Calculating memory leaks...");
767 mem_leaks();
768 if (G_Leaks > 1 ) {
769 client_notice(ClientS, "Memory leaks: %ld size: %ld", G_Leaks, G_LeaksSize);
770 client_notice(ClientS, "!!! MEMORY LEAKS FOUND --- LOOK IN THE ERROR LOG !!!");
771 }
772 else { client_notice(ClientS, "No memory leaks found! IGNORE 1 FAKE MEMLEAK IN client_io.c!"); }
773 }
774 #endif
775 else {
776 if (ClientS->ConnS == NULL) { client_notice(ClientS, "No attached connection, use PATTACH to attach first."); }
777 else {
778 if (Conn_IsConnect(ClientS->ConnS)) {
779 if (Conn_IsWelcome(ClientS->ConnS)) {
780 if ((!strcasecmp(CommandPT, "WHO")) && (Params >= 1)) {
781 struct Chan_Struct *ChanS;
782 struct Who_Struct *WhoS;
783 ChanS = chan_get(ClientS->ConnS, ParamsPT[0]);
784 if (ChanS != NULL) {
785 WhoS = malloc(sizeof(struct Who_Struct));
786 if (WhoS != NULL) {
787 memset(WhoS, 0, sizeof(struct Who_Struct));
788 WhoS->PrevForClient = NULL;
789 WhoS->NextForClient = ClientS->Who_Head;
790 if (WhoS->NextForClient != NULL) { WhoS->NextForClient->PrevForClient = WhoS; }
791 ClientS->Who_Head = WhoS;
792 WhoS->NextForChan = ChanS->Who_Head;
793 ChanS->Who_Head = WhoS;
794 WhoS->ClientS = ClientS;
795 }
796 }
797 }
798 }
799 conn_addsendq(ClientS->ConnS, "%s", LinePT);
800 }
801 else { client_notice(ClientS, "Attached connection not established."); }
802 }
803 }
804 }
805