]>
Commit | Line | Data |
---|---|---|
3bd189cb JR |
1 | /* |
2 | * IRC - Internet Relay Chat, common/send.c | |
3 | * Copyright (C) 1990 Jarkko Oikarinen and | |
4 | * University of Oulu, Computing Center | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 1, or (at your option) | |
9 | * any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
20 | ||
21 | #ifndef lint | |
22 | static const volatile char rcsid[] = "@(#)$Id: send.c,v 1.108 2008/06/08 17:17:10 chopin Exp $"; | |
23 | #endif | |
24 | ||
25 | #include "os.h" | |
26 | #include "s_defines.h" | |
27 | #define SEND_C | |
28 | #include "s_externs.h" | |
29 | #undef SEND_C | |
30 | ||
31 | static char sendbuf[2048]; | |
32 | ||
33 | ||
34 | static void vsendto_prefix_one(aClient *, aClient *, char *, va_list); | |
35 | static char psendbuf[2048]; | |
36 | static int sentalong[MAXCONNECTIONS]; | |
37 | ||
38 | /* | |
39 | ** dead_link | |
40 | ** An error has been detected. The link *must* be closed, | |
41 | ** but *cannot* call ExitClient (m_bye) from here. | |
42 | ** Instead, mark it with FLAGS_DEADSOCK. This should | |
43 | ** generate ExitClient from the main loop. | |
44 | ** | |
45 | ** The notice is skipped for "uninteresting" cases, | |
46 | ** like Persons and yet unknown connections... | |
47 | */ | |
48 | static int dead_link(aClient *to, char *pattern, ...) | |
49 | { | |
50 | char notice[BUFSIZE]; | |
51 | va_list va; | |
52 | ||
53 | va_start(va, pattern); | |
54 | vsprintf(notice, pattern, va); | |
55 | va_end(va); | |
56 | ||
57 | SetDead(to); | |
58 | /* | |
59 | * If because of BUFFERPOOL problem then clean dbufs now so that | |
60 | * notices don't hurt operators below. | |
61 | */ | |
62 | DBufClear(&to->recvQ); | |
63 | DBufClear(&to->sendQ); | |
64 | if (!IsPerson(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING)) | |
65 | sendto_flag(SCH_ERROR, notice); | |
66 | Debug((DEBUG_ERROR, notice)); | |
67 | return -1; | |
68 | } | |
69 | ||
70 | /* | |
71 | ** flush_fdary | |
72 | ** Used to empty all output buffers for connections in fdary. | |
73 | */ | |
74 | void flush_fdary(FdAry *fdp) | |
75 | { | |
76 | int i; | |
77 | aClient *cptr; | |
78 | ||
79 | for (i = 0; i <= fdp->highest; i++) | |
80 | { | |
81 | if (!(cptr = local[fdp->fd[i]])) | |
82 | continue; | |
83 | if (!IsRegistered(cptr)) /* is this needed?? -kalt */ | |
84 | continue; | |
85 | if (DBufLength(&cptr->sendQ) > 0) | |
86 | (void)send_queued(cptr); | |
87 | } | |
88 | } | |
89 | ||
90 | /* | |
91 | ** flush_connections | |
92 | ** Used to empty all output buffers for all connections. Should only | |
93 | ** be called once per scan of connections. There should be a select in | |
94 | ** here perhaps but that means either forcing a timeout or doing a poll. | |
95 | ** When flushing, all we do is empty the obuffer array for each local | |
96 | ** client and try to send it. if we can't send it, it goes into the sendQ | |
97 | ** -avalon | |
98 | */ | |
99 | void flush_connections(int fd) | |
100 | { | |
101 | Reg int i; | |
102 | Reg aClient *cptr; | |
103 | ||
104 | if (fd == me.fd) | |
105 | { | |
106 | for (i = highest_fd; i >= 0; i--) | |
107 | if ((cptr = local[i]) && DBufLength(&cptr->sendQ) > 0) | |
108 | (void)send_queued(cptr); | |
109 | } | |
110 | else if (fd >= 0 && (cptr = local[fd]) && DBufLength(&cptr->sendQ) > 0) | |
111 | (void)send_queued(cptr); | |
112 | } | |
113 | ||
114 | /* | |
115 | ** send_message | |
116 | ** Internal utility which delivers one message buffer to the | |
117 | ** socket. Takes care of the error handling and buffering, if | |
118 | ** needed. | |
119 | ** if ZIP_LINKS is defined, the message will eventually be compressed, | |
120 | ** anything stored in the sendQ is compressed. | |
121 | ** | |
122 | ** If msg is a null pointer, we are flushing connection | |
123 | */ | |
124 | int send_message(aClient *to, char *msg, int len) | |
125 | { | |
126 | int i; | |
127 | ||
128 | Debug((DEBUG_SEND,"Sending %s %d [%s] ", to->name, to->fd, msg)); | |
129 | ||
130 | if (to->from) | |
131 | to = to->from; | |
132 | if (to->fd < 0) | |
133 | { | |
134 | Debug((DEBUG_ERROR, | |
135 | "Local socket %s with negative fd... AARGH!", | |
136 | to->name)); | |
137 | } | |
138 | if (IsMe(to)) | |
139 | { | |
140 | sendto_flag(SCH_ERROR, "Trying to send to myself! [%s]", msg); | |
141 | return 0; | |
142 | } | |
143 | if (IsDead(to)) | |
144 | return 0; /* This socket has already been marked as dead */ | |
145 | if (DBufLength(&to->sendQ) > (i=get_sendq(to, CBurst(to)))) | |
146 | { | |
147 | to->exitc = EXITC_SENDQ; | |
148 | if (IsService(to) || IsServer(to)) | |
149 | { | |
150 | return dead_link(to, | |
151 | "Max SendQ limit exceeded for %s: %d > %d", | |
152 | get_client_name(to, FALSE), | |
153 | DBufLength(&to->sendQ), i); | |
154 | } | |
155 | return dead_link(to, "Max Sendq exceeded"); | |
156 | } | |
157 | # ifdef ZIP_LINKS | |
158 | /* | |
159 | ** data is first stored in to->zip->outbuf until | |
160 | ** it's big enough to be compressed and stored in the sendq. | |
161 | ** send_queued is then responsible to never let the sendQ | |
162 | ** be empty and to->zip->outbuf not empty. | |
163 | */ | |
164 | if (to->flags & FLAGS_ZIP) | |
165 | msg = zip_buffer(to, msg, &len, 0); | |
166 | ||
167 | # endif /* ZIP_LINKS */ | |
168 | tryagain: | |
169 | if (len && (i = dbuf_put(&to->sendQ, msg, len)) < 0) | |
170 | { | |
171 | if (i == -2 /* Poolsize was exceeded. */ | |
172 | #ifdef POOLSIZE_LIMITED | |
173 | /* | |
174 | ** Defining this retains old ircd behaviour (will | |
175 | ** allow client quit with buffer allocation error | |
176 | ** as a result of poolsize starvation). As it may | |
177 | ** happen to all clients on a big channel without | |
178 | ** their fault, I think this is not right. | |
179 | ** In the long run it should not matter (poolsize | |
180 | ** or memory usage-wise), because if client lacks | |
181 | ** the poolsize, the poolsize is too small anyway | |
182 | ** and next netburst would probably make it grow. | |
183 | ** IMO increasing poolsize with no limits is good | |
184 | ** for clients -- hence this is not defined. --B. | |
185 | */ | |
186 | && CBurst(to) | |
187 | #endif | |
188 | ) | |
189 | { | |
190 | /* Anyway, 10% increase. */ | |
191 | poolsize *= 1.1; | |
192 | sendto_flag(SCH_NOTICE, | |
193 | "New poolsize %u. (reached)", | |
194 | poolsize); | |
195 | istat.is_dbufmore++; | |
196 | goto tryagain; | |
197 | } | |
198 | else | |
199 | { | |
200 | to->exitc = EXITC_MBUF; | |
201 | return dead_link(to, | |
202 | "Buffer allocation error for %s", | |
203 | get_client_name(to, FALSE)); | |
204 | } | |
205 | } | |
206 | /* | |
207 | ** Update statistics. The following is slightly incorrect | |
208 | ** because it counts messages even if queued, but bytes | |
209 | ** only really sent. Queued bytes get updated in SendQueued. | |
210 | */ | |
211 | to->sendM += 1; | |
212 | me.sendM += 1; | |
213 | if (to->acpt != &me) | |
214 | to->acpt->sendM += 1; | |
215 | /* | |
216 | ** This little bit is to stop the sendQ from growing too large when | |
217 | ** there is no need for it to. Thus we call send_queued() every time | |
218 | ** 2k has been added to the queue since the last non-fatal write. | |
219 | ** Also stops us from deliberately building a large sendQ and then | |
220 | ** trying to flood that link with data (possible during the net | |
221 | ** relinking done by servers with a large load). | |
222 | */ | |
223 | if (DBufLength(&to->sendQ)/1024 > to->lastsq) | |
224 | send_queued(to); | |
225 | return 0; | |
226 | } | |
227 | ||
228 | /* | |
229 | ** send_queued | |
230 | ** This function is called from the main select-loop (or whatever) | |
231 | ** when there is a chance the some output would be possible. This | |
232 | ** attempts to empty the send queue as far as possible... | |
233 | */ | |
234 | int send_queued(aClient *to) | |
235 | { | |
236 | char *msg; | |
237 | int len, rlen, more = 0; | |
238 | aClient *bysptr = NULL; | |
239 | ||
240 | /* | |
241 | ** Once socket is marked dead, we cannot start writing to it, | |
242 | ** even if the error is removed... | |
243 | */ | |
244 | if (IsDead(to)) | |
245 | { | |
246 | /* | |
247 | ** Actually, we should *NEVER* get here--something is | |
248 | ** not working correct if send_queued is called for a | |
249 | ** dead socket... --msa | |
250 | */ | |
251 | return -1; | |
252 | } | |
253 | #ifdef ZIP_LINKS | |
254 | /* | |
255 | ** Here, we must make sure than nothing will be left in to->zip->outbuf | |
256 | ** This buffer needs to be compressed and sent if all the sendQ is sent | |
257 | */ | |
258 | if ((to->flags & FLAGS_ZIP) && to->zip->outcount) | |
259 | { | |
260 | if (DBufLength(&to->sendQ) > 0) | |
261 | more = 1; | |
262 | else | |
263 | { | |
264 | msg = zip_buffer(to, NULL, &len, 1); | |
265 | ||
266 | if (len == -1) | |
267 | return dead_link(to, | |
268 | "fatal error in zip_buffer()"); | |
269 | ||
270 | if (dbuf_put(&to->sendQ, msg, len) < 0) | |
271 | { | |
272 | to->exitc = EXITC_MBUF; | |
273 | return dead_link(to, | |
274 | "Buffer allocation error for %s", | |
275 | get_client_name(to, FALSE)); | |
276 | } | |
277 | } | |
278 | } | |
279 | #endif | |
280 | while (DBufLength(&to->sendQ) > 0 || more) | |
281 | { | |
282 | msg = dbuf_map(&to->sendQ, &len); | |
283 | /* Returns always len > 0 */ | |
284 | if ((rlen = deliver_it(to, msg, len)) < 0) | |
285 | { | |
286 | if ( (IsConnecting(to) || IsHandshake(to)) | |
287 | && to->serv && to->serv->byuid[0]) | |
288 | { | |
289 | bysptr = find_uid(to->serv->byuid, NULL); | |
290 | if (bysptr && !MyConnect(bysptr)) | |
291 | { | |
292 | sendto_one(bysptr, ":%s NOTICE %s :" | |
293 | "Write error (%s) to %s, closing link", | |
294 | ME, bysptr->name, strerror(-rlen), | |
295 | to->name); | |
296 | } | |
297 | } | |
298 | return dead_link(to, | |
299 | "Write error (%s) to %s, closing link", | |
300 | strerror(-rlen), get_client_name(to, FALSE)); | |
301 | } | |
302 | (void)dbuf_delete(&to->sendQ, rlen); | |
303 | to->lastsq = DBufLength(&to->sendQ)/1024; | |
304 | if (rlen < len) /* ..or should I continue until rlen==0? */ | |
305 | break; | |
306 | ||
307 | #ifdef ZIP_LINKS | |
308 | if (DBufLength(&to->sendQ) == 0 && more) | |
309 | { | |
310 | /* | |
311 | ** The sendQ is now empty, compress what's left | |
312 | ** uncompressed and try to send it too | |
313 | */ | |
314 | more = 0; | |
315 | msg = zip_buffer(to, NULL, &len, 1); | |
316 | ||
317 | if (len == -1) | |
318 | return dead_link(to, | |
319 | "fatal error in zip_buffer()"); | |
320 | ||
321 | if (dbuf_put(&to->sendQ, msg, len) < 0) | |
322 | { | |
323 | to->exitc = EXITC_MBUF; | |
324 | return dead_link(to, | |
325 | "Buffer allocation error for %s", | |
326 | get_client_name(to, FALSE)); | |
327 | } | |
328 | } | |
329 | #endif | |
330 | } | |
331 | ||
332 | return (IsDead(to)) ? -1 : 0; | |
333 | } | |
334 | ||
335 | ||
336 | static anUser ausr; | |
337 | static aClient anon; | |
338 | ||
339 | void initanonymous(void) | |
340 | { | |
341 | memset(&ausr, 0, sizeof(anUser)); | |
342 | strcpy(ausr.username, "anonymous"); | |
343 | strcpy(ausr.uid, "0ANONYM"); | |
344 | strcpy(ausr.host, "anonymous."); | |
345 | ausr.server = "anonymous."; | |
346 | ||
347 | memset(&anon, 0, sizeof(aClient)); | |
348 | anon.user = &ausr; | |
349 | anon.from = &anon; | |
350 | anon.fd = -2; | |
351 | anon.status = STAT_CLIENT; | |
352 | anon.name = anon.namebuf; | |
353 | strcpy(anon.namebuf, "anonymous"); | |
354 | strcpy(anon.username, "anonymous"); | |
355 | anon.info = "anonymous identity hider"; | |
356 | anon.exitc = EXITC_UNDEF; | |
357 | } | |
358 | ||
359 | /* | |
360 | * sendprep: takes care of building the string according to format & args | |
361 | */ | |
362 | static int vsendprep(char *pattern, va_list va) | |
363 | { | |
364 | int len; | |
365 | ||
366 | Debug((DEBUG_L10, "sendprep(%s)", pattern)); | |
367 | len = vsprintf(sendbuf, pattern, va); | |
368 | if (len > 510) | |
369 | #ifdef IRCII_KLUDGE | |
370 | len = 511; | |
371 | #else | |
372 | len = 510; | |
373 | sendbuf[len++] = '\r'; | |
374 | #endif | |
375 | sendbuf[len++] = '\n'; | |
376 | sendbuf[len] = '\0'; | |
377 | return len; | |
378 | } | |
379 | ||
380 | /* | |
381 | * sendpreprep: takes care of building the string according to format & args, | |
382 | * and of adding a complete prefix if necessary | |
383 | */ | |
384 | static int vsendpreprep(aClient *to, aClient *from, char *pattern, va_list va) | |
385 | { | |
386 | int len; | |
387 | ||
388 | Debug((DEBUG_L10, "sendpreprep(%#x(%s),%#x(%s),%s)", | |
389 | to, to->name, from, from->name, pattern)); | |
390 | if (to && from && MyClient(to) && IsPerson(from) && | |
391 | !strncmp(pattern, ":%s", 3)) | |
392 | { | |
393 | char *par = va_arg(va, char *); | |
394 | ||
395 | if (from == &anon || !mycmp(par, from->name)) | |
396 | { | |
397 | len = sprintf(psendbuf, ":%s!%s@%s", from->name, | |
398 | from->user->username, from->user->host); | |
399 | } | |
400 | else | |
401 | { | |
402 | len = sprintf(psendbuf, ":%s", par); | |
403 | } | |
404 | ||
405 | len += vsprintf(psendbuf+len, pattern+3, va); | |
406 | } | |
407 | else | |
408 | len = vsprintf(psendbuf, pattern, va); | |
409 | ||
410 | if (len > 510) | |
411 | #ifdef IRCII_KLUDGE | |
412 | len = 511; | |
413 | #else | |
414 | len = 510; | |
415 | psendbuf[len++] = '\r'; | |
416 | #endif | |
417 | psendbuf[len++] = '\n'; | |
418 | psendbuf[len] = '\0'; | |
419 | return len; | |
420 | } | |
421 | ||
422 | /* | |
423 | ** send message to single client | |
424 | */ | |
425 | int vsendto_one(aClient *to, char *pattern, va_list va) | |
426 | { | |
427 | int len; | |
428 | ||
429 | len = vsendprep(pattern, va); | |
430 | ||
431 | (void)send_message(to, sendbuf, len); | |
432 | return len; | |
433 | } | |
434 | ||
435 | int sendto_one(aClient *to, char *pattern, ...) | |
436 | { | |
437 | int len; | |
438 | va_list va; | |
439 | va_start(va, pattern); | |
440 | len = vsendto_one(to, pattern, va); | |
441 | va_end(va); | |
442 | return len; | |
443 | } | |
444 | ||
445 | /* | |
446 | * sendto_channel_butone | |
447 | * | |
448 | * Send a message to all members of a channel that are connected to this | |
449 | * server except client 'one'. | |
450 | */ | |
451 | void sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr, | |
452 | char *pattern, ...) | |
453 | { | |
454 | Reg Link *lp; | |
455 | Reg aClient *acptr, *lfrm = from; | |
456 | int len1, len2 = 0; | |
457 | ||
458 | if (IsAnonymous(chptr) && IsClient(from)) | |
459 | { | |
460 | lfrm = &anon; | |
461 | } | |
462 | ||
463 | if (one != from && MyConnect(from) && IsRegisteredUser(from)) | |
464 | { | |
465 | /* useless junk? */ /* who said that and why? --B. */ | |
466 | va_list va; | |
467 | va_start(va, pattern); | |
468 | vsendto_prefix_one(from, from, pattern, va); | |
469 | va_end(va); | |
470 | } | |
471 | ||
472 | { | |
473 | va_list va; | |
474 | va_start(va, pattern); | |
475 | len1 = vsendprep(pattern, va); | |
476 | va_end(va); | |
477 | } | |
478 | ||
479 | ||
480 | for (lp = chptr->clist; lp; lp = lp->next) | |
481 | { | |
482 | acptr = lp->value.cptr; | |
483 | if (acptr->from == one || IsMe(acptr)) | |
484 | continue; /* ...was the one I should skip */ | |
485 | if (MyConnect(acptr) && IsRegisteredUser(acptr)) | |
486 | { | |
487 | if (!len2) | |
488 | { | |
489 | va_list va; | |
490 | va_start(va, pattern); | |
491 | len2 = vsendpreprep(acptr, lfrm, pattern, va); | |
492 | va_end(va); | |
493 | } | |
494 | ||
495 | if (acptr != from) | |
496 | (void)send_message(acptr, psendbuf, len2); | |
497 | } | |
498 | else | |
499 | (void)send_message(acptr, sendbuf, len1); | |
500 | } | |
501 | return; | |
502 | } | |
503 | ||
504 | /* | |
505 | * sendto_server_butone | |
506 | * | |
507 | * Send a message to all connected servers except the client 'one'. | |
508 | */ | |
509 | void sendto_serv_butone(aClient *one, char *pattern, ...) | |
510 | { | |
511 | Reg int i, len=0; | |
512 | Reg aClient *cptr; | |
513 | ||
514 | for (i = fdas.highest; i >= 0; i--) | |
515 | if ((cptr = local[fdas.fd[i]]) && | |
516 | (!one || cptr != one->from) && !IsMe(cptr)) { | |
517 | if (!len) | |
518 | { | |
519 | va_list va; | |
520 | va_start(va, pattern); | |
521 | len = vsendprep(pattern, va); | |
522 | va_end(va); | |
523 | } | |
524 | (void)send_message(cptr, sendbuf, len); | |
525 | } | |
526 | return; | |
527 | } | |
528 | ||
529 | int sendto_serv_v(aClient *one, int ver, char *pattern, ...) | |
530 | { | |
531 | Reg int i, len=0, rc=0; | |
532 | Reg aClient *cptr; | |
533 | ||
534 | for (i = fdas.highest; i >= 0; i--) | |
535 | { | |
536 | if ((cptr = local[fdas.fd[i]]) && | |
537 | (!one || cptr != one->from) && !IsMe(cptr)) | |
538 | { | |
539 | #if 0 | |
540 | /* We're not using it for now, so just save some cpu. | |
541 | ** Revive once we need it --B. */ | |
542 | if ((cptr->serv->version & ver) == 0) | |
543 | { | |
544 | rc = 1; | |
545 | continue; | |
546 | } | |
547 | #endif | |
548 | if (!len) | |
549 | { | |
550 | va_list va; | |
551 | va_start(va, pattern); | |
552 | len = vsendprep(pattern, va); | |
553 | va_end(va); | |
554 | } | |
555 | (void)send_message(cptr, sendbuf, len); | |
556 | } | |
557 | } | |
558 | ||
559 | return rc; | |
560 | } | |
561 | ||
562 | #if 0 | |
563 | /* We're not using it for now, so just save some cpu. | |
564 | ** Revive once we need it --B. */ | |
565 | int sendto_serv_notv(aClient *one, int ver, char *pattern, ...) | |
566 | { | |
567 | Reg int i, len=0, rc=0; | |
568 | Reg aClient *cptr; | |
569 | ||
570 | for (i = fdas.highest; i >= 0; i--) | |
571 | { | |
572 | if ((cptr = local[fdas.fd[i]]) && | |
573 | (!one || cptr != one->from) && !IsMe(cptr)) | |
574 | { | |
575 | if ((cptr->serv->version & ver) == 0) | |
576 | { | |
577 | if (!len) | |
578 | { | |
579 | va_list va; | |
580 | va_start(va, pattern); | |
581 | len = vsendprep(pattern, va); | |
582 | va_end(va); | |
583 | } | |
584 | ||
585 | (void)send_message(cptr, sendbuf, len); | |
586 | } | |
587 | else | |
588 | { | |
589 | rc = 1; | |
590 | } | |
591 | } | |
592 | } | |
593 | ||
594 | return rc; | |
595 | } | |
596 | #endif | |
597 | ||
598 | /* | |
599 | * sendto_common_channels() | |
600 | * | |
601 | * Sends a message to all people (inclusing user) on local server who are | |
602 | * in same channel with user, except for channels set Quiet or Anonymous | |
603 | * The calling procedure must take the necessary steps for such channels. | |
604 | */ | |
605 | void sendto_common_channels(aClient *user, char *pattern, ...) | |
606 | { | |
607 | Reg int i; | |
608 | Reg aClient *cptr; | |
609 | Reg Link *channels, *lp; | |
610 | int len = 0; | |
611 | ||
612 | /* This is kind of funky, but should work. The first part below | |
613 | is optimized for HUB servers or servers with few clients on | |
614 | them. The second part is optimized for bigger client servers | |
615 | where looping through the whole client list is bad. I'm not | |
616 | really certain of the point at which each function equals | |
617 | out...but I do know the 2nd part will help big client servers | |
618 | fairly well... - Comstud 97/04/24 | |
619 | */ | |
620 | ||
621 | if (highest_fd < 50) /* This part optimized for HUB servers... */ | |
622 | { | |
623 | if (MyConnect(user)) | |
624 | { | |
625 | va_list va; | |
626 | va_start(va, pattern); | |
627 | len = vsendpreprep(user, user, pattern, va); | |
628 | va_end(va); | |
629 | (void)send_message(user, psendbuf, len); | |
630 | } | |
631 | for (i = 0; i <= highest_fd; i++) | |
632 | { | |
633 | if (!(cptr = local[i]) || IsServer(cptr) || | |
634 | user == cptr || !user->user) | |
635 | continue; | |
636 | for (lp = user->user->channel; lp; lp = lp->next) | |
637 | { | |
638 | if (!IsMember(cptr, lp->value.chptr)) | |
639 | continue; | |
640 | if (IsAnonymous(lp->value.chptr)) | |
641 | continue; | |
642 | if (!IsQuiet(lp->value.chptr)) | |
643 | { | |
644 | #ifndef DEBUGMODE | |
645 | if (!len) /* This saves little cpu, | |
646 | but breaks the debug code.. */ | |
647 | #endif | |
648 | { | |
649 | va_list va; | |
650 | va_start(va, pattern); | |
651 | len = vsendpreprep(cptr, user, pattern, va); | |
652 | va_end(va); | |
653 | } | |
654 | (void)send_message(cptr, psendbuf, | |
655 | len); | |
656 | break; | |
657 | } | |
658 | } | |
659 | } | |
660 | } | |
661 | else | |
662 | { | |
663 | /* This part optimized for client servers */ | |
664 | bzero((char *)&sentalong[0], sizeof(int) * MAXCONNECTIONS); | |
665 | if (MyConnect(user)) | |
666 | { | |
667 | va_list va; | |
668 | va_start(va, pattern); | |
669 | len = vsendpreprep(user, user, pattern, va); | |
670 | va_end(va); | |
671 | (void)send_message(user, psendbuf, len); | |
672 | sentalong[user->fd] = 1; | |
673 | } | |
674 | if (!user->user) | |
675 | return; | |
676 | for (channels=user->user->channel; channels; | |
677 | channels=channels->next) | |
678 | { | |
679 | if (IsQuiet(channels->value.chptr)) | |
680 | continue; | |
681 | if (IsAnonymous(channels->value.chptr)) | |
682 | continue; | |
683 | for (lp=channels->value.chptr->clist;lp; | |
684 | lp=lp->next) | |
685 | { | |
686 | cptr = lp->value.cptr; | |
687 | if (user == cptr) | |
688 | continue; | |
689 | if (!cptr->user || sentalong[cptr->fd]) | |
690 | continue; | |
691 | sentalong[cptr->fd]++; | |
692 | #ifndef DEBUGMODE | |
693 | if (!len) /* This saves little cpu, | |
694 | but breaks the debug code.. */ | |
695 | #endif | |
696 | { | |
697 | va_list va; | |
698 | va_start(va, pattern); | |
699 | len = vsendpreprep(cptr, user, pattern, va); | |
700 | va_end(va); | |
701 | } | |
702 | (void)send_message(cptr, psendbuf, len); | |
703 | } | |
704 | } | |
705 | } | |
706 | return; | |
707 | } | |
708 | ||
709 | /* | |
710 | * sendto_channel_butserv | |
711 | * | |
712 | * Send a message to all members of a channel that are connected to this | |
713 | * server. | |
714 | */ | |
715 | void sendto_channel_butserv(aChannel *chptr, aClient *from, char *pattern, ...) | |
716 | { | |
717 | Reg Link *lp; | |
718 | Reg aClient *acptr, *lfrm = from; | |
719 | int len = 0; | |
720 | ||
721 | if (MyClient(from)) | |
722 | { /* Always send to the client itself */ | |
723 | va_list va; | |
724 | va_start(va, pattern); | |
725 | vsendto_prefix_one(from, from, pattern, va); | |
726 | va_end(va); | |
727 | if (IsQuiet(chptr)) /* Really shut up.. */ | |
728 | return; | |
729 | } | |
730 | if (IsAnonymous(chptr) && IsClient(from)) | |
731 | { | |
732 | lfrm = &anon; | |
733 | } | |
734 | ||
735 | for (lp = chptr->clist; lp; lp = lp->next) | |
736 | if (MyClient(acptr = lp->value.cptr) && acptr != from) | |
737 | { | |
738 | if (!len) | |
739 | { | |
740 | va_list va; | |
741 | va_start(va, pattern); | |
742 | len = vsendpreprep(acptr, lfrm, pattern, va); | |
743 | va_end(va); | |
744 | } | |
745 | (void)send_message(acptr, psendbuf, len); | |
746 | } | |
747 | ||
748 | return; | |
749 | } | |
750 | ||
751 | /* | |
752 | ** send a msg to all ppl on servers/hosts that match a specified mask | |
753 | ** (used for enhanced PRIVMSGs) | |
754 | ** | |
755 | ** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de) | |
756 | */ | |
757 | ||
758 | static int match_it(aClient *one, char *mask, int what) | |
759 | { | |
760 | switch (what) | |
761 | { | |
762 | case MATCH_HOST: | |
763 | return (match(mask, one->user->host)==0); | |
764 | case MATCH_SERVER: | |
765 | default: | |
766 | return (match(mask, one->user->server)==0); | |
767 | } | |
768 | } | |
769 | ||
770 | /* | |
771 | * sendto_match_servs | |
772 | * | |
773 | * send to all servers which match the mask at the end of a channel name | |
774 | * (if there is a mask present) or to all if no mask. | |
775 | */ | |
776 | void sendto_match_servs(aChannel *chptr, aClient *from, char *format, ...) | |
777 | { | |
778 | Reg int i, len=0; | |
779 | Reg aClient *cptr; | |
780 | char *mask; | |
781 | ||
782 | if (chptr) | |
783 | { | |
784 | if (*chptr->chname == '&') | |
785 | return; | |
786 | if ((mask = get_channelmask(chptr->chname))) | |
787 | mask++; | |
788 | } | |
789 | else | |
790 | mask = (char *)NULL; | |
791 | ||
792 | for (i = fdas.highest; i >= 0; i--) | |
793 | { | |
794 | if (!(cptr = local[fdas.fd[i]]) || (cptr == from) || | |
795 | IsMe(cptr)) | |
796 | continue; | |
797 | if (!BadPtr(mask) && match(mask, cptr->name)) | |
798 | continue; | |
799 | #ifdef JAPANESE | |
800 | if (!jp_valid(cptr, chptr, 0)) | |
801 | continue; | |
802 | #endif | |
803 | if (!len) | |
804 | { | |
805 | va_list va; | |
806 | va_start(va, format); | |
807 | len = vsendprep(format, va); | |
808 | va_end(va); | |
809 | } | |
810 | (void)send_message(cptr, sendbuf, len); | |
811 | } | |
812 | } | |
813 | ||
814 | int sendto_match_servs_v(aChannel *chptr, aClient *from, int ver, | |
815 | char *format, ...) | |
816 | { | |
817 | Reg int i, len=0, rc=0; | |
818 | Reg aClient *cptr; | |
819 | char *mask; | |
820 | ||
821 | if (chptr) | |
822 | { | |
823 | if (*chptr->chname == '&') | |
824 | return 0; | |
825 | if ((mask = get_channelmask(chptr->chname))) | |
826 | mask++; | |
827 | } | |
828 | else | |
829 | mask = (char *)NULL; | |
830 | ||
831 | for (i = fdas.highest; i >= 0; i--) | |
832 | { | |
833 | if (!(cptr = local[fdas.fd[i]]) || (cptr == from) || | |
834 | IsMe(cptr)) | |
835 | continue; | |
836 | if (!BadPtr(mask) && match(mask, cptr->name)) | |
837 | continue; | |
838 | #ifdef JAPANESE | |
839 | if (!jp_valid(cptr, chptr, 0)) | |
840 | continue; | |
841 | #endif | |
842 | ||
843 | #if 0 | |
844 | /* We're not using it for now, so just save some cpu. | |
845 | ** Revive once we need it --B. */ | |
846 | if ((ver & cptr->serv->version) == 0) | |
847 | { | |
848 | rc = 1; | |
849 | continue; | |
850 | } | |
851 | #endif | |
852 | if (!len) | |
853 | { | |
854 | va_list va; | |
855 | va_start(va, format); | |
856 | len = vsendprep(format, va); | |
857 | va_end(va); | |
858 | } | |
859 | (void)send_message(cptr, sendbuf, len); | |
860 | } | |
861 | return rc; | |
862 | } | |
863 | ||
864 | #if 0 | |
865 | /* We're not using it for now, so just save some cpu. | |
866 | ** Revive once we need it --B. */ | |
867 | int sendto_match_servs_notv(aChannel *chptr, aClient *from, int ver, | |
868 | char *format, ...) | |
869 | { | |
870 | Reg int i, len=0, rc=0; | |
871 | Reg aClient *cptr; | |
872 | char *mask; | |
873 | ||
874 | if (chptr) | |
875 | { | |
876 | if (*chptr->chname == '&') | |
877 | return 0; | |
878 | if ((mask = get_channelmask(chptr->chname))) | |
879 | mask++; | |
880 | } | |
881 | else | |
882 | mask = (char *)NULL; | |
883 | ||
884 | for (i = fdas.highest; i >= 0; i--) | |
885 | { | |
886 | if (!(cptr = local[fdas.fd[i]]) || (cptr == from) || | |
887 | IsMe(cptr)) | |
888 | continue; | |
889 | if (!BadPtr(mask) && match(mask, cptr->name)) | |
890 | continue; | |
891 | #ifdef JAPANESE | |
892 | if (!jp_valid(cptr, chptr, 0)) | |
893 | continue; | |
894 | #endif | |
895 | if ((ver & cptr->serv->version) != 0) | |
896 | { | |
897 | rc = 1; | |
898 | continue; | |
899 | } | |
900 | if (!len) | |
901 | { | |
902 | va_list va; | |
903 | va_start(va, format); | |
904 | len = vsendprep(format, va); | |
905 | va_end(va); | |
906 | } | |
907 | (void)send_message(cptr, sendbuf, len); | |
908 | } | |
909 | return rc; | |
910 | } | |
911 | #endif | |
912 | ||
913 | /* | |
914 | * sendto_match_butone | |
915 | * | |
916 | * Send to all clients which match the mask in a way defined on 'what'; | |
917 | * either by user hostname or user servername. | |
918 | */ | |
919 | void sendto_match_butone(aClient *one, aClient *from, char *mask, int what, | |
920 | char *pattern, ...) | |
921 | { | |
922 | int i; | |
923 | aClient *cptr, | |
924 | *srch; | |
925 | ||
926 | for (i = 0; i <= highest_fd; i++) | |
927 | { | |
928 | if (!(cptr = local[i])) | |
929 | continue; /* that clients are not mine */ | |
930 | if (cptr == one) /* must skip the origin !! */ | |
931 | continue; | |
932 | if (IsServer(cptr)) | |
933 | { | |
934 | /* | |
935 | ** we can save some CPU here by not searching the | |
936 | ** entire list of users since it is ordered! | |
937 | ** original idea/code from pht. | |
938 | ** it could be made better by looping on the list of | |
939 | ** servers to avoid non matching blocks in the list | |
940 | ** (srch->from != cptr), but then again I never | |
941 | ** bothered to worry or optimize this routine -kalt | |
942 | */ | |
943 | for (srch = cptr->prev; srch; srch = srch->prev) | |
944 | { | |
945 | if (!IsRegisteredUser(srch)) | |
946 | continue; | |
947 | if (srch->from == cptr && | |
948 | match_it(srch, mask, what)) | |
949 | break; | |
950 | } | |
951 | if (srch == NULL) | |
952 | continue; | |
953 | } | |
954 | /* my client, does he match ? */ | |
955 | else if (!(IsRegisteredUser(cptr) && | |
956 | match_it(cptr, mask, what))) | |
957 | { | |
958 | continue; | |
959 | } | |
960 | /* this frame have tricked me many times ;) and it's only | |
961 | ** frame for having va declared ;) --Beeth */ | |
962 | { | |
963 | va_list va; | |
964 | va_start(va, pattern); | |
965 | vsendto_prefix_one(cptr, from, pattern, va); | |
966 | va_end(va); | |
967 | } | |
968 | ||
969 | } | |
970 | return; | |
971 | } | |
972 | ||
973 | /* | |
974 | ** sendto_ops_butone | |
975 | ** Send message to all operators. | |
976 | ** one - client not to send message to | |
977 | ** from- client which message is from *NEVER* NULL!! | |
978 | */ | |
979 | void sendto_ops_butone(aClient *one, char *from, char *pattern, ...) | |
980 | { | |
981 | va_list va; | |
982 | char buf[BUFSIZE]; | |
983 | ||
984 | va_start(va, pattern); | |
985 | vsprintf(buf, pattern, va); | |
986 | va_end(va); | |
987 | sendto_serv_butone(one, ":%s WALLOPS :%s", from, buf); | |
988 | sendto_flag(SCH_WALLOP, "!%s! %s", from, buf); | |
989 | ||
990 | return; | |
991 | } | |
992 | ||
993 | /* | |
994 | * to - destination client | |
995 | * from - client which message is from | |
996 | * | |
997 | * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!! | |
998 | * -avalon | |
999 | */ | |
1000 | void sendto_prefix_one(aClient *to, aClient *from, char *pattern, ...) | |
1001 | { | |
1002 | int len; | |
1003 | ||
1004 | va_list va; | |
1005 | va_start(va, pattern); | |
1006 | len = vsendpreprep(to, from, pattern, va); | |
1007 | va_end(va); | |
1008 | send_message(to, psendbuf, len); | |
1009 | return; | |
1010 | } | |
1011 | ||
1012 | static void vsendto_prefix_one(aClient *to, aClient *from, char *pattern, | |
1013 | va_list va) | |
1014 | { | |
1015 | int len; | |
1016 | ||
1017 | len = vsendpreprep(to, from, pattern, va); | |
1018 | send_message(to, psendbuf, len); | |
1019 | return; | |
1020 | } | |
1021 | ||
1022 | ||
1023 | /* | |
1024 | * sends a message to a server-owned channel | |
1025 | */ | |
1026 | static SChan svchans[SCH_MAX] = { | |
1027 | { SCH_ERROR, "&ERRORS", NULL, -2}, | |
1028 | { SCH_NOTICE, "&NOTICES", NULL, -2}, | |
1029 | { SCH_KILL, "&KILLS", NULL, -2}, | |
1030 | { SCH_CHAN, "&CHANNEL", NULL, -2}, | |
1031 | { SCH_NUM, "&NUMERICS", NULL, -2}, | |
1032 | { SCH_SERVER, "&SERVERS", NULL, -2}, | |
1033 | { SCH_HASH, "&HASH", NULL, -2}, | |
1034 | { SCH_LOCAL, "&LOCAL", NULL, -2}, | |
1035 | { SCH_SERVICE, "&SERVICES", NULL, -2}, | |
1036 | { SCH_DEBUG, "&DEBUG", NULL, -2}, | |
1037 | { SCH_AUTH, "&AUTH", NULL, -2}, | |
1038 | { SCH_SAVE, "&SAVE", NULL, -2}, | |
1039 | { SCH_WALLOP, "&WALLOPS", NULL, -2}, | |
1040 | #ifdef CLIENTS_CHANNEL | |
1041 | { SCH_CLIENT, "&CLIENTS", NULL, -2}, | |
1042 | #endif | |
1043 | { SCH_OPER, "&OPER", NULL, -2}, | |
1044 | }; | |
1045 | ||
1046 | ||
1047 | void setup_svchans(void) | |
1048 | { | |
1049 | int i; | |
1050 | SChan *shptr; | |
1051 | ||
1052 | #ifdef LOG_SERVER_CHANNELS | |
1053 | /* They're here, as they need to be done only once per server run, | |
1054 | ** to determine if we want given channel logged. --B. */ | |
1055 | # ifdef LOG_SCH_ERROR | |
1056 | (svchans+SCH_ERROR)->fd = -1; | |
1057 | # endif | |
1058 | # ifdef LOG_SCH_NOTICE | |
1059 | (svchans+SCH_NOTICE)->fd = -1; | |
1060 | # endif | |
1061 | # ifdef LOG_SCH_KILL | |
1062 | (svchans+SCH_KILL)->fd = -1; | |
1063 | # endif | |
1064 | # ifdef LOG_SCH_CHAN | |
1065 | (svchans+SCH_CHAN)->fd = -1; | |
1066 | # endif | |
1067 | # ifdef LOG_SCH_NUM | |
1068 | (svchans+SCH_NUM)->fd = -1; | |
1069 | # endif | |
1070 | # ifdef LOG_SCH_SERVER | |
1071 | (svchans+SCH_SERVER)->fd = -1; | |
1072 | # endif | |
1073 | # ifdef LOG_SCH_HASH | |
1074 | (svchans+SCH_HASH)->fd = -1; | |
1075 | # endif | |
1076 | # ifdef LOG_SCH_LOCAL | |
1077 | (svchans+SCH_LOCAL)->fd = -1; | |
1078 | # endif | |
1079 | # ifdef LOG_SCH_SERVICE | |
1080 | (svchans+SCH_SERVICE)->fd = -1; | |
1081 | # endif | |
1082 | # ifdef LOG_SCH_DEBUG | |
1083 | (svchans+SCH_DEBUG)->fd = -1; | |
1084 | # endif | |
1085 | # ifdef LOG_SCH_AUTH | |
1086 | (svchans+SCH_AUTH)->fd = -1; | |
1087 | # endif | |
1088 | # ifdef LOG_SCH_SAVE | |
1089 | (svchans+SCH_SAVE)->fd = -1; | |
1090 | # endif | |
1091 | # ifdef LOG_SCH_WALLOP | |
1092 | (svchans+SCH_WALLOP)->fd = -1; | |
1093 | # endif | |
1094 | # ifdef CLIENTS_CHANNEL | |
1095 | # ifdef LOG_SCH_CLIENT | |
1096 | (svchans+SCH_CLIENT)->fd = -1; | |
1097 | # endif | |
1098 | # endif | |
1099 | # ifdef LOG_SCH_OPER | |
1100 | (svchans+SCH_OPER)->fd = -1; | |
1101 | # endif | |
1102 | #endif | |
1103 | for (i = SCH_MAX - 1, shptr = svchans + i; i >= 0; i--, shptr--) | |
1104 | shptr->svc_ptr = find_channel(shptr->svc_chname, NULL); | |
1105 | } | |
1106 | ||
1107 | void sendto_flag(u_int chan, char *pattern, ...) | |
1108 | { | |
1109 | Reg aChannel *chptr = NULL; | |
1110 | SChan *shptr; | |
1111 | char nbuf[1024]; | |
1112 | ||
1113 | if (chan >= SCH_MAX) | |
1114 | chan = SCH_NOTICE; | |
1115 | shptr = svchans + chan; | |
1116 | ||
1117 | if ((chptr = shptr->svc_ptr)) | |
1118 | { | |
1119 | { | |
1120 | va_list va; | |
1121 | va_start(va, pattern); | |
1122 | (void)vsprintf(nbuf, pattern, va); | |
1123 | va_end(va); | |
1124 | } | |
1125 | sendto_channel_butserv(chptr, &me, ":%s NOTICE %s :%s", ME, chptr->chname, nbuf); | |
1126 | ||
1127 | #ifdef USE_SERVICES | |
1128 | switch (chan) | |
1129 | { | |
1130 | case SCH_ERROR: | |
1131 | check_services_butone(SERVICE_WANT_ERRORS, NULL, &me, | |
1132 | "&ERRORS :%s", nbuf); | |
1133 | break; | |
1134 | case SCH_NOTICE: | |
1135 | check_services_butone(SERVICE_WANT_NOTICES, NULL, &me, | |
1136 | "&NOTICES :%s", nbuf); | |
1137 | break; | |
1138 | case SCH_LOCAL: | |
1139 | check_services_butone(SERVICE_WANT_LOCAL, NULL, &me, | |
1140 | "&LOCAL :%s", nbuf); | |
1141 | break; | |
1142 | case SCH_NUM: | |
1143 | check_services_butone(SERVICE_WANT_NUMERICS, NULL, &me, | |
1144 | "&NUMERICS :%s", nbuf); | |
1145 | break; | |
1146 | #ifdef CLIENTS_CHANNEL | |
1147 | case SCH_CLIENT: | |
1148 | check_services_butone(SERVICE_WANT_CLIENTS, NULL, &me, | |
1149 | "&CLIENTS :%s", nbuf); | |
1150 | break; | |
1151 | #endif | |
1152 | } | |
1153 | #endif | |
1154 | } | |
1155 | #ifdef LOG_SERVER_CHANNELS | |
1156 | if ((svchans+chan)->fd >= 0) | |
1157 | { | |
1158 | char lbuf[1024]; | |
1159 | int len; | |
1160 | ||
1161 | len = sprintf(lbuf, "%u %s\n", (u_int)timeofday, nbuf); | |
1162 | (void)write((svchans+chan)->fd, lbuf, len); | |
1163 | } | |
1164 | #endif | |
1165 | return; | |
1166 | } | |
1167 | ||
1168 | static int userlog = -1; | |
1169 | static int connlog = -1; | |
1170 | ||
1171 | void logfiles_open(void) | |
1172 | { | |
1173 | #ifdef LOG_SERVER_CHANNELS | |
1174 | int i; | |
1175 | SChan *shptr; | |
1176 | char fname[BUFSIZE]; | |
1177 | ||
1178 | for (i = SCH_MAX - 1, shptr = svchans + i; i >= 0; i--, shptr--) | |
1179 | { | |
1180 | if (shptr->fd == -2) | |
1181 | { | |
1182 | /* We don't want this channel logged. */ | |
1183 | continue; | |
1184 | } | |
1185 | ||
1186 | sprintf(fname, "%s.%s", FNAME_SCH_PREFIX, shptr->svc_chname+1); | |
1187 | shptr->fd = open(fname, O_WRONLY|O_APPEND|O_NDELAY | |
1188 | #ifdef LOGFILES_ALWAYS_CREATE | |
1189 | |O_CREAT, S_IRUSR|S_IWUSR | |
1190 | #endif | |
1191 | ); | |
1192 | /* Better safe than sorry. */ | |
1193 | if (shptr->fd >= 0) | |
1194 | { | |
1195 | local[shptr->fd] = NULL; | |
1196 | } | |
1197 | } | |
1198 | #endif | |
1199 | #ifdef FNAME_USERLOG | |
1200 | userlog = open(FNAME_USERLOG, O_WRONLY|O_APPEND|O_NDELAY | |
1201 | # ifdef LOGFILES_ALWAYS_CREATE | |
1202 | |O_CREAT, S_IRUSR|S_IWUSR | |
1203 | # endif | |
1204 | ); | |
1205 | /* Better safe than sorry. */ | |
1206 | if (userlog >= 0) | |
1207 | { | |
1208 | local[userlog] = NULL; | |
1209 | } | |
1210 | #else | |
1211 | userlog = -1; | |
1212 | #endif | |
1213 | #ifdef FNAME_CONNLOG | |
1214 | connlog = open(FNAME_CONNLOG, O_WRONLY|O_APPEND|O_NDELAY | |
1215 | # ifdef LOGFILES_ALWAYS_CREATE | |
1216 | |O_CREAT, S_IRUSR|S_IWUSR | |
1217 | # endif | |
1218 | ); | |
1219 | if (connlog >= 0) | |
1220 | { | |
1221 | local[connlog] = NULL; | |
1222 | } | |
1223 | #else | |
1224 | connlog = -1; | |
1225 | #endif | |
1226 | } | |
1227 | ||
1228 | void logfiles_close(void) | |
1229 | { | |
1230 | #ifdef LOG_SERVER_CHANNELS | |
1231 | int i; | |
1232 | SChan *shptr; | |
1233 | ||
1234 | for (i = SCH_MAX - 1, shptr = svchans + i; i >= 0; i--, shptr--) | |
1235 | { | |
1236 | if (shptr->fd >= 0) | |
1237 | { | |
1238 | (void)close(shptr->fd); | |
1239 | } | |
1240 | } | |
1241 | #endif | |
1242 | #ifdef FNAME_USERLOG | |
1243 | if (userlog != -1) | |
1244 | { | |
1245 | (void)close(userlog); | |
1246 | userlog = -1; | |
1247 | } | |
1248 | #endif | |
1249 | #ifdef FNAME_CONNLOG | |
1250 | if (connlog != -1) | |
1251 | { | |
1252 | (void)close(connlog); | |
1253 | connlog = -1; | |
1254 | } | |
1255 | #endif | |
1256 | } | |
1257 | ||
1258 | /* | |
1259 | * sendto_flog | |
1260 | * cptr used for firsttime, auth, exitc, send/receive M/B | |
1261 | * msg exit code | |
1262 | * username sometimes can't get it from cptr | |
1263 | * hostname i.e. | |
1264 | */ | |
1265 | void sendto_flog(aClient *cptr, char msg, char *username, char *hostname) | |
1266 | { | |
1267 | /* | |
1268 | ** One day we will rewrite linebuf to malloc()s, but for now | |
1269 | ** we are lazy. The longest linebuf I saw during last year | |
1270 | ** was 216. Max auth reply can be 1024, see rfc931_work() and | |
1271 | ** if iauth is disabled, read_authports() makes it max 513. | |
1272 | ** And the rest... just count, I got 154 --Beeth | |
1273 | */ | |
1274 | char linebuf[1500]; | |
1275 | int linebuflen; | |
1276 | /* | |
1277 | ** This is a potential buffer overflow. | |
1278 | ** I mean, when you manage to keep ircd | |
1279 | ** running for almost 12 years ;-) --B. | |
1280 | */ | |
1281 | #ifdef LOG_OLDFORMAT | |
1282 | char buf[12]; | |
1283 | #endif | |
1284 | int logfile; | |
1285 | ||
1286 | /* | |
1287 | ** EXITC_REG == 0 means registered client quitting, so it goes to | |
1288 | ** userlog; otherwise it's rejection and goes to connlog --Beeth. | |
1289 | */ | |
1290 | logfile = (msg == EXITC_REG ? userlog : connlog); | |
1291 | ||
1292 | #if !defined(USE_SERVICES) && !( defined(USE_SYSLOG) && \ | |
1293 | (defined(SYSLOG_USERS) || defined(SYSLOG_CONN)) ) | |
1294 | if (logfile == -1) | |
1295 | { | |
1296 | return; | |
1297 | } | |
1298 | #endif | |
1299 | #ifdef LOG_OLDFORMAT | |
1300 | if (msg == EXITC_REG) | |
1301 | { | |
1302 | time_t duration; | |
1303 | ||
1304 | duration = timeofday - cptr->firsttime + 1; | |
1305 | (void)sprintf(buf, "%3d:%02d:%02d", | |
1306 | (int) (duration / 3600), | |
1307 | (int) ((duration % 3600) / 60), | |
1308 | (int) (duration % 60)); | |
1309 | } | |
1310 | else | |
1311 | { | |
1312 | char *anyptr; | |
1313 | ||
1314 | switch(msg) | |
1315 | { | |
1316 | case EXITC_GHMAX: anyptr="G IP max"; break; | |
1317 | case EXITC_GUHMAX: anyptr="G u@h max"; break; | |
1318 | case EXITC_LHMAX: anyptr="L IP max"; break; | |
1319 | case EXITC_LUHMAX: anyptr="L u@h max"; break; | |
1320 | case EXITC_AREF: | |
1321 | case EXITC_AREFQ: anyptr=" Denied "; break; | |
1322 | case EXITC_KLINE: anyptr=" K lined "; break; | |
1323 | case EXITC_CLONE: anyptr=" ?Clone? "; break; | |
1324 | case EXITC_YLINEMAX: anyptr=" max "; break; | |
1325 | case EXITC_NOILINE: anyptr=" No Auth "; break; | |
1326 | case EXITC_AUTHFAIL: anyptr="No iauth!"; break; | |
1327 | case EXITC_AUTHTOUT: anyptr="iauth t/o"; break; | |
1328 | case EXITC_FAILURE: anyptr=" Failure "; break; | |
1329 | default: anyptr=" Unknown "; | |
1330 | } | |
1331 | (void)sprintf(buf, "%s", anyptr); | |
1332 | } | |
1333 | linebuflen = sprintf(linebuf, | |
1334 | "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb ", | |
1335 | myctime(cptr->firsttime), buf, | |
1336 | username[0] ? username : "<none>", hostname, | |
1337 | cptr->auth ? cptr->auth : "<none>", | |
1338 | cptr->exitc, cptr->sendM, (long)(cptr->sendB>>10), | |
1339 | cptr->receiveM, (long)(cptr->receiveB>>10)); | |
1340 | #else | |
1341 | /* | |
1342 | ** This is the content of loglines. | |
1343 | */ | |
1344 | linebuflen = sprintf(linebuf, | |
1345 | "%c %d %d %s %s %s %s %d %s %lu %llu %lu %llu ", | |
1346 | /* exit code as defined in common/struct_def.h; some common: | |
1347 | * '0' normal exit, '-' unregistered client quit, 'k' k-lined, | |
1348 | * 'K' killed, 'X' x-lined, 'Y' max clients limit of Y-line, | |
1349 | * 'L' local @host limit, 'l' local user@host limit, 'P' ping | |
1350 | * timeout, 'Q' send queue exceeded, 'E' socket error */ | |
1351 | cptr->exitc, | |
1352 | /* signon unix time */ | |
1353 | (u_int) cptr->firsttime, | |
1354 | /* signoff unix time */ | |
1355 | (u_int) timeofday, | |
1356 | /* username (if ident is not working, it's from USER cmd) */ | |
1357 | username, | |
1358 | /* hmm, let me take an educated guess... a hostname? */ | |
1359 | hostname, | |
1360 | /* ident, if available */ | |
1361 | cptr->auth ? cptr->auth : "?", | |
1362 | /* client IP */ | |
1363 | cptr->user ? cptr->user->sip : | |
1364 | #ifdef INET6 | |
1365 | inetntop(AF_INET6, (char *)&cptr->ip, ipv6string, sizeof(ipv6string)), | |
1366 | #else | |
1367 | inetntoa((char *)&cptr->ip), | |
1368 | #endif | |
1369 | /* client (remote) port */ | |
1370 | cptr->port, | |
1371 | /* server sockhost (IP plus port or unix socket path) */ | |
1372 | cptr->acpt ? cptr->acpt->sockhost : "?", | |
1373 | /* messages and bytes sent to client */ | |
1374 | cptr->sendM, cptr->sendB, | |
1375 | /* messages and bytes received from client */ | |
1376 | cptr->receiveM, cptr->receiveB); | |
1377 | #endif /* LOG_OLDFORMAT */ | |
1378 | #if defined(USE_SYSLOG) && (defined(SYSLOG_USERS) || defined(SYSLOG_CONN)) | |
1379 | if (msg == EXITC_REG) | |
1380 | { | |
1381 | # ifdef SYSLOG_USERS | |
1382 | syslog(LOG_NOTICE, "%s", linebuf); | |
1383 | # endif | |
1384 | } | |
1385 | else | |
1386 | { | |
1387 | # ifdef SYSLOG_CONN | |
1388 | syslog(LOG_NOTICE, "%s", linebuf); | |
1389 | # endif | |
1390 | } | |
1391 | #endif /* USE_SYSLOG */ | |
1392 | ||
1393 | #ifdef USE_SERVICES | |
1394 | if (msg == EXITC_REG) | |
1395 | { | |
1396 | check_services_butone(SERVICE_WANT_USERLOG, NULL, &me, | |
1397 | "USERLOG :%s", linebuf); | |
1398 | } | |
1399 | else | |
1400 | { | |
1401 | check_services_butone(SERVICE_WANT_CONNLOG, NULL, &me, | |
1402 | "CONNLOG :%s", linebuf); | |
1403 | } | |
1404 | #endif | |
1405 | if (logfile != -1) | |
1406 | { | |
1407 | linebuf[linebuflen-1] = '\n'; | |
1408 | (void)write(logfile, linebuf, linebuflen); | |
1409 | } | |
1410 | } |