1 /************************************************************************
2 * IRC - Internet Relay Chat, ircd/s_serv.c (formerly ircd/s_msg.c)
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
5 *
6 * See file AUTHORS in IRC package for additional names of
7 * the programmers.
8 *
9 * This program 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 1, or (at your option)
12 * any later version.
13 *
14 * This program 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 this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #ifndef lint
25 static const volatile char rcsid[] = "@(#)$Id: s_serv.c,v 1.298 2010/08/12 16:24:31 bif Exp $";
26 #endif
27
28 #include "os.h"
29 #include "s_defines.h"
30 #define S_SERV_C
31 #include "s_externs.h"
32 #undef S_SERV_C
33
34 static char buf[BUFSIZE];
35
36 static int check_link (aClient *);
37 static int get_version (char *, char *);
38 static void trace_one (aClient *, aClient *);
39 static void report_listeners(aClient *, char *);
40 static void count_servers_users(aClient *, int *, int *);
41 const char *check_servername_errors[3][2] = {
42 { "too long", "Bogus servername - too long" },
43 { "invalid", "Bogus servername - invalid chars in hostname" },
44 { "bogus", "Bogus servername - no dot"}};
45 static int send_users(aClient *, aClient *, int, char **);
46
47 /*
48 ** m_functions execute protocol messages on this server:
49 **
50 ** cptr is always NON-NULL, pointing to a *LOCAL* client
51 ** structure (with an open socket connected!). This
52 ** identifies the physical socket where the message
53 ** originated (or which caused the m_function to be
54 ** executed--some m_functions may call others...).
55 **
56 ** sptr is the source of the message, defined by the
57 ** prefix part of the message if present. If not
58 ** or prefix not found, then sptr==cptr.
59 **
60 ** (!IsServer(cptr)) => (cptr == sptr), because
61 ** prefixes are taken *only* from servers...
62 **
63 ** (IsServer(cptr))
64 ** (sptr == cptr) => the message didn't
65 ** have the prefix.
66 **
67 ** (sptr != cptr && IsServer(sptr) means
68 ** the prefix specified servername. (?)
69 **
70 ** (sptr != cptr && !IsServer(sptr) means
71 ** that message originated from a remote
72 ** user (not local).
73 **
74 ** combining
75 **
76 ** (!IsServer(sptr)) means that, sptr can safely
77 ** taken as defining the target structure of the
78 ** message in this server.
79 **
80 ** *Always* true (if 'parse' and others are working correct):
81 **
82 ** 1) sptr->from == cptr (note: cptr->from == cptr)
83 **
84 ** 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
85 ** *cannot* be a local connection, unless it's
86 ** actually cptr!). [MyConnect(x) should probably
87 ** be defined as (x == x->from) --msa ]
88 **
89 ** parc number of variable parameter strings (if zero,
90 ** parv is allowed to be NULL)
91 **
92 ** parv a NULL terminated list of parameter pointers,
93 **
94 ** parv[0], sender (prefix string), if not present
95 ** this points to an empty string.
96 ** parv[1]...parv[parc-1]
97 ** pointers to additional parameters
98 ** parv[parc] == NULL, *always*
99 **
100 ** note: it is guaranteed that parv[0]..parv[parc-1] are all
101 ** non-NULL pointers.
102 */
103
104 /*
105 ** m_version
106 ** parv[0] = sender prefix
107 ** parv[1] = remote server
108 */
m_version(aClient * cptr,aClient * sptr,int parc,char * parv[])109 int m_version(aClient *cptr, aClient *sptr, int parc, char *parv[])
110 {
111 if (hunt_server(cptr,sptr,":%s VERSION :%s",1,parc,parv)==HUNTED_ISME)
112 sendto_one(sptr, replies[RPL_VERSION], ME, BadTo(parv[0]),
113 version, debugmode, ME, me.serv->sid, serveropts);
114 return 2;
115 }
116
117 /*
118 ** m_squit
119 ** parv[0] = sender prefix
120 ** parv[1] = server name
121 ** parv[2] = comment
122 */
m_squit(aClient * cptr,aClient * sptr,int parc,char * parv[])123 int m_squit(aClient *cptr, aClient *sptr, int parc, char *parv[])
124 {
125 Reg aConfItem *aconf;
126 char *server;
127 Reg aClient *acptr = NULL;
128 int rsquit = 0;
129 char *comment;
130 static char comment2[TOPICLEN+1];
131
132 if (!is_allowed(sptr, ACL_SQUIT))
133 return m_nopriv(cptr, sptr, parc, parv);
134
135 server = parv[1];
136 comment = parv[2];
137 /*
138 ** To accomodate host masking, a squit for a masked server
139 ** name is expanded if the incoming mask is the same as
140 ** the server name for that link to the name of link.
141 */
142 if ((*server == '*') && IsServer(cptr)
143 && (aconf = cptr->serv->nline) != NULL
144 && !mycmp(server, my_name_for_link(ME, aconf->port)))
145 {
146 server = cptr->name;
147 }
148 /* Try finding by sid. */
149 acptr = find_sid(server, NULL);
150 /*
151 ** The following allows wild cards in SQUIT. Only useful
152 ** when the command is issued by an oper.
153 */
154 if (!acptr)
155 {
156 acptr = find_server(server, NULL);
157 }
158 if (!acptr)
159 {
160 for (acptr = client;
161 (acptr = next_client(acptr, server));
162 acptr = acptr->next)
163 {
164 if (IsServer(acptr) || IsMe(acptr))
165 {
166 break;
167 }
168 }
169 }
170 if (acptr && IsMe(acptr))
171 {
172 if (MyConnect(sptr) && IsServer(sptr))
173 {
174 /* remote server is closing it's link */
175 rsquit = 1;
176 }
177 if (IsServer(cptr))
178 {
179 acptr = cptr;
180 server = cptr->sockhost;
181 }
182 else
183 {
184 sendto_one(cptr, ":%s NOTICE %s :You can QUIT, "
185 "but you cannot SQUIT me.",
186 ME, cptr->name);
187 return 1;
188 }
189 }
190
191 /*
192 ** SQUIT semantics is tricky, be careful...
193 **
194 ** The old (irc2.2PL1 and earlier) code just cleans away the
195 ** server client from the links (because it is never true
196 ** "cptr == acptr".
197 **
198 ** This logic here works the same way until "SQUIT host" hits
199 ** the server having the target "host" as local link. Then it
200 ** will do a real cleanup spewing SQUIT's and QUIT's to all
201 ** directions, also to the link from which the original SQUIT
202 ** came, generating one unnecessary "SQUIT host" back to that
203 ** link.
204 **
205 ** One may think that this could be implemented like
206 ** "hunt_server" (e.g. just pass on "SQUIT" without doing
207 ** nothing until the server having the link as local is
208 ** reached). Unfortunately this wouldn't work in the real life,
209 ** because either target may be unreachable or may not comply
210 ** with the request. In either case it would leave target in
211 ** links--no command to clear it away. So, it's better just
212 ** clean out while going forward, just to be sure.
213 **
214 ** ...of course, even better cleanout would be to QUIT/SQUIT
215 ** dependant users/servers already on the way out, but
216 ** currently there is not enough information about remote
217 ** clients to do this... --msa
218 */
219 if (!acptr)
220 {
221 sendto_one(sptr, replies[ERR_NOSUCHSERVER], ME, BadTo(parv[0]), server);
222 return 1;
223 }
224 if (!MyConnect(acptr) && !is_allowed(sptr, ACL_SQUITREMOTE))
225 {
226 return m_nopriv(cptr, sptr, parc, parv);
227 }
228 if (MyPerson(sptr))
229 {
230 int k=TOPICLEN-strlen(sptr->name)-7;
231
232 /* Shorten original comment, should it be too long. */
233 if (strlen(comment) > k)
234 {
235 comment[k] = '\0';
236 }
237 /* As we change comment, we have to copy, who knows what
238 ** parv[2] can overwrite. */
239 comment2[0] = '\0';
240 sprintf(comment2, "%s (by %s)", comment, sptr->name);
241 comment = comment2;
242 }
243 if (!MyConnect(acptr) && (cptr != acptr->from))
244 {
245 /* just propagate upstream */
246 sendto_one(acptr->from, ":%s SQUIT %s :%s",
247 IsServer(sptr) ?
248 sptr->serv->sid : sptr->name,
249 acptr->serv->sid, comment);
250 sendto_flag(SCH_SERVER,
251 "Forwarding SQUIT %s (%s) from %s (%s)",
252 acptr->name, acptr->serv->sid, parv[0],
253 comment);
254 sendto_flag(SCH_DEBUG,
255 "Forwarding SQUIT %s to %s from %s (%s)",
256 acptr->name, acptr->from->name,
257 parv[0], comment);
258 return 1;
259 }
260 /*
261 ** Notify all opers, if my local link is remotely squitted
262 */
263 if (MyConnect(acptr) && !IsAnOper(cptr) && !rsquit)
264 {
265 sendto_ops_butone(NULL, ME,
266 "Received SQUIT %s from %s (%s)",
267 acptr->name, parv[0], comment);
268 #if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT)
269 syslog(LOG_DEBUG,"SQUIT From %s : %s (%s)",
270 parv[0], acptr->name, comment);
271 #endif
272 }
273 if (MyConnect(acptr))
274 {
275 int timeconnected = timeofday - acptr->firsttime;
276 sendto_flag(SCH_NOTICE,
277 "Closing link to %s (%d, %2d:%02d:%02d)",
278 get_client_name(acptr, FALSE),
279 timeconnected / 86400,
280 (timeconnected % 86400) / 3600,
281 (timeconnected % 3600)/60,
282 timeconnected % 60);
283 }
284 return exit_client(cptr, acptr, sptr, comment);
285 }
286
287 /*
288 ** get_version()
289 ** Tries to guess what version or, rather, what
290 ** capabilities remote server has.
291 */
get_version(char * version,char * id)292 static int get_version(char *version, char *id)
293 {
294 int result = 0;
295
296 if (!strncmp(version, "0210", 4))
297 {
298 int vers;
299
300 vers = atoi(version+4);
301 if (vers >= 991200)
302 {
303 /* good beta of 2.11 */
304 result = SV_2_11;
305 }
306 else
307 {
308 /* earlier than 2.11.0b12 kills users with nicks longer
309 ** than 9 and does not pass +R modes --B. */
310 result = SV_OLD;
311 }
312 }
313 else if (!strncmp(version, "021", 3))
314 {
315 /* 2.11 or newer (you wish!) */
316 /* btw, it will work until we do 2.20+ or 3.0+ version */
317 result = SV_2_11;
318 }
319 else
320 {
321 /* if it doesn't match above, it is too old
322 to coexist with us, sorry! */
323 result = SV_OLD;
324 }
325
326 return result;
327 }
328
329 /*
330 ** check_version
331 ** The PASS command delivers additional information about incoming
332 ** connection. The data is temporarily stored to info/name/username
333 ** in m_pass() and processed here before the fields are natively used.
334 ** Return: < 1: exit/error, > 0: no error
335 */
check_version(aClient * cptr)336 int check_version(aClient *cptr)
337 {
338 char *id, *misc = NULL, *link = NULL;
339
340 Debug((DEBUG_INFO,"check_version: %s", cptr->info));
341
342 if (cptr->info == DefInfo)
343 {
344 cptr->hopcount = SV_OLD;
345 return 1; /* no version checked (e.g. older than 2.9) */
346 }
347 if ((id = index(cptr->info, ' ')))
348 {
349 *id++ = '\0';
350 if ((link = index(id, ' ')))
351 {
352 *link++ = '\0';
353 }
354 if ((misc = index(id, '|')))
355 {
356 *misc++ = '\0';
357 }
358 else
359 {
360 misc = id;
361 id = "";
362 }
363 }
364 else
365 {
366 id = "";
367 }
368
369 cptr->hopcount = get_version(cptr->info, id);
370
371 /* Check version number/mask from conf */
372 sprintf(buf, "%s/%s", id, cptr->info);
373 if (find_two_masks(cptr->name, buf, CONF_VER))
374 {
375 sendto_flag(SCH_ERROR, "Bad version %s %s from %s", id,
376 cptr->info, get_client_name(cptr, TRUE));
377 return exit_client(cptr, cptr, &me, "Bad version");
378 }
379
380 if (misc)
381 {
382 sprintf(buf, "%s/%s", id, misc);
383 /* Check version flags from conf */
384 if (find_conf_flags(cptr->name, buf, CONF_VER))
385 {
386 sendto_flag(SCH_ERROR, "Bad flags %s (%s) from %s",
387 misc, id, get_client_name(cptr, TRUE));
388 return exit_client(cptr, cptr, &me, "Bad flags");
389 }
390 }
391
392 #ifdef JAPANESE
393 if (link && strchr(link, 'j')) /* jp version */
394 cptr->flags |= FLAGS_JP;
395 #endif
396
397 /* right now, I can't code anything good for this */
398 /* Stop whining, and do it! ;) */
399 if (link && strchr(link, 'Z')) /* Compression requested */
400 {
401 cptr->flags |= FLAGS_ZIPRQ;
402 }
403 /*
404 * If server was started with -p strict, be careful about the
405 * other server mode.
406 */
407 if (link && strncmp(cptr->info, "020", 3) &&
408 (bootopt & BOOT_STRICTPROT) && !strchr(link, 'P'))
409 {
410 return exit_client(cptr, cptr, &me, "Unsafe mode");
411 }
412
413 return 2;
414 }
415
416
417 /*
418 ** send_server()
419 ** Sends server server to cptr.
420 */
send_server(aClient * cptr,aClient * server)421 static void send_server(aClient *cptr, aClient *server)
422 {
423 aConfItem *aconf;
424
425 if (cptr->from == server->from)
426 {
427 return;
428 }
429 aconf = cptr->serv->nline;
430
431 if (!aconf)
432 {
433 return;
434 }
435
436 if (!match(my_name_for_link(ME, aconf->port), server->name) ||
437 IsMasked(server))
438 {
439 /* I'm masking this server, or it was introduced to us with
440 ** SMASK. */
441 sendto_one(cptr, ":%s SMASK %s %s",
442 server->serv->up->serv->sid, server->serv->sid,
443 server->serv->verstr);
444 return;
445 }
446 sendto_one(cptr,":%s SERVER %s %d %s %s :%s",
447 server->serv->up->serv->sid, server->name,
448 server->hopcount + 1, server->serv->sid,
449 server->serv->verstr, server->info);
450
451 return;
452 }
453
454
455 /*
456 ** introduce_server()
457 ** Introduces a server I got from cptr to all my other servers.
458 */
introduce_server(aClient * cptr,aClient * server)459 static void introduce_server(aClient *cptr, aClient *server)
460 {
461 int i;
462 aClient *acptr;
463
464 for (i = fdas.highest; i >= 0; i--)
465 {
466 if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
467 (acptr == cptr) || IsMe(acptr))
468 {
469 continue;
470 }
471 send_server(acptr, server);
472 }
473
474 return;
475 }
476
477
478 /*
479 ** send_server_burst()
480 ** Sends all servers I know to cptr.
481 ** Acptr is the current to send.
482 */
send_server_burst(aClient * cptr,aClient * acptr)483 static void send_server_burst(aClient *cptr, aClient *acptr)
484 {
485 for (; acptr; acptr = acptr->serv->right)
486 {
487 if (cptr == acptr)
488 {
489 continue;
490 }
491 send_server(cptr, acptr);
492 send_server_burst(cptr, acptr->serv->down);
493 }
494
495 return;
496 }
497
498
499 /*
500 ** m_smask - Introduction of servers behind mask
501 ** parv[0] = sender prefix
502 ** parv[1] = sid
503 ** parv[2] = version
504 */
m_smask(aClient * cptr,aClient * sptr,int parc,char * parv[])505 int m_smask(aClient *cptr, aClient *sptr, int parc, char *parv[])
506 {
507 aClient *acptr;
508
509 if (!sid_valid(parv[1]))
510 {
511 sendto_flag(SCH_ERROR,
512 "Invalid SID (%s) in SMASK from %s, dropping link",
513 parv[1],sptr->name);
514 return exit_client(cptr, cptr, &me, "Invalid SID");
515 }
516
517 if (find_sid(parv[1],NULL))
518 {
519 char ecbuf[BUFSIZE];
520 sendto_flag(SCH_NOTICE,
521 "SID collision (SMASK) on %s brought by %s, "
522 "dropping link", parv[1],sptr->name);
523 sprintf(ecbuf, "SID collision (%s)", parv[1]);
524 return exit_client(cptr, cptr, &me, ecbuf);
525 }
526
527 acptr = make_client(cptr);
528 make_server(acptr);
529 acptr->hopcount = sptr->hopcount + 1;
530 strncpyzt(acptr->serv->namebuf, sptr->name, sizeof(acptr->serv->namebuf));
531 acptr->info = mystrdup("Masked Server");
532 acptr->serv->up = sptr;
533 acptr->serv->snum = sptr->serv->maskedby->serv->snum;
534 strncpyzt(acptr->serv->verstr, parv[2], sizeof(acptr->serv->verstr));
535 acptr->serv->version = get_version(parv[2], NULL);
536 acptr->serv->maskedby = sptr->serv->maskedby;
537 SetServer(acptr);
538 istat.is_masked++;
539
540 /* We add this server to client list, but *only* to SID hash. */
541 add_client_to_list(acptr);
542 register_server(acptr);
543
544 strncpyzt(acptr->serv->sid, parv[1], SIDLEN + 1);
545 add_to_sid_hash_table(parv[1], acptr);
546
547 add_server_to_tree(acptr);
548
549 /* And introduce the server to others. */
550 introduce_server(cptr, acptr);
551
552 return 1;
553 }
554
555
556 /*
557 ** m_server
558 ** parv[0] = sender prefix
559 ** parv[1] = servername
560 ** parv[2] = hopcount
561 ** parv[3] = sid(2.11)/token(2.10)/serverinfo(local 2.10)
562 ** parv[4] = server version (remote 2.11)/serverinfo(remote 2.10+local2.11)
563 ** parv[5] = serverinfo (remote 2.11)
564 */
m_server(aClient * cptr,aClient * sptr,int parc,char * parv[])565 int m_server(aClient *cptr, aClient *sptr, int parc, char *parv[])
566 {
567 char info[REALLEN+1], *inpath, *host;
568 char versionbuf[11]; /* At least PATCHLEVEL size! */
569 aClient *acptr, *bcptr;
570 aConfItem *aconf;
571 int hop = 0;
572 int tmperr;
573
574 if (sptr->user) /* in case NICK has been received already */
575 {
576 sendto_one(sptr, replies[ERR_ALREADYREGISTRED], ME, BadTo(parv[0]));
577 return 1;
578 }
579 if ((bootopt & BOOT_STANDALONE))
580 {
581 sendto_flag(SCH_ERROR,
582 "Running in standalone mode, cannot accept %s/%s", parv[1], parv[3]);
583 return exit_client(cptr, cptr, &me,
584 "Running in standalone mode");
585 }
586 info[0] = info[REALLEN] = '\0'; /* strncpy() doesn't guarantee NULL */
587 inpath = get_client_name(cptr, FALSE);
588 if (parc < 2 || *parv[1] == '\0')
589 {
590 sendto_one(cptr,"ERROR :No servername");
591 return 1;
592 }
593
594 if (parc < 3 || (IsServer(cptr) && parc < 4))
595 {
596 return exit_client(cptr, cptr, &me, "Server version too old");
597 }
598
599 if (IsServer(cptr))
600 {
601 if (parc < 6)
602 {
603 sendto_flag(SCH_ERROR,
604 "Not enough parameters to SERVER (%d < 6), "
605 "dropping link to %s", parc,
606 get_client_name(cptr,TRUE));
607 return exit_client(cptr, cptr, &me,
608 "Not enough parameters to SERVER");
609 }
610 if (!sid_valid(parv[3]))
611 {
612 sendto_flag(SCH_ERROR,
613 "Invalid SID %s from %s, dropping link",
614 parv[3], get_client_name(cptr, TRUE));
615 return exit_client(cptr, cptr, &me, "Invalid SID");
616 }
617 if (find_sid(parv[3],NULL))
618 {
619 /* check for SID collision */
620 char ecbuf[BUFSIZE];
621
622 sendto_flag(SCH_NOTICE, "Link %s tried to introduce"
623 " already existing SID (%s), dropping link",
624 get_client_name(cptr, TRUE), parv[3]);
625 sprintf(ecbuf, "SID collision (%s)", parv[3]);
626 return exit_client(cptr, cptr, &me, ecbuf);
627 }
628 }
629
630 host = parv[1];
631 hop = atoi(parv[2]);
632 strncpyzt(info, parv[parc-1], REALLEN);
633
634 /* check if the servername is valid */
635 if ((tmperr = check_servername(host)))
636 {
637 tmperr--;
638 sendto_flag(SCH_ERROR,
639 "Rejected server with %s server name (%s) from %s",
640 check_servername_errors[tmperr][0],
641 host, get_client_name(cptr, TRUE));
642 return exit_client(cptr, cptr, &me,
643 check_servername_errors[tmperr][1]);
644 }
645
646 /* *WHEN* can it be that "cptr != sptr" ????? --msa */
647 /* When SERVER command (like now) has prefix. -avalon */
648
649 if (IsRegistered(cptr) && ((acptr = find_name(host, NULL))
650 || (acptr = find_mask(host, NULL))))
651 {
652 char tbuf[BUFSIZE];
653 sprintf(tbuf, "Server %s Exists",host);
654 /*
655 ** This link is trying feed me a server that I already have
656 ** access through another path -- multiple paths not accepted
657 ** currently, kill this link immeatedly!!
658 **
659 ** Rather than KILL the link which introduced it, KILL the
660 ** youngest of the two links. -avalon
661 */
662 bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr :
663 acptr->from;
664 sendto_one(bcptr, "ERROR :Server %s already exists", host);
665 /* in both cases the bcptr (the youngest is killed) */
666 if (bcptr == cptr)
667 {
668 sendto_flag(SCH_ERROR,
669 "Link %s cancelled, server %s already exists",
670 get_client_name(bcptr, TRUE), host);
671 return exit_client(bcptr, bcptr, &me, tbuf);
672 }
673 else
674 {
675 /*
676 ** in this case, we are not dropping the link from
677 ** which we got the SERVER message. Thus we canNOT
678 ** `return' yet! -krys
679 */
680 strcpy(buf, get_client_name(bcptr, TRUE));
681 sendto_flag(SCH_ERROR,
682 "Link %s cancelled, server %s reintroduced by %s",
683 buf, host, get_client_name(cptr, TRUE));
684 (void) exit_client(bcptr, bcptr, &me, tbuf);
685 }
686 }
687
688 if (IsServer(cptr))
689 {
690 /* A server can only be introduced by another server. */
691 if (!IsServer(sptr))
692 {
693 sendto_flag(SCH_NOTICE,
694 "Squitting %s brought by %s (introduced by %s)",
695 host, get_client_name(cptr, FALSE),
696 sptr->name);
697 sendto_one(cptr,
698 ":%s SQUIT %s :(Introduced by %s from %s)",
699 me.name, host, sptr->name,
700 get_client_name(cptr, FALSE));
701 return 1;
702 }
703 /*
704 ** Server is informing about a new server behind
705 ** this link. Create REMOTE server structure,
706 ** add it to list and propagate word to my other
707 ** server links...
708 */
709 if (parc == 1 || info[0] == '\0')
710 {
711 sendto_one(cptr,
712 "ERROR :No server info specified for %s",
713 host);
714 sendto_flag(SCH_ERROR, "No server info for %s from %s",
715 host, get_client_name(cptr, TRUE));
716 return 1;
717 }
718
719 /*
720 ** See if the newly found server is behind a guaranteed
721 ** leaf (L-line). If so, close the link.
722 */
723 if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) &&
724 (!aconf->port || (hop > aconf->port)))
725 {
726 sendto_flag(SCH_ERROR,
727 "Leaf-only link %s->%s - Closing",
728 get_client_name(cptr, TRUE),
729 aconf->host ? aconf->host : "*");
730 sendto_one(cptr, "ERROR :Leaf-only link, sorry.");
731 return exit_client(cptr, cptr, &me, "Leaf Only");
732 }
733 /*
734 **
735 */
736 if (!(aconf =
737 find_conf_host_sid(cptr->confs, host, parv[3], CONF_HUB))
738 || (aconf->port && (hop > aconf->port)) )
739 {
740 sendto_flag(SCH_ERROR,
741 "Non-Hub link %s introduced %s(%s).",
742 get_client_name(cptr, TRUE), host,
743 aconf ? (aconf->host ? aconf->host : "*") :
744 "!");
745 return exit_client(cptr, cptr, &me,
746 "Too many servers");
747 }
748 /*
749 ** See if the newly found server has a Q line for it in
750 ** our conf. If it does, lose the link that brought it
751 ** into our network. Format:
752 **
753 ** Q:<unused>:<reason>:<servername>
754 **
755 ** Example: Q:*:for the hell of it:eris.Berkeley.EDU
756 */
757 if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER)))
758 {
759 sendto_ops_butone(NULL, ME,
760 "%s brought in %s, %s %s",
761 get_client_name(cptr, TRUE),
762 host, "closing link because",
763 BadPtr(aconf->passwd) ? "reason unspecified" :
764 aconf->passwd);
765
766 sendto_one(cptr,
767 "ERROR :%s is not welcome: %s. %s",
768 host, BadPtr(aconf->passwd) ?
769 "reason unspecified" : aconf->passwd,
770 "Go away and get a life");
771
772 return exit_client(cptr, cptr, &me, "Q-Lined Server");
773 }
774
775 acptr = make_client(cptr);
776 make_server(acptr);
777 acptr->hopcount = hop;
778 strncpyzt(acptr->serv->namebuf, host, sizeof(acptr->serv->namebuf));
779 if (acptr->info != DefInfo)
780 MyFree(acptr->info);
781 acptr->info = mystrdup(info);
782 acptr->serv->up = sptr;
783 acptr->serv->snum = find_server_num(acptr->name);
784 acptr->serv->maskedby = acptr;
785 SetServer(acptr);
786 istat.is_serv++;
787 if (istat.is_serv > istat.is_m_serv)
788 istat.is_m_serv = istat.is_serv;
789 add_client_to_list(acptr);
790 register_server(acptr);
791
792 strncpyzt(acptr->serv->sid, parv[3], SIDLEN+1);
793 acptr->serv->version |= SV_UID;
794 add_to_sid_hash_table(parv[3], acptr);
795
796 strncpyzt(acptr->serv->verstr,
797 parv[4], sizeof(acptr->serv->verstr));
798 acptr->serv->version = get_version(parv[4],NULL);
799
800 add_server_to_tree(acptr);
801 (void)add_to_client_hash_table(acptr->name, acptr);
802
803 introduce_server(cptr, acptr);
804 #ifdef USE_SERVICES
805 check_services_butone(SERVICE_WANT_SERVER, acptr->serv, acptr,
806 ":%s SERVER %s %d %s :%s", parv[0],
807 acptr->name, hop+1, acptr->serv->sid,
808 acptr->info);
809 #endif
810 sendto_flag(SCH_SERVER, "Received SERVER %s from %s (%d %s)",
811 acptr->name, parv[0], hop+1, acptr->info);
812 return 0;
813 }
814
815 if ((!IsUnknown(cptr) && !IsHandshake(cptr)) ||
816 (cptr->flags & FLAGS_UNKCMD))
817 return 1;
818 /*
819 ** A local link that is still in undefined state wants
820 ** to be a SERVER. Check if this is allowed and change
821 ** status accordingly...
822 */
823 /* Oh joy. :( I had to move this if() here from m_server_estab()
824 * (it was there just before SetServer), because we no longer
825 * use cptr->name, only cptr->serv->namebuf, which is allocated
826 * in make_server()... --B. */
827 /* doesnt duplicate cptr->serv if allocated this struct already */
828 make_server(cptr);
829 strncpyzt(cptr->serv->namebuf, host, sizeof(cptr->serv->namebuf));
830 /* cptr->name has to exist before check_version(), and cptr->info
831 * may not be filled before check_version(). */
832 if ((hop = check_version(cptr)) < 1)
833 return hop; /* from exit_client() */
834 if (cptr->info != DefInfo)
835 {
836 strncpyzt(versionbuf, cptr->info, sizeof(versionbuf));
837 MyFree(cptr->info);
838 }
839 cptr->info = mystrdup(info[0] ? info : ME);
840
841 switch (check_server_init(cptr))
842 {
843 case 0 :
844 return m_server_estab(cptr, (parc > 3) ? parv[3] : NULL,
845 versionbuf);
846 case 1 :
847 sendto_flag(SCH_NOTICE, "Checking access for %s",
848 get_client_name(cptr,TRUE));
849 return 1;
850 default :
851 ircstp->is_ref++;
852 sendto_flag(SCH_NOTICE, "Unauthorized server from %s.",
853 get_client_host(cptr));
854 return exit_client(cptr, cptr, &me, "No C/N conf lines");
855 }
856 }
857
m_server_estab(aClient * cptr,char * sid,char * versionbuf)858 int m_server_estab(aClient *cptr, char *sid, char *versionbuf)
859 {
860 Reg aClient *acptr;
861 aClient *bysptr = NULL;
862 #ifndef HUB
863 int i;
864 #endif
865
866 Reg aConfItem *aconf, *bconf;
867 char mlname[HOSTLEN+1], *inpath, *host, *s, *encr;
868
869 host = cptr->name;
870 inpath = get_client_name(cptr,TRUE); /* "refresh" inpath with host */
871
872 if (cptr->serv && cptr->serv->byuid[0])
873 {
874 bysptr = find_uid(cptr->serv->byuid, NULL);
875 /* we are interrested only in *remote* opers */
876 if (bysptr && MyConnect(bysptr))
877 {
878 bysptr = NULL;
879 }
880 }
881
882 if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER)))
883 {
884 ircstp->is_ref++;
885 sendto_one(cptr,
886 "ERROR :Access denied. No N line for server %s",
887 inpath);
888 sendto_flag(SCH_ERROR,
889 "Access denied. No N line for server %s", inpath);
890 if (bysptr)
891 {
892 sendto_one(bysptr,
893 ":%s NOTICE %s :Access denied. No N line for "
894 "server %s", ME, bysptr->name, inpath);
895 }
896
897 return exit_client(cptr, cptr, &me, "No N line for server");
898 }
899 if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER|
900 CONF_ZCONNECT_SERVER)))
901 {
902 ircstp->is_ref++;
903 sendto_one(cptr, "ERROR :Only N (no C) field for server %s",
904 inpath);
905 sendto_flag(SCH_ERROR,
906 "Only N (no C) field for server %s",inpath);
907 if (bysptr)
908 {
909 sendto_one(bysptr,
910 ":%s NOTICE %s :Only N (no C) field for server %s",
911 ME, bysptr->name, inpath);
912 }
913 return exit_client(cptr, cptr, &me, "No C line for server");
914 }
915
916 if (cptr->hopcount == SV_OLD) /* lame test, should be == 0 */
917 {
918 sendto_one(cptr, "ERROR :Server version is too old.");
919 sendto_flag(SCH_ERROR, "Old version for %s", inpath);
920 if (bysptr)
921 {
922 sendto_one(bysptr,
923 ":%s NOTICE %s :Old version for %s",
924 ME, bysptr->name, inpath);
925 }
926 return exit_client(cptr, cptr, &me, "Old version");
927 }
928
929 #ifdef CRYPT_LINK_PASSWORD
930 /* pass whole aconf->passwd as salt, let crypt() deal with it */
931
932 if (*cptr->passwd)
933 {
934 extern char *crypt();
935
936 encr = crypt(cptr->passwd, aconf->passwd);
937 if (encr == NULL)
938 {
939 ircstp->is_ref++;
940 sendto_one(cptr, "ERROR :No Access (crypt failed) %s",
941 inpath);
942 sendto_flag(SCH_ERROR,
943 "Access denied (crypt failed) %s", inpath);
944 if (bysptr)
945 {
946 sendto_one(bysptr,
947 ":%s NOTICE %s :Access denied (crypt "
948 "failed %s", ME, bysptr->name, inpath);
949 }
950 return exit_client(cptr, cptr, &me, "Bad Password");
951 }
952 }
953 else
954 encr = "";
955 #else
956 encr = cptr->passwd;
957 #endif /* CRYPT_LINK_PASSWORD */
958 if (*aconf->passwd && !StrEq(aconf->passwd, encr))
959 {
960 ircstp->is_ref++;
961 sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s",
962 inpath);
963 sendto_flag(SCH_ERROR,
964 "Access denied (passwd mismatch) %s", inpath);
965 if (bysptr)
966 {
967 sendto_one(bysptr, ":%s NOTICE %s :Access denied "
968 "(passwd mismatch) %s", ME, bysptr->name,
969 inpath);
970 }
971 return exit_client(cptr, cptr, &me, "Bad Password");
972 }
973 bzero(cptr->passwd, sizeof(cptr->passwd));
974
975 #ifndef HUB
976 for (i = 0; i <= highest_fd; i++)
977 if (local[i] && IsServer(local[i]))
978 {
979 ircstp->is_ref++;
980 sendto_flag(SCH_ERROR, "I'm a leaf, cannot link %s",
981 get_client_name(cptr, TRUE));
982 if (bysptr)
983 {
984 sendto_one(bysptr, ":%s NOTICE %s :I'm a leaf,"
985 " cannot link %s", ME, bysptr->name,
986 get_client_name(cptr, TRUE));
987 }
988 return exit_client(cptr, cptr, &me, "I'm a leaf");
989 }
990 #endif
991 (void) strcpy(mlname, my_name_for_link(ME, aconf->port));
992
993 if (!match(cptr->name,mlname))
994 {
995 sendto_flag(SCH_NOTICE, "Mask of server %s is matching "
996 "my name %s, dropping link", cptr->name, mlname);
997 if (bysptr)
998 {
999 sendto_one(bysptr, ":%s NOTICE %s :Mask of server %s "
1000 "is matching my name %s, dropping link",
1001 ME, bysptr->name, cptr->name, mlname);
1002 }
1003 return exit_client(cptr, cptr, &me,
1004 "Server exists (mask matches)");
1005 }
1006 if (!match(mlname,cptr->name))
1007 {
1008 sendto_flag(SCH_NOTICE, "Server %s matches my name for link "
1009 "%s, dropping link", cptr->name, mlname);
1010 if (bysptr)
1011 {
1012 sendto_one(bysptr, ":%s NOTICE %s :Server %s "
1013 "matches my name for link %s, dropping link",
1014 ME, bysptr->name, cptr->name, mlname);
1015 }
1016
1017 return exit_client(cptr, cptr, &me,
1018 "Server exists (matches my mask)");
1019 }
1020
1021 if (IsUnknown(cptr))
1022 {
1023 /*
1024 ** If we get a connection which has been authorized to be
1025 ** an already existing connection, remove the already
1026 ** existing connection if it has a sendq else remove the
1027 ** new and duplicate server. -avalon
1028 ** Remove existing link only if it has been linked for longer
1029 ** and has sendq higher than a threshold. -Vesa
1030 */
1031 if (((acptr = find_name(host, NULL))
1032 || (acptr = find_mask(host, NULL))) && IsServer(acptr))
1033 {
1034 if (MyConnect(acptr) &&
1035 DBufLength(&acptr->sendQ) > CHREPLLEN &&
1036 timeofday - acptr->firsttime > TIMESEC)
1037 (void) exit_client(acptr, acptr, &me,
1038 "New Server");
1039 else
1040 return exit_client(cptr, cptr, &me,
1041 "Server Exists");
1042 }
1043
1044 if (bconf->passwd[0])
1045 sendto_one(cptr, "PASS %s %s IRC|%s %s%s%s",
1046 bconf->passwd, pass_version, serveropts,
1047 (bootopt & BOOT_STRICTPROT) ? "P" : "",
1048 #ifdef JAPANESE
1049 "j",
1050 #else
1051 "",
1052 #endif
1053 #ifdef ZIP_LINKS
1054 (bconf->status == CONF_ZCONNECT_SERVER) ? "Z" :
1055 #endif
1056 ""
1057 );
1058 /*
1059 ** Pass my info to the new server
1060 */
1061 sendto_one(cptr, "SERVER %s 1 %s :%s",
1062 mlname, me.serv->sid, me.info);
1063
1064 }
1065 else
1066 {
1067 s = (char *)index(aconf->host, '@');
1068 *s = '\0'; /* should never be NULL */
1069 Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]",
1070 aconf->host, cptr->username));
1071 if (match(aconf->host, cptr->username))
1072 {
1073 *s = '@';
1074 ircstp->is_ref++;
1075 sendto_flag(SCH_ERROR,
1076 "Username mismatch [%s]v[%s] : %s",
1077 aconf->host, cptr->username,
1078 get_client_name(cptr, TRUE));
1079 sendto_one(cptr, "ERROR :No Username Match");
1080 return exit_client(cptr, cptr, &me, "Bad User");
1081 }
1082 *s = '@';
1083 }
1084
1085 #ifdef ZIP_LINKS
1086 if ((cptr->flags & FLAGS_ZIPRQ) &&
1087 (bconf->status == CONF_ZCONNECT_SERVER))
1088 {
1089 if (zip_init(cptr) == -1)
1090 {
1091 zip_free(cptr);
1092 sendto_flag(SCH_ERROR,
1093 "Unable to setup compressed link for %s",
1094 get_client_name(cptr, TRUE));
1095 if (bysptr)
1096 {
1097 sendto_one(bysptr,
1098 ":%s NOTICE %s :Unable to setup "
1099 "compressed link for %s",
1100 ME, bysptr->name, get_client_name(cptr, TRUE));
1101 }
1102 return exit_client(cptr, cptr, &me,
1103 "zip_init() failed");
1104 }
1105 cptr->flags |= FLAGS_ZIP|FLAGS_ZIPSTART;
1106 }
1107 #endif
1108
1109 /* version has been temporarily stored in ->hopcount */
1110 if (cptr->hopcount & SV_UID)
1111 {
1112 if (!sid)
1113 {
1114 sendto_flag(SCH_ERROR, "Invalid SID from %s",
1115 get_client_name(cptr, TRUE));
1116 if (bysptr)
1117 {
1118 sendto_one(bysptr,
1119 ":%s NOTICE %s :Invalid SID from %s",
1120 ME, bysptr->name,
1121 get_client_name(cptr, TRUE));
1122 }
1123 return exit_client(cptr, cptr, &me, "Invalid SID");
1124 }
1125 if (!sid_valid(sid))
1126 {
1127 sendto_flag(SCH_ERROR, "Invalid SID %s from %s",
1128 sid, get_client_name(cptr, TRUE));
1129 if (bysptr)
1130 {
1131 sendto_one(bysptr,
1132 ":%s NOTICE %s :Invalid SID %s from %s",
1133 ME, bysptr->name, sid,
1134 get_client_name(cptr, TRUE));
1135 }
1136 return exit_client(cptr, cptr, &me, "Invalid SID");
1137 }
1138 if (find_sid(sid, NULL))
1139 {
1140 sendto_flag(SCH_NOTICE, "Link %s tried to introduce"
1141 " already existing SID (%s), dropping link",
1142 get_client_name(cptr, TRUE), sid);
1143 if (bysptr)
1144 {
1145 sendto_one(bysptr,
1146 ":%s NOTICE %s :Link %s tried to "
1147 "introduce already existing SID (%s), "
1148 "dropping link", ME, bysptr->name,
1149 get_client_name(cptr, TRUE), sid);
1150 }
1151 return exit_client(cptr, cptr, &me,"SID collision");
1152 }
1153 }
1154
1155 if ((cptr->hopcount & SV_OLD))
1156 {
1157 /* remote is too old */
1158 sendto_flag(SCH_ERROR, "Remote server %s is too old, "
1159 "dropping link", get_client_name(cptr,TRUE));
1160 if (bysptr)
1161 {
1162 sendto_one(bysptr, ":%s NOTICE %s :Remote server %s is"
1163 "too old, dropping link",
1164 ME, bysptr->name, get_client_name(cptr, TRUE));
1165 }
1166 return exit_client(cptr, cptr, &me, "Too old version");
1167 }
1168
1169 det_confs_butmask(cptr, CONF_LEAF|CONF_HUB|CONF_NOCONNECT_SERVER);
1170 /*
1171 ** *WARNING*
1172 ** In the following code in place of plain server's
1173 ** name we send what is returned by get_client_name
1174 ** which may add the "sockhost" after the name. It's
1175 ** *very* *important* that there is a SPACE between
1176 ** the name and sockhost (if present). The receiving
1177 ** server will start the information field from this
1178 ** first blank and thus puts the sockhost into info.
1179 ** ...a bit tricky, but you have been warned, besides
1180 ** code is more neat this way... --msa
1181 */
1182 SetServer(cptr);
1183 istat.is_unknown--;
1184 istat.is_serv++;
1185 if (istat.is_serv > istat.is_m_serv)
1186 istat.is_m_serv = istat.is_serv;
1187 istat.is_myserv++;
1188 if (istat.is_myserv > istat.is_m_myserv)
1189 istat.is_m_myserv = istat.is_myserv;
1190 nextping = timeofday;
1191 sendto_flag(SCH_NOTICE, "Link with %s established. (%X%s)", inpath,
1192 cptr->hopcount, (cptr->flags & FLAGS_ZIP) ? "z" : "");
1193 if (bysptr)
1194 {
1195 sendto_one(bysptr,
1196 ":%s NOTICE %s :Link with %s established. (%X%s)",
1197 ME, bysptr->name, inpath, cptr->hopcount,
1198 (cptr->flags & FLAGS_ZIP) ? "z" : "");
1199 }
1200 (void)add_to_client_hash_table(cptr->name, cptr);
1201 cptr->serv->up = &me;
1202 cptr->serv->maskedby = cptr;
1203 cptr->serv->nline = aconf;
1204 cptr->serv->version = cptr->hopcount; /* temporary location */
1205 cptr->hopcount = 1; /* local server connection */
1206 cptr->serv->snum = find_server_num(cptr->name);
1207
1208 strncpyzt(cptr->serv->verstr, versionbuf, sizeof(cptr->serv->verstr));
1209 strcpy(cptr->serv->sid, sid);
1210
1211 cptr->flags |= FLAGS_CBURST;
1212 register_server(cptr);
1213 add_to_sid_hash_table(sid, cptr);
1214 add_server_to_tree(cptr);
1215 /* why no add_client_to_list() here? --B. */
1216 Debug((DEBUG_NOTICE, "Server link established with %s V%X %s",
1217 cptr->name, cptr->serv->version, cptr->serv->sid));
1218 add_fd(cptr->fd, &fdas);
1219 #ifdef USE_SERVICES
1220 check_services_butone(SERVICE_WANT_SERVER, cptr->serv, cptr,
1221 ":%s SERVER %s %d %s :%s", ME, cptr->name,
1222 cptr->hopcount+1, cptr->serv->sid, cptr->info);
1223 #endif
1224 sendto_flag(SCH_SERVER, "Received SERVER %s from %s (%d %s)",
1225 cptr->name, ME, 1, cptr->info);
1226 introduce_server(cptr, cptr);
1227
1228 /*
1229 ** Pass on my client information to the new server
1230 **
1231 ** First, pass only servers (idea is that if the link gets
1232 ** cancelled beacause the server was already there,
1233 ** there are no NICK's to be cancelled...). Of course,
1234 ** if cancellation occurs, all this info is sent anyway,
1235 ** and I guess the link dies when a read is attempted...? --msa
1236 **
1237 ** Note: Link cancellation to occur at this point means
1238 ** that at least two servers from my fragment are building
1239 ** up connection this other fragment at the same time, it's
1240 ** a race condition, not the normal way of operation...
1241 **
1242 ** ALSO NOTE: using the get_client_name for server names--
1243 ** see previous *WARNING*!!! (Also, original inpath
1244 ** is destroyed...)
1245 */
1246 send_server_burst(cptr, me.serv->down);
1247
1248 for (acptr = &me; acptr; acptr = acptr->prev)
1249 {
1250 /* acptr->from == acptr for acptr == cptr */
1251 if (acptr->from == cptr)
1252 continue;
1253 if (IsPerson(acptr))
1254 {
1255 /*
1256 ** IsPerson(x) is true only when IsClient(x) is true.
1257 ** These are only true when *BOTH* NICK and USER have
1258 ** been received. -avalon
1259 */
1260 send_umode(NULL, acptr, 0, SEND_UMODES, buf);
1261 sendto_one(cptr,
1262 ":%s UNICK %s %s %s %s %s %s :%s",
1263 acptr->user->servp->sid,
1264 acptr->name, acptr->user->uid,
1265 acptr->user->username,
1266 acptr->user->host,
1267 acptr->user->sip,
1268 (*buf) ? buf : "+", acptr->info);
1269 }
1270 else if (IsService(acptr) &&
1271 (match(acptr->service->dist, cptr->name) == 0 ||
1272 match(acptr->service->dist, cptr->serv->sid) == 0))
1273 {
1274 sendto_one(cptr, ":%s SERVICE %s %s %d :%s",
1275 acptr->service->servp->sid,
1276 acptr->name,
1277 acptr->service->dist,
1278 acptr->service->type,
1279 acptr->info);
1280 }
1281 /* the previous if does NOT catch all services.. ! */
1282 }
1283
1284 flush_connections(cptr->fd);
1285
1286 /*
1287 ** Last, pass all channels modes
1288 ** only sending modes for LIVE channels.
1289 ** Correction: now we send empty channels as well (with "." as
1290 ** a client), so other side can lock the channel if they don't
1291 ** know it (either "yet" (restarted server) or "already" (L/DCTL
1292 ** differences)). Also send modes for such !channels. --B.
1293 */
1294 {
1295 Reg aChannel *chptr;
1296 int rv = atoi(cptr->serv->verstr);
1297
1298 for (chptr = channel; chptr; chptr = chptr->nextch)
1299 {
1300 if (chptr->users)
1301 {
1302 send_channel_members(cptr, chptr);
1303 send_channel_modes(cptr, chptr);
1304 }
1305 else
1306 if (rv >= 210991700) /* XXX remove soon */
1307 {
1308 sendto_one(cptr, ":%s NJOIN %s .",
1309 me.serv->sid, chptr->chname);
1310 if (*chptr->chname == '!')
1311 send_channel_modes(cptr, chptr);
1312 }
1313 }
1314 }
1315 if (istat.is_myserv == 1)
1316 { /* remote server is the only we have connected */
1317 sendto_one(cptr, ":%s EOB", me.serv->sid);
1318 }
1319 else
1320 {
1321 aServer *asptr;
1322 char eobbuf[BUFSIZE];
1323 char *e;
1324 int eobmaxlen;
1325
1326 e = eobbuf;
1327 eobmaxlen = BUFSIZE
1328 - 1 /* ":" */
1329 - SIDLEN /* my SID */
1330 - 6 /* " EOB :" */
1331 - 2; /* "\r\n" */
1332
1333 /* space for last comma and SID (calculation moved
1334 * from "if (e - eobbuf > eobmaxlen)" inside following
1335 * loop)
1336 */
1337 eobmaxlen -= SIDLEN + 1;
1338
1339 /* send EOBs */
1340 for (asptr = svrtop; asptr; asptr = asptr->nexts)
1341 {
1342 /* No appending of own SID */
1343 if (asptr->bcptr == &me)
1344 continue;
1345 /* Send EOBs only for servers which already
1346 * finished bursting */
1347 if (!IsBursting(asptr->bcptr))
1348 {
1349 if ((int) (e - eobbuf) > eobmaxlen)
1350 {
1351 *e = '\0';
1352 /* eobbuf always starts with
1353 * comma, so +1 gets rid of it
1354 */
1355 sendto_one(cptr, ":%s EOB :%s",
1356 me.serv->sid,
1357 eobbuf + 1);
1358 e = eobbuf;
1359 }
1360
1361 *e++ = ',';
1362 memcpy(e, asptr->sid, SIDLEN);
1363 e += SIDLEN;
1364 }
1365 }
1366 /* Send the rest, if any */
1367 if (e > eobbuf)
1368 {
1369 *e = '\0';
1370 sendto_one(cptr, ":%s EOB :%s", me.serv->sid,
1371 eobbuf+1);
1372 }
1373 else
1374 {
1375 sendto_one(cptr, ":%s EOB", me.serv->sid);
1376 }
1377 }
1378 #ifdef ZIP_LINKS
1379 /*
1380 ** some stats about the connect burst,
1381 ** they are slightly incorrect because of cptr->zip->outbuf.
1382 */
1383 if ((cptr->flags & FLAGS_ZIP) && cptr->zip->out->total_in)
1384 sendto_flag(SCH_NOTICE,
1385 "Connect burst to %s: %lu, compressed: %lu (%3.1f%%)",
1386 get_client_name(cptr, TRUE),
1387 cptr->zip->out->total_in,cptr->zip->out->total_out,
1388 (float) 100*cptr->zip->out->total_out/cptr->zip->out->total_in);
1389 #endif
1390 return 0;
1391 }
1392
1393 /*
1394 ** m_info
1395 ** parv[0] = sender prefix
1396 ** parv[1] = servername
1397 */
m_info(aClient * cptr,aClient * sptr,int parc,char * parv[])1398 int m_info(aClient *cptr, aClient *sptr, int parc, char *parv[])
1399 {
1400 char **text = infotext;
1401
1402 if (check_link(sptr))
1403 {
1404 sendto_one(sptr, replies[RPL_TRYAGAIN], ME, BadTo(parv[0]),
1405 "INFO");
1406 return 5;
1407 }
1408 if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME)
1409 {
1410 while (*text)
1411 sendto_one(sptr, replies[RPL_INFO], ME, BadTo(parv[0]), *text++);
1412
1413 sendto_one(sptr, replies[RPL_INFO], ME, BadTo(parv[0]), "");
1414 sendto_one(sptr,
1415 ":%s %d %s :Birth Date: %s, compile # %s",
1416 ME, RPL_INFO, parv[0], creation, generation);
1417 sendto_one(sptr, ":%s %d %s :On-line since %s",
1418 ME, RPL_INFO, parv[0],
1419 myctime(me.firsttime));
1420 sendto_one(sptr, replies[RPL_ENDOFINFO], ME, BadTo(parv[0]));
1421 return 5;
1422 }
1423 else
1424 return 10;
1425 }
1426
1427 /*
1428 ** m_links
1429 ** parv[0] = sender prefix
1430 ** parv[1] = servername mask
1431 ** or
1432 ** parv[0] = sender prefix
1433 ** parv[1] = server to query
1434 ** parv[2] = servername mask
1435 */
m_links(aClient * cptr,aClient * sptr,int parc,char * parv[])1436 int m_links(aClient *cptr, aClient *sptr, int parc, char *parv[])
1437 {
1438 Reg aServer *asptr;
1439 char *mask;
1440 aClient *acptr;
1441
1442 if (parc > 2)
1443 {
1444 if (check_link(sptr))
1445 {
1446 sendto_one(sptr, replies[RPL_TRYAGAIN], ME, BadTo(parv[0]),
1447 "LINKS");
1448 return 5;
1449 }
1450 if (hunt_server(cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv)
1451 != HUNTED_ISME)
1452 return 5;
1453 mask = parv[2];
1454 }
1455 else
1456 mask = parc < 2 ? NULL : parv[1];
1457
1458 for (asptr = svrtop, (void)collapse(mask); asptr; asptr = asptr->nexts)
1459 {
1460 acptr = asptr->bcptr;
1461 if (IsMasked(acptr))
1462 {
1463 continue;
1464 }
1465 if (!BadPtr(mask) && match(mask, acptr->name))
1466 continue;
1467 sendto_one(sptr, replies[RPL_LINKS], ME, BadTo(parv[0]),
1468 acptr->name, acptr->serv->up->name,
1469 acptr->hopcount, acptr->serv->sid,
1470 (acptr->info[0] ? acptr->info :
1471 "(Unknown Location)"));
1472 }
1473
1474 sendto_one(sptr, replies[RPL_ENDOFLINKS], ME, BadTo(parv[0]),
1475 BadPtr(mask) ? "*" : mask);
1476 return 2;
1477 }
1478
1479 /*
1480 ** m_summon should be redefined to ":prefix SUMMON host user" so
1481 ** that "hunt_server"-function could be used for this too!!! --msa
1482 ** As of 2.7.1e, this was the case. -avalon
1483 **
1484 ** parv[0] = sender prefix
1485 ** parv[1] = user
1486 ** parv[2] = server
1487 ** parv[3] = channel (optional)
1488 */
m_summon(aClient * cptr,aClient * sptr,int parc,char * parv[])1489 int m_summon(aClient *cptr, aClient *sptr, int parc, char *parv[])
1490 {
1491 char *host, *user, *chname;
1492 #ifdef ENABLE_SUMMON
1493 char hostbuf[17], namebuf[10], linebuf[10];
1494 # ifdef LEAST_IDLE
1495 char linetmp[10], ttyname[15]; /* Ack */
1496 struct stat stb;
1497 time_t ltime = (time_t)0;
1498 # endif
1499 int fd, flag = 0;
1500 #endif
1501
1502 if (parc < 2 || *parv[1] == '\0')
1503 {
1504 sendto_one(sptr, replies[ERR_NORECIPIENT], ME, BadTo(parv[0]), "SUMMON");
1505 return 1;
1506 }
1507 user = parv[1];
1508 host = (parc < 3 || BadPtr(parv[2])) ? ME : parv[2];
1509 chname = (parc > 3) ? parv[3] : "*";
1510 /*
1511 ** Summoning someone on remote server, find out which link to
1512 ** use and pass the message there...
1513 */
1514 parv[1] = user;
1515 parv[2] = host;
1516 parv[3] = chname;
1517 parv[4] = NULL;
1518 if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) ==
1519 HUNTED_ISME)
1520 {
1521 #ifdef ENABLE_SUMMON
1522 if ((fd = utmp_open()) == -1)
1523 {
1524 sendto_one(sptr, replies[ERR_FILEERROR], ME, BadTo(parv[0]),
1525 "open", UTMP);
1526 return 1;
1527 }
1528
1529 # ifndef LEAST_IDLE
1530 while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf,
1531 sizeof(hostbuf))) == 0)
1532 {
1533 if (StrEq(namebuf,user))
1534 {
1535 break;
1536 }
1537 }
1538 # else /* LEAST_IDLE */
1539 /* use least-idle tty, not the first
1540 * one we find in utmp. 10/9/90 Spike@world.std.com
1541 * (loosely based on Jim Frost jimf@saber.com code)
1542 */
1543
1544 while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf,
1545 sizeof(hostbuf))) == 0)
1546 {
1547 if (StrEq(namebuf,user))
1548 {
1549 sprintf(ttyname,"/dev/%s",linetmp);
1550 if (stat(ttyname,&stb) == -1)
1551 {
1552 sendto_one(sptr,
1553 replies[ERR_FILEERROR],
1554 ME, BadTo(sptr->name),
1555 "stat", ttyname);
1556 return 1;
1557 }
1558 if (!ltime)
1559 {
1560 ltime= stb.st_mtime;
1561 (void)strcpy(linebuf,linetmp);
1562 }
1563 else if (stb.st_mtime > ltime) /* less idle */
1564 {
1565 ltime= stb.st_mtime;
1566 (void)strcpy(linebuf,linetmp);
1567 }
1568 }
1569 }
1570 # endif /* LEAST_IDLE */
1571 (void)utmp_close(fd);
1572 # ifdef LEAST_IDLE
1573 if (ltime == 0)
1574 # else
1575 if (flag == -1)
1576 # endif
1577 {
1578 sendto_one(sptr, replies[ERR_NOLOGIN], ME, BadTo(parv[0]), user);
1579 }
1580 else
1581 {
1582 summon(sptr, user, linebuf, chname);
1583 }
1584 #else /* ENABLE_SUMMON */
1585 sendto_one(sptr, replies[ERR_SUMMONDISABLED], ME, BadTo(parv[0]));
1586 #endif /* ENABLE_SUMMON */
1587 }
1588 else
1589 {
1590 return 3;
1591 }
1592 return 2;
1593 }
1594 /* stats ? - quick info about connected servers
1595 */
report_myservers(aClient * sptr,char * to)1596 static void report_myservers(aClient *sptr, char *to)
1597 {
1598 int i;
1599 int timeconnected;
1600 aClient *acptr;
1601 int users, servers;
1602
1603 for (i = fdas.highest; i >= 0; i--)
1604 {
1605 if (!(acptr = local[fdas.fd[i]]))
1606 {
1607 continue;
1608 }
1609
1610 if (IsMe(acptr) || !IsServer(acptr))
1611 {
1612 continue;
1613 }
1614 timeconnected = timeofday - acptr->firsttime;
1615 count_servers_users(acptr, &servers, &users);
1616 sendto_one(sptr,
1617 ":%s %d %s :%s (%d, %02d:%02d:%02d) %dS %dC"
1618 " %lldkB sent %lldkB recv %ldkB sq %sV%X%s",
1619 ME, RPL_STATSDEBUG, to, acptr->name,
1620 timeconnected / 86400,
1621 (timeconnected % 86400) / 3600,
1622 (timeconnected % 3600)/60,
1623 timeconnected % 60,
1624 servers, users,
1625 (acptr->sendB / 1024) ,
1626 (acptr->receiveB / 1024),
1627 (int) ((int)DBufLength(&acptr->sendQ) / 1024),
1628 IsBursting(acptr) ? "BURST " : "",
1629 acptr->serv->version,
1630 (acptr->flags & FLAGS_ZIP) ? "z" : "");
1631 }
1632 }
1633
1634 /* Count number of servers and users behind client cptr.
1635 ** Values are put on provided servers and users. */
count_servers_users(aClient * cptr,int * servers,int * users)1636 void count_servers_users(aClient *cptr, int *servers, int *users)
1637 {
1638 #ifdef HUB
1639 aServer *asptr;
1640
1641 *servers = 0;
1642 *users = 0;
1643 for (asptr = svrtop; asptr; asptr = asptr->nexts)
1644 {
1645 if (asptr->bcptr->from == cptr)
1646 {
1647 if (!IsMasked(asptr->bcptr))
1648 {
1649 *servers += 1;
1650 }
1651 *users += asptr->usercnt[0];
1652 *users += asptr->usercnt[1];
1653 }
1654 }
1655 #else /* !HUB */
1656 /* we can have only one server linked */
1657 *servers = istat.is_serv - 1;
1658 *users = istat.is_user[0];
1659 *users += istat.is_user[1];
1660 /* is_user includes myclnt, so we have to subtract it */
1661 *users -= istat.is_myclnt;
1662 #endif
1663 return;
1664 }
1665
1666 /*
1667 ** m_stats
1668 ** parv[0] = sender prefix
1669 ** parv[1] = statistics selector (defaults to Message frequency)
1670 ** parv[2] = server name (current server defaulted, if omitted)
1671 **
1672 ** Currently supported are:
1673 ** M = Message frequency (the old stat behaviour)
1674 ** L = Local Link statistics
1675 ** C = Report C and N configuration lines
1676 */
1677 /*
1678 ** m_stats/stats_conf
1679 ** Report N/C-configuration lines from this server. This could
1680 ** report other configuration lines too, but converting the
1681 ** status back to "char" is a bit akward--not worth the code
1682 ** it needs...
1683 **
1684 ** Note: The info is reported in the order the server uses
1685 ** it--not reversed as in ircd.conf!
1686 */
1687
1688 static int report_array[18][3] = {
1689 { CONF_ZCONNECT_SERVER, RPL_STATSCLINE, 'c'},
1690 { CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'},
1691 { CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'},
1692 { CONF_CLIENT, RPL_STATSILINE, 'I'},
1693 { CONF_OTHERKILL, RPL_STATSKLINE, 'k'},
1694 { CONF_KILL, RPL_STATSKLINE, 'K'},
1695 { CONF_QUARANTINED_SERVER,RPL_STATSQLINE, 'Q'},
1696 { CONF_LEAF, RPL_STATSLLINE, 'L'},
1697 { CONF_OPERATOR, RPL_STATSOLINE, 'O'},
1698 { CONF_HUB, RPL_STATSHLINE, 'H'},
1699 { CONF_SERVICE, RPL_STATSSLINE, 'S'},
1700 { CONF_VER, RPL_STATSVLINE, 'V'},
1701 { CONF_BOUNCE, RPL_STATSBLINE, 'B'},
1702 { CONF_DENY, RPL_STATSDLINE, 'D'},
1703 #ifdef TKLINE
1704 { CONF_TOTHERKILL, RPL_STATSKLINE, 'k'},
1705 { CONF_TKILL, RPL_STATSKLINE, 'K'},
1706 #else
1707 { 0, 0, 0}, { 0, 0, 0},
1708 #endif
1709 { 0, 0, 0}
1710 };
1711
1712 #ifdef XLINE
report_x_lines(aClient * sptr,char * to)1713 static void report_x_lines(aClient *sptr, char *to)
1714 {
1715 aConfItem *tmp;
1716
1717 for (tmp = conf; tmp; tmp = tmp->next)
1718 {
1719 if (tmp->status != CONF_XLINE)
1720 continue;
1721
1722 sendto_one(sptr,":%s %d %s X :%s %s %s %s %s %s",
1723 ME, RPL_STATSDEBUG, to,
1724 BadTo(tmp->host), BadTo(tmp->passwd),
1725 BadTo(tmp->name), BadTo(tmp->name2),
1726 BadTo(tmp->name3), BadTo(tmp->source_ip));
1727 }
1728 }
1729 #endif
1730
report_configured_links(aClient * sptr,char * to,int mask)1731 static void report_configured_links(aClient *sptr, char *to, int mask)
1732 {
1733 static char null[] = "<NULL>";
1734 aConfItem *tmp;
1735 int *p, port;
1736 char c, *host, *pass, *name;
1737
1738 if ((mask & (CONF_KILL|CONF_OTHERKILL)))
1739 tmp = kconf;
1740 #ifdef TKLINE
1741 else if ((mask & (CONF_TKILL|CONF_TOTHERKILL)))
1742 tmp = tkconf;
1743 #endif
1744 else
1745 tmp = conf;
1746
1747 for (; tmp; tmp = tmp->next)
1748 if (tmp->status & mask)
1749 {
1750 for (p = &report_array[0][0]; *p; p += 3)
1751 if (*p == tmp->status)
1752 break;
1753 if (!*p)
1754 continue;
1755 c = (char)*(p+2);
1756 host = BadPtr(tmp->host) ? null : tmp->host;
1757 pass = BadPtr(tmp->passwd) ? NULL : tmp->passwd;
1758 name = BadPtr(tmp->name) ? null : tmp->name;
1759 port = (int)tmp->port;
1760 /*
1761 * On K/V lines the passwd contents can be
1762 * displayed on STATS reply. -Vesa
1763 * Also H: is safe, we have SID mask there. --B.
1764 */
1765 if (tmp->status == CONF_KILL
1766 || tmp->status == CONF_OTHERKILL
1767 || tmp->status == CONF_HUB
1768 || tmp->status == CONF_QUARANTINED_SERVER
1769 || tmp->status == CONF_VER)
1770 {
1771 sendto_one(sptr, replies[p[1]], ME, BadTo(to),
1772 c, host, (pass) ? pass : null,
1773 name, port, get_conf_class(tmp));
1774 }
1775 #ifdef TKLINE
1776 else if ((tmp->status & (CONF_TKILL|CONF_TOTHERKILL)))
1777 {
1778 sendto_one(sptr, replies[p[1]], ME, BadTo(to),
1779 c, host, (pass) ? pass : null,
1780 name, tmp->hold - timeofday,
1781 get_conf_class(tmp));
1782 }
1783 #endif
1784 else if ((tmp->status & CONF_CLIENT))
1785 {
1786 sendto_one(sptr, replies[p[1]], ME, BadTo(to),
1787 c, host, (pass) ? "*" : null,
1788 name, port, get_conf_class(tmp),
1789 iline_flags_to_string(tmp->flags));
1790
1791 }
1792 else if ((tmp->status & CONF_OPERATOR))
1793 {
1794 sendto_one(sptr, replies[p[1]], ME, BadTo(to),
1795 c, host, (pass) ? "*" : null,
1796 name, port, get_conf_class(tmp),
1797 oline_flags_to_string(tmp->flags));
1798
1799 }
1800 else
1801 sendto_one(sptr, replies[p[1]], ME, BadTo(to),
1802 c, host, (pass) ? "*" : null,
1803 name, port, get_conf_class(tmp));
1804 }
1805 return;
1806 }
1807
report_ping(aClient * sptr,char * to)1808 static void report_ping(aClient *sptr, char *to)
1809 {
1810 aConfItem *tmp;
1811 aCPing *cp;
1812
1813 for (tmp = conf; tmp; tmp = tmp->next)
1814 if ((cp = tmp->ping) && cp->lseq)
1815 {
1816 if (mycmp(tmp->name, tmp->host))
1817 sprintf(buf,"%s[%s]",tmp->name, tmp->host);
1818 else
1819 (void)strcpy(buf, tmp->name);
1820 sendto_one(sptr, replies[RPL_STATSPING], ME, BadTo(to),
1821 buf, cp->lseq, cp->lrecvd,
1822 cp->ping / (cp->recvd ? cp->recvd : 1),
1823 tmp->pref);
1824 /* sendto_flag(SCH_DEBUG, "%s: %d", buf, cp->seq); */
1825 }
1826 return;
1827 }
1828
report_fd(aClient * sptr,aClient * acptr,char * to)1829 static void report_fd(aClient *sptr, aClient *acptr, char *to)
1830 {
1831 static char locip[100], *ret;
1832 int s;
1833
1834 if (IsMe(acptr) || !acptr->acpt || !IsRegistered(acptr))
1835 return;
1836 ret =
1837 #ifdef INET6
1838 inetntop(AF_INET6,
1839 (char *)&acptr->acpt->ip,
1840 ipv6string, sizeof(ipv6string));
1841 #else
1842 inetntoa((char *)&acptr->acpt->ip);
1843 #endif
1844 s = strlen(ret) + 1;
1845 memcpy(locip, ret, s < sizeof(locip) ? s : sizeof(locip));
1846 locip[sizeof(locip) - 1] = 0;
1847 sendto_one(sptr,":%s %d %s %d %s %d %s %d %s %s %d",
1848 ME,RPL_STATSLINKINFO,to,
1849 acptr->fd,
1850 locip,
1851 acptr->acpt->port,
1852 #ifdef INET6
1853 inetntop(AF_INET6,
1854 (char *)&acptr->ip,
1855 ipv6string, sizeof(ipv6string)),
1856 #else
1857 inetntoa((char *)&acptr->ip),
1858 #endif
1859 acptr->port,acptr->name,
1860 acptr->user ? acptr->user->username : acptr->auth,
1861 acptr->user ? timeofday - acptr->user->last : -1
1862 );
1863 }
1864
m_stats(aClient * cptr,aClient * sptr,int parc,char * parv[])1865 int m_stats(aClient *cptr, aClient *sptr, int parc, char *parv[])
1866 {
1867 static char Lformat[] = ":%s %d %s %s %u %lu %llu %lu %llu :%d";
1868 struct Message *mptr;
1869 aClient *acptr;
1870 char stat = parc > 1 ? parv[1][0] : '\0';
1871 Reg int i;
1872 int wilds, doall;
1873 char *name, *cm;
1874
1875 /* If request from remote client, let's tame it a little. */
1876 if (IsServer(cptr))
1877 {
1878 /* These stats usually output large quantity of lines. */
1879 switch(stat)
1880 {
1881 case 'i': case 'I':
1882 case 'c': case 'C':
1883 case 'k': case 'K':
1884 case 'm': case 'M':
1885 case 't': case 'T':
1886 case 'z': case 'Z':
1887 if (check_link(sptr))
1888 {
1889 sendto_one(sptr, replies[RPL_TRYAGAIN], ME,
1890 BadTo(parv[0]), "STATS");
1891 return 5;
1892 }
1893 }
1894 }
1895 if (parc == 3)
1896 {
1897 if (hunt_server(cptr, sptr, ":%s STATS %s %s",
1898 2, parc, parv) != HUNTED_ISME)
1899 return 5;
1900 }
1901 else if (parc >= 3)
1902 {
1903 if (hunt_server(cptr, sptr, ":%s STATS %s %s %s",
1904 2, parc, parv) != HUNTED_ISME)
1905 return 5;
1906 }
1907
1908 name = (parc > 2) ? parv[2] : ME;
1909 cm = (parc > 3) ? parv[3]: name;
1910 doall = !match(name, ME) && !match(cm, ME);
1911 wilds = index(cm, '*') || index(cm, '?') || index(cm, '#');
1912
1913 #if 0
1914 /* That's useless. Why bother? */
1915 if (parc > 1 && parv[1][1] != '\0')
1916 {
1917 stat = '*';
1918 }
1919 #endif
1920
1921 switch (stat)
1922 {
1923 case 'f' : case 'F' :
1924 /* send list of file descriptors
1925 * Avaible only for local opers for security reasons.
1926 */
1927 if (!is_allowed(sptr, ACL_TRACE) || !MyConnect(sptr))
1928 {
1929 stat = '*';
1930 break;
1931 }
1932 if (doall || wilds)
1933 {
1934 for (i = 0; i <= highest_fd; i++)
1935 {
1936 if (!(acptr = local[i]))
1937 continue;
1938
1939 if (wilds && match(cm, acptr->name))
1940 continue;
1941 report_fd(sptr, acptr, parv[0]);
1942 }
1943 }
1944 else
1945 {
1946 if ((acptr = find_client(cm, NULL)))
1947 report_fd(sptr, acptr, parv[0]);
1948 }
1949 break;
1950
1951 /* fallthru to stats l */
1952
1953 case 'L' : case 'l' :
1954 /*
1955 * send info about connections which match, or all if the
1956 * mask matches ME. Only restrictions are on those who
1957 * are invisible not being visible to 'foreigners' who use
1958 * a wild card based search to list it.
1959 */
1960 if (doall || wilds)
1961 {
1962 if (check_link(sptr))
1963 {
1964 sendto_one(sptr, replies[RPL_TRYAGAIN], ME,
1965 BadTo(parv[0]), "STATS");
1966 return 5;
1967 }
1968 for (i = 0; i <= highest_fd; i++)
1969 {
1970 if (!(acptr = local[i]))
1971 continue;
1972 if (IsUnknown(acptr) &&
1973 !(IsAnOper(sptr) && SendWallops(sptr)))
1974 continue;
1975 if (IsPerson(acptr) && (!MyConnect(sptr)
1976 || !is_allowed(sptr, ACL_TRACE)) && acptr != sptr)
1977 continue;
1978 if (wilds && match(cm, acptr->name))
1979 continue;
1980 sendto_one(cptr, Lformat, ME,
1981 RPL_STATSLINKINFO, parv[0],
1982 get_client_name(acptr, isupper(stat)),
1983 (int)DBufLength(&acptr->sendQ),
1984 acptr->sendM, acptr->sendB,
1985 acptr->receiveM, acptr->receiveB,
1986 (int)(timeofday - acptr->firsttime));
1987 }
1988 }
1989 else
1990 {
1991 if ((acptr = find_client(cm, NULL)) && MyConnect(acptr))
1992 sendto_one(cptr, Lformat, ME,
1993 RPL_STATSLINKINFO, parv[0],
1994 get_client_name(acptr, isupper(stat)),
1995 (int)DBufLength(&acptr->sendQ),
1996 acptr->sendM, acptr->sendB,
1997 acptr->receiveM, acptr->receiveB,
1998 (int)(timeofday - acptr->firsttime));
1999
2000 }
2001 break;
2002 #if defined(USE_IAUTH)
2003 case 'a' : case 'A' : /* iauth configuration */
2004 report_iauth_conf(sptr, parv[0]);
2005 break;
2006 #endif
2007 case 'B' : case 'b' : /* B conf lines */
2008 report_configured_links(cptr, parv[0], CONF_BOUNCE);
2009 break;
2010 case 'c': /* C and N conf lines */
2011 report_configured_links(cptr, parv[0], CONF_CONNECT_SERVER|
2012 CONF_ZCONNECT_SERVER|
2013 CONF_NOCONNECT_SERVER);
2014 break;
2015 case 'd' : case 'D' : /* defines */
2016 send_defines(cptr, parv[0], parv[1]);
2017 break;
2018 case 'H' : case 'h' : /* H, L and D conf lines */
2019 report_configured_links(cptr, parv[0],
2020 CONF_HUB|CONF_LEAF|CONF_DENY);
2021 break;
2022 case 'I' : case 'i' : /* I (and i) conf lines */
2023 report_configured_links(cptr, parv[0], CONF_CLIENT);
2024 break;
2025 case 'k' : /* temporary K lines */
2026 #ifdef TKLINE
2027 #ifdef DISABLE_STATSTKLINE
2028 if (!IsAnOper(sptr))
2029 {
2030 sendto_one(sptr, replies[ERR_NOPRIVILEGES],
2031 ME, BadTo(parv[0]));
2032 return 2;
2033 }
2034 else
2035 #endif
2036 report_configured_links(cptr, parv[0],
2037 (CONF_TKILL|CONF_TOTHERKILL));
2038 break;
2039 #endif
2040 case 'K' : /* K lines */
2041 #ifdef TXT_NOSTATSK
2042 if (!IsAnOper(sptr))
2043 {
2044 sendto_one(sptr, replies[ERR_STATSKLINE],
2045 ME, BadTo(parv[0]));
2046 return 2;
2047 }
2048 else
2049 #endif
2050 report_configured_links(cptr, parv[0],
2051 (CONF_KILL|CONF_OTHERKILL));
2052 break;
2053 case 'M' : case 'm' : /* commands use/stats */
2054 for (mptr = msgtab; mptr->cmd; mptr++)
2055 {
2056 #define _mh(n) (mptr->handlers[n])
2057 if (_mh(0).count + _mh(1).count + _mh(2).count
2058 + _mh(3).count + _mh(4).count > 0)
2059 {
2060 sendto_one(cptr, replies[RPL_STATSCOMMANDS],
2061 ME, BadTo(parv[0]), mptr->cmd,
2062 _mh(0).count, _mh(0).bytes,
2063 _mh(0).rcount, _mh(0).rbytes,
2064 _mh(1).count, _mh(1).bytes,
2065 _mh(1).rcount, _mh(1).rbytes,
2066 _mh(2).count, _mh(2).bytes,
2067 _mh(2).rcount, _mh(2).rbytes,
2068 _mh(3).count, _mh(3).bytes,
2069 _mh(3).rcount, _mh(3).rbytes,
2070 _mh(4).count, _mh(4).bytes,
2071 _mh(4).rcount, _mh(4).rbytes);
2072 }
2073 #undef _mh
2074 }
2075 break;
2076 case 'o' : case 'O' : /* O (and o) lines */
2077 report_configured_links(cptr, parv[0], CONF_OPS);
2078 break;
2079 case 'P': /* ports listening */
2080 report_listeners(sptr, parv[0]);
2081 break;
2082 case 'p' : /* ircd ping stats */
2083 report_ping(sptr, parv[0]);
2084 break;
2085 case 'Q' : case 'q' : /* Q lines */
2086 report_configured_links(cptr,parv[0],CONF_QUARANTINED_SERVER);
2087 break;
2088 case 'R' : case 'r' : /* usage */
2089 send_usage(cptr, parv[0]);
2090 break;
2091 case 'S' : case 's' : /* S lines */
2092 report_configured_links(cptr, parv[0], CONF_SERVICE);
2093 break;
2094 case 'T' : case 't' : /* various statistics */
2095 tstats(cptr, parv[0]);
2096 break;
2097 case 'U' : case 'u' : /* uptime */
2098 {
2099 register time_t now;
2100
2101 now = timeofday - me.since;
2102 sendto_one(sptr, replies[RPL_STATSUPTIME], ME, BadTo(parv[0]),
2103 now/86400, (now/3600)%24, (now/60)%60, now%60);
2104 break;
2105 }
2106 case 'V' : case 'v' : /* V conf lines */
2107 report_configured_links(cptr, parv[0], CONF_VER);
2108 break;
2109 case 'X' :
2110 #ifdef XLINE
2111 if (IsAnOper(sptr))
2112 {
2113 report_x_lines(sptr, parv[0]);
2114 }
2115 #endif
2116 break;
2117 case 'x' : /* lists */
2118 #ifdef DEBUGMODE
2119 send_listinfo(cptr, parv[0]);
2120 #endif
2121 break;
2122 case 'Y' : case 'y' : /* Y lines */
2123 report_classes(cptr, parv[0]);
2124 break;
2125 case 'Z':
2126 #ifdef DEBUGMODE
2127 /* memory use (OPER only) */
2128 if (MyOper(sptr))
2129 count_memory(cptr, parv[0], 1);
2130 else
2131 #endif
2132 case 'z' : /* memory use */
2133 count_memory(cptr, parv[0], 0);
2134 break;
2135 case '?' :
2136 report_myservers(sptr, parv[0]);
2137 break;
2138 default :
2139 stat = '*';
2140 break;
2141 }
2142 sendto_one(cptr, replies[RPL_ENDOFSTATS], ME, BadTo(parv[0]), stat);
2143 return 2;
2144 }
2145
2146 /*
2147 ** m_users
2148 ** parv[0] = sender prefix
2149 ** parv[1] = servername
2150 */
m_users(aClient * cptr,aClient * sptr,int parc,char * parv[])2151 int m_users(aClient *cptr, aClient *sptr, int parc, char *parv[])
2152 {
2153 if (parc > 1 &&
2154 hunt_server(cptr, sptr, ":%s USERS :%s", 1, parc, parv)
2155 != HUNTED_ISME)
2156 {
2157 return 3;
2158 }
2159
2160 #ifdef USERS_RFC1459
2161 {
2162 #ifdef USERS_SHOWS_UTMP
2163 char namebuf[10],linebuf[10],hostbuf[17];
2164 int fd, flag = 0;
2165
2166 if ((fd = utmp_open()) == -1)
2167 {
2168 sendto_one(sptr, replies[ERR_FILEERROR], ME, BadTo(parv[0]),
2169 "open", UTMP);
2170 return 1;
2171 }
2172
2173 sendto_one(sptr, replies[RPL_USERSSTART], ME, BadTo(parv[0]));
2174 while (utmp_read(fd, namebuf, linebuf,
2175 hostbuf, sizeof(hostbuf)) == 0)
2176 {
2177 flag = 1;
2178 sendto_one(sptr, replies[RPL_USERS], ME, BadTo(parv[0]),
2179 namebuf, linebuf, hostbuf);
2180 }
2181 if (flag == 0)
2182 sendto_one(sptr, replies[RPL_NOUSERS], ME, BadTo(parv[0]));
2183
2184 sendto_one(sptr, replies[RPL_ENDOFUSERS], ME, BadTo(parv[0]));
2185 (void)utmp_close(fd);
2186 #else
2187 sendto_one(sptr, replies[ERR_USERSDISABLED], ME, BadTo(parv[0]));
2188 #endif
2189 }
2190 #else /* USERS_RFC1459 */
2191 (void) send_users(cptr, sptr, parc, parv);
2192 #endif /* USERS_RFC1459 */
2193 return 2;
2194 }
2195
send_users(aClient * cptr,aClient * sptr,int parc,char * parv[])2196 int send_users(aClient *cptr, aClient *sptr, int parc, char *parv[])
2197 {
2198 sendto_one(sptr, replies[RPL_LOCALUSERS], ME, BadTo(parv[0]),
2199 istat.is_myclnt, istat.is_m_myclnt,
2200 istat.is_myclnt, istat.is_m_myclnt);
2201 sendto_one(sptr, replies[RPL_GLOBALUSERS], ME, BadTo(parv[0]),
2202 istat.is_user[0] + istat.is_user[1], istat.is_m_users,
2203 istat.is_user[0] + istat.is_user[1], istat.is_m_users);
2204 return 2;
2205 }
2206
2207 /*
2208 ** Note: At least at protocol level ERROR has only one parameter,
2209 ** although this is called internally from other functions
2210 ** --msa
2211 **
2212 ** parv[0] = sender prefix
2213 ** parv[*] = parameters
2214 */
m_error(aClient * cptr,aClient * sptr,int parc,char * parv[])2215 int m_error(aClient *cptr, aClient *sptr, int parc, char *parv[])
2216 {
2217 Reg char *para;
2218
2219 para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>";
2220
2221 Debug((DEBUG_ERROR,"Received ERROR message from %s: %s",
2222 sptr->name, para));
2223 /*
2224 ** Ignore error messages generated by normal user clients
2225 ** (because ill-behaving user clients would flood opers
2226 ** screen otherwise). Pass ERROR's from other sources to
2227 ** the local operator...
2228 */
2229 if (IsPerson(cptr) || IsUnknown(cptr) || IsService(cptr))
2230 return 2;
2231 if (cptr == sptr)
2232 sendto_flag(SCH_ERROR, "from %s -- %s",
2233 get_client_name(cptr, FALSE), para);
2234 else
2235 sendto_flag(SCH_ERROR, "from %s via %s -- %s",
2236 sptr->name, get_client_name(cptr,FALSE), para);
2237 return 2;
2238 }
2239
2240 /*
2241 ** m_help
2242 ** parv[0] = sender prefix
2243 */
m_help(aClient * cptr,aClient * sptr,int parc,char * parv[])2244 int m_help(aClient *cptr, aClient *sptr, int parc, char *parv[])
2245 {
2246 int i;
2247
2248 for (i = 0; msgtab[i].cmd; i++)
2249 sendto_one(sptr,":%s NOTICE %s :%s",
2250 ME, parv[0], msgtab[i].cmd);
2251 return 2;
2252 }
2253
2254 /*
2255 * parv[0] = sender
2256 * parv[1] = host/server mask.
2257 * parv[2] = server to query
2258 */
m_lusers(aClient * cptr,aClient * sptr,int parc,char * parv[])2259 int m_lusers(aClient *cptr, aClient *sptr, int parc, char *parv[])
2260 {
2261 int all = 0; /* showing counts of all clients */
2262 int s_count = 0, /* server */
2263 c_count = 0, /* client (visible) */
2264 u_count = 0, /* unknown */
2265 i_count = 0, /* invisible client */
2266 o_count = 0, /* operator */
2267 v_count = 0; /* service */
2268 int m_clients = 0, /* my clients */
2269 m_servers = 0, /* my server links */
2270 m_services = 0; /* my services */
2271
2272 if (parc > 2)
2273 {
2274 if (hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv)
2275 != HUNTED_ISME)
2276 return 3;
2277 }
2278
2279 if (parc > 1)
2280 {
2281 (void)collapse(parv[1]);
2282 }
2283
2284 if (parc == 1 || (parv[1][0] == '*' && parv[1][1] == '\0'))
2285 {
2286 all = 1;
2287 s_count = istat.is_serv;
2288 c_count = istat.is_user[0];
2289 i_count = istat.is_user[1];
2290 u_count = istat.is_unknown;
2291 o_count = istat.is_oper;
2292 v_count = istat.is_service;
2293 m_clients = istat.is_myclnt;
2294 m_servers = istat.is_myserv;
2295 m_services = istat.is_myservice;
2296 }
2297 else
2298 {
2299 aClient *acptr;
2300 aServer *asptr;
2301 aService *svcp;
2302
2303 if ((acptr = find_client(parv[1], NULL)) && IsServer(acptr))
2304 {
2305 /* LUSERS <server> */
2306 s_count = 1;
2307 c_count = acptr->serv->usercnt[0];
2308 i_count = acptr->serv->usercnt[1];
2309 o_count = acptr->serv->usercnt[2];
2310
2311 if (IsMe(acptr))
2312 {
2313 m_clients = istat.is_myclnt;
2314 m_servers = istat.is_myserv;
2315 m_services = istat.is_myservice;
2316 u_count = istat.is_unknown;
2317
2318 }
2319 }
2320 else
2321 {
2322 /* LUSERS <mask> */
2323 for (asptr = svrtop; asptr; asptr = asptr->nexts)
2324 {
2325 if (!match(parv[1], asptr->bcptr->name))
2326 {
2327 s_count++;
2328
2329 c_count += asptr->usercnt[0];
2330 i_count += asptr->usercnt[1];
2331 o_count += asptr->usercnt[2];
2332
2333 if (IsMe(asptr->bcptr))
2334 {
2335 m_clients = istat.is_myclnt;
2336 m_servers = istat.is_myserv;
2337 m_services = istat.is_myservice;
2338 u_count = istat.is_unknown;
2339
2340 }
2341 }
2342 }
2343 }
2344 /* Count services, but only if we found some matching server
2345 * before (to prevent wrong matches on masks like *irc*).
2346 */
2347 if (s_count)
2348 {
2349 for (svcp = svctop; svcp; svcp = svcp->nexts)
2350 {
2351 if (!match(parv[1], svcp->servp->bcptr->name))
2352 {
2353 v_count++;
2354 }
2355 }
2356 }
2357 }
2358
2359 sendto_one(sptr, replies[RPL_LUSERCLIENT], ME, BadTo(parv[0]),
2360 c_count + i_count, v_count, s_count);
2361 if (o_count)
2362 {
2363 sendto_one(sptr, replies[RPL_LUSEROP], ME, BadTo(parv[0]),
2364 o_count);
2365 }
2366 if (u_count)
2367 {
2368 sendto_one(sptr, replies[RPL_LUSERUNKNOWN], ME, parv[0],
2369 u_count);
2370 }
2371 sendto_one(sptr, replies[RPL_LUSERCHANNELS], ME, BadTo(parv[0]),
2372 istat.is_chan);
2373
2374 sendto_one(sptr, replies[RPL_LUSERME], ME, BadTo(parv[0]), m_clients,
2375 m_services, m_servers);
2376 if (all)
2377 (void) send_users(cptr, sptr, parc, parv);
2378 return 2;
2379 }
2380
2381
2382 /***********************************************************************
2383 * m_connect() - Added by Jto 11 Feb 1989
2384 ***********************************************************************/
2385
2386 /*
2387 ** m_connect
2388 ** parv[0] = sender prefix
2389 ** parv[1] = servername
2390 ** parv[2] = port number
2391 ** parv[3] = remote server
2392 */
m_connect(aClient * cptr,aClient * sptr,int parc,char * parv[])2393 int m_connect(aClient *cptr, aClient *sptr, int parc, char *parv[])
2394 {
2395 int port, tmpport, retval;
2396 aConfItem *aconf;
2397 aClient *acptr;
2398
2399 if (!is_allowed(sptr, parc > 3 ? ACL_CONNECTREMOTE : ACL_CONNECTLOCAL))
2400 {
2401 return m_nopriv(cptr, sptr, parc, parv);
2402 }
2403
2404 if ((bootopt & BOOT_STANDALONE))
2405 {
2406 sendto_one(sptr, ":%s NOTICE %s :Connect disabled, running in"
2407 " standalone mode", ME, parv[0]);
2408 return 0;
2409 }
2410
2411 if (hunt_server(cptr,sptr,":%s CONNECT %s %s :%s",
2412 3,parc,parv) != HUNTED_ISME)
2413 return 1;
2414
2415 if ((acptr = find_name(parv[1], NULL))
2416 || (acptr = find_mask(parv[1], NULL)))
2417 {
2418 sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.",
2419 ME, parv[0], parv[1], "already exists from",
2420 acptr->from->name);
2421 return 0;
2422 }
2423
2424 for (aconf = conf; aconf; aconf = aconf->next)
2425 if ((aconf->status == CONF_CONNECT_SERVER ||
2426 aconf->status == CONF_ZCONNECT_SERVER) &&
2427 match(parv[1], aconf->name) == 0)
2428 break;
2429 /* Checked first servernames, then try hostnames. */
2430 if (!aconf)
2431 for (aconf = conf; aconf; aconf = aconf->next)
2432 if ((aconf->status == CONF_CONNECT_SERVER ||
2433 aconf->status == CONF_ZCONNECT_SERVER) &&
2434 (match(parv[1], aconf->host) == 0 ||
2435 match(parv[1], index(aconf->host, '@')+1) == 0))
2436 break;
2437
2438 if (!aconf)
2439 {
2440 sendto_one(sptr,
2441 "NOTICE %s :Connect: Host %s not listed in ircd.conf",
2442 parv[0], parv[1]);
2443 return 0;
2444 }
2445 /*
2446 ** Get port number from user, if given. If not specified,
2447 ** use the default form configuration structure. If missing
2448 ** from there, then use the precompiled default.
2449 */
2450 tmpport = port = aconf->port;
2451 if (parc > 2)
2452 {
2453 port = atoi(parv[2]);
2454 }
2455
2456 if (parc < 3 || port == 0)
2457 {
2458 port = abs(tmpport);
2459 if (port == 0)
2460 {
2461 sendto_one(sptr,
2462 ":%s NOTICE %s :Connect: missing port number",
2463 ME, parv[0]);
2464 return 0;
2465 }
2466 }
2467 if (port <= 0)
2468 {
2469 sendto_one(sptr, "NOTICE %s :Connect: Illegal port number",
2470 parv[0]);
2471 return 0;
2472 }
2473
2474 /*
2475 ** Notify all operators about remote connect requests
2476 */
2477 if (!IsAnOper(cptr))
2478 {
2479 sendto_ops_butone(NULL, ME,
2480 "Remote CONNECT %s %d from %s",
2481 parv[1], port,
2482 get_client_name(sptr,FALSE));
2483 #if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT)
2484 syslog(LOG_DEBUG, "CONNECT From %s : %s %s", parv[0],
2485 parv[1], parv[2] ? parv[2] : "");
2486 #endif
2487 }
2488 aconf->port = port;
2489 switch (retval = connect_server(aconf, sptr, NULL))
2490 {
2491 case 0:
2492 sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s[%s].",
2493 ME, parv[0], aconf->host, aconf->name);
2494 sendto_flag(SCH_NOTICE, "Connecting to %s[%s] by %s",
2495 aconf->host, aconf->name,
2496 get_client_name(sptr, FALSE));
2497 break;
2498 case -1:
2499 sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.",
2500 ME, parv[0], aconf->host);
2501 sendto_flag(SCH_NOTICE, "Couldn't connect to %s by %s",
2502 aconf->host, get_client_name(sptr, FALSE));
2503 break;
2504 case -2:
2505 sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.",
2506 ME, parv[0], aconf->host);
2507 sendto_flag(SCH_NOTICE, "Connect by %s to unknown host %s",
2508 get_client_name(sptr, FALSE), aconf->host);
2509 break;
2510 default:
2511 sendto_one(sptr,
2512 ":%s NOTICE %s :*** Connection to %s failed: %s",
2513 ME, parv[0], aconf->host, strerror(retval));
2514 sendto_flag(SCH_NOTICE, "Connection to %s by %s failed: %s",
2515 aconf->host, get_client_name(sptr, FALSE),
2516 strerror(retval));
2517 }
2518 aconf->port = tmpport;
2519 return 0;
2520 }
2521
2522 /*
2523 ** m_wallops (write to *all* opers currently online)
2524 ** parv[0] = sender prefix
2525 ** parv[1] = message text
2526 */
m_wallops(aClient * cptr,aClient * sptr,int parc,char * parv[])2527 int m_wallops(aClient *cptr, aClient *sptr, int parc, char *parv[])
2528 {
2529 sendto_ops_butone(IsServer(cptr) ? cptr : NULL, parv[0], "%s", parv[1]);
2530 #ifdef USE_SERVICES
2531 check_services_butone(SERVICE_WANT_WALLOP, NULL, sptr,
2532 ":%s WALLOP :%s", parv[0], parv[1]);
2533 #endif
2534 return 2;
2535 }
2536
2537 /*
2538 ** m_time
2539 ** parv[0] = sender prefix
2540 ** parv[1] = servername
2541 */
m_time(aClient * cptr,aClient * sptr,int parc,char * parv[])2542 int m_time(aClient *cptr, aClient *sptr, int parc, char *parv[])
2543 {
2544 if (hunt_server(cptr,sptr,":%s TIME :%s",1,parc,parv) == HUNTED_ISME)
2545 sendto_one(sptr, replies[RPL_TIME], ME, BadTo(parv[0]), ME, date((long)0));
2546 return 2;
2547 }
2548
2549
2550 /*
2551 ** m_admin
2552 ** parv[0] = sender prefix
2553 ** parv[1] = servername
2554 */
m_admin(aClient * cptr,aClient * sptr,int parc,char * parv[])2555 int m_admin(aClient *cptr, aClient *sptr, int parc, char *parv[])
2556 {
2557 aConfItem *aconf;
2558
2559 if (IsRegistered(cptr) && /* only local query for unregistered */
2560 hunt_server(cptr,sptr,":%s ADMIN :%s",1,parc,parv) != HUNTED_ISME)
2561 return 3;
2562 if ((aconf = find_admin()) && aconf->host && aconf->passwd
2563 && aconf->name)
2564 {
2565 sendto_one(sptr, replies[RPL_ADMINME], ME, BadTo(parv[0]), ME);
2566 sendto_one(sptr, replies[RPL_ADMINLOC1], ME, BadTo(parv[0]), aconf->host);
2567 sendto_one(sptr, replies[RPL_ADMINLOC2], ME, BadTo(parv[0]),
2568 aconf->passwd);
2569 sendto_one(sptr, replies[RPL_ADMINEMAIL], ME, BadTo(parv[0]),
2570 aconf->name);
2571 }
2572 else
2573 sendto_one(sptr, replies[ERR_NOADMININFO], ME, BadTo(parv[0]), ME);
2574 return 2;
2575 }
2576
2577 /*
2578 ** m_rehash
2579 **
2580 */
m_rehash(aClient * cptr,aClient * sptr,int parc,char * parv[])2581 int m_rehash(aClient *cptr, aClient *sptr, int parc, char *parv[])
2582 {
2583 if (!is_allowed(sptr, ACL_REHASH))
2584 return m_nopriv(cptr, sptr, parc, parv);
2585
2586 sendto_one(sptr, replies[RPL_REHASHING], ME, BadTo(parv[0]),
2587 mybasename(configfile));
2588 sendto_flag(SCH_NOTICE,
2589 "%s is rehashing Server config file", parv[0]);
2590 #ifdef USE_SYSLOG
2591 syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE));
2592 #endif
2593 return rehash(cptr, sptr, (parc > 1) ? parv[1][0] : 0);
2594 }
2595
2596 /*
2597 ** m_restart
2598 **
2599 */
m_restart(aClient * cptr,aClient * sptr,int parc,char * parv[])2600 int m_restart(aClient *cptr, aClient *sptr, int parc, char *parv[])
2601 {
2602 Reg aClient *acptr;
2603 Reg int i;
2604 char killer[HOSTLEN * 2 + USERLEN + 5];
2605
2606 if (!is_allowed(sptr, ACL_RESTART))
2607 return m_nopriv(cptr, sptr, parc, parv);
2608
2609 strcpy(killer, get_client_name(sptr, TRUE));
2610 sprintf(buf, "RESTART by %s", get_client_name(sptr, TRUE));
2611 for (i = 0; i <= highest_fd; i++)
2612 {
2613 if (!(acptr = local[i]))
2614 continue;
2615 if (IsClient(acptr) || IsService(acptr))
2616 {
2617 sendto_one(acptr,
2618 ":%s NOTICE %s :Server Restarting. %s",
2619 ME, acptr->name, killer);
2620 acptr->exitc = EXITC_DIE;
2621 if (IsClient(acptr))
2622 exit_client(acptr, acptr, &me,
2623 "Server Restarting");
2624 /* services are kept for logging purposes */
2625 }
2626 else if (IsServer(acptr))
2627 sendto_one(acptr, ":%s ERROR :Restarted by %s",
2628 ME, killer);
2629 }
2630 flush_connections(me.fd);
2631
2632 restart(buf);
2633 /*NOT REACHED*/
2634 return 0;
2635 }
2636
trace_one(aClient * sptr,aClient * acptr)2637 static void trace_one(aClient *sptr, aClient *acptr)
2638 {
2639 char *name;
2640 int class;
2641 char *to;
2642
2643 /* to = #ST_UID#IsServer(acptr) && sptr->user ? sptr->user->uid : sptr->name; */
2644 to = sptr->name;
2645 name = get_client_name(acptr, FALSE);
2646 class = get_client_class(acptr);
2647
2648 switch (acptr->status)
2649 {
2650 case STAT_CONNECTING:
2651 sendto_one(sptr, replies[RPL_TRACECONNECTING],ME, to,
2652 class, name);
2653 break;
2654
2655 case STAT_HANDSHAKE:
2656 sendto_one(sptr, replies[RPL_TRACEHANDSHAKE], ME, to,
2657 class, name);
2658 break;
2659
2660 case STAT_ME:
2661 break;
2662
2663 case STAT_UNKNOWN:
2664 sendto_one(sptr, replies[RPL_TRACEUNKNOWN], ME, to,
2665 class, name);
2666 break;
2667
2668 case STAT_OPER:
2669 sendto_one(sptr, replies[RPL_TRACEOPERATOR], ME,
2670 to, class, name);
2671 break;
2672
2673 case STAT_CLIENT:
2674 sendto_one(sptr, replies[RPL_TRACEUSER], ME,
2675 to, class, name);
2676 break;
2677
2678 case STAT_SERVER:
2679 {
2680 /* we need to count servers/users behind this link */
2681 int servers = 0, users = 0;
2682 count_servers_users(acptr, &servers, &users);
2683 if (acptr->serv->user)
2684 {
2685 sendto_one(sptr, replies[RPL_TRACESERVER], ME,
2686 to, class, servers,
2687 users, name, acptr->serv->by,
2688 acptr->serv->user->username,
2689 acptr->serv->user->host,
2690 acptr->serv->version,
2691 (acptr->flags & FLAGS_ZIP) ?
2692 "z" : "");
2693 }
2694 else
2695 {
2696 sendto_one(sptr, replies[RPL_TRACESERVER], ME,
2697 to, class, servers,
2698 users, name,
2699 *(acptr->serv->by) ?
2700 acptr->serv->by : "*", "*", ME,
2701 acptr->serv->version,
2702 (acptr->flags & FLAGS_ZIP) ?
2703 "z" : "");
2704 }
2705 break;
2706 }
2707
2708 case STAT_SERVICE:
2709 sendto_one(sptr, replies[RPL_TRACESERVICE], ME, to,
2710 class, name,
2711 acptr->service->type, acptr->service->wants);
2712 break;
2713
2714 default: /* ...we actually shouldn't come here... --msa */
2715 sendto_one(sptr, replies[RPL_TRACENEWTYPE], ME, to,
2716 name);
2717 break;
2718 }
2719 }
2720
2721 /*
2722 * m_trace
2723 * parv[0] = sender prefix
2724 * parv[1] = traced nick/server/service
2725 */
m_trace(aClient * cptr,aClient * sptr,int parc,char * parv[])2726 int m_trace(aClient *cptr, aClient *sptr, int parc, char *parv[])
2727 {
2728 aClient *acptr;
2729 int maskedserv = 0;
2730 int showsid = 0;
2731 int i = 0;
2732
2733 if (parc > 1)
2734 {
2735 /* wildcards now allowed only in server/service names */
2736 acptr = find_matching_client(parv[1]);
2737 if (!acptr)
2738 {
2739 acptr = find_sid(parv[1], NULL);
2740 if (acptr)
2741 {
2742 showsid = 1;
2743 }
2744 }
2745 if (!acptr)
2746 {
2747 sendto_one(sptr, replies[ERR_NOSUCHSERVER],
2748 ME, BadTo(parv[0]), parv[1]);
2749 return 1;
2750 }
2751 if (IsServer(acptr))
2752 {
2753 if (!match(acptr->name, parv[1]))
2754 {
2755 /* if we are tracing masked server
2756 * we have to send parv[1], not acptr->name
2757 */
2758 maskedserv = 1;
2759 }
2760 }
2761 }
2762 else
2763 {
2764 acptr = &me;
2765 }
2766
2767 if (!IsMe(acptr))
2768 {
2769 if (!MyConnect(acptr) || IsServer(acptr))
2770 {
2771 if (acptr->from == cptr)
2772 { /* eek ?! */
2773 return 1;
2774 }
2775 /* passthru */
2776 sendto_one(sptr, replies[RPL_TRACELINK], ME,
2777 BadTo(parv[0]), version, debugmode,
2778 (maskedserv || showsid) ?
2779 parv[1] : acptr->name,
2780 acptr->from->name,
2781 acptr->from->serv->version,
2782 (acptr->from->flags & FLAGS_ZIP) ? "z" : "",
2783 (int)(timeofday - acptr->from->firsttime),
2784 (int)DBufLength(&acptr->from->sendQ),
2785 (int)DBufLength(&sptr->from->sendQ));
2786
2787 sendto_one(acptr, ":%s TRACE :%s", sptr->name,
2788 (maskedserv || showsid) ? parv[1] : acptr->name);
2789 return 5;
2790 }
2791 else
2792 {
2793 /* tracing something local */
2794 trace_one(sptr, acptr);
2795 }
2796 }
2797 else
2798 {
2799 /* report everything */
2800 aClient *a2cptr;
2801
2802 for (i = 0; i <= highest_fd; i++)
2803 {
2804 if (!(a2cptr = local[i]))
2805 {
2806 continue;
2807 }
2808 if (IsMe(a2cptr))
2809 {
2810 continue;
2811 }
2812 if (IsPerson(a2cptr) /* if client about to
2813 * trace is person */
2814 && !(a2cptr == sptr) /* but not user self */
2815 && !(IsAnOper(a2cptr)) /* nor some oper */
2816 && (!MyConnect(sptr) ||
2817 !is_allowed(sptr, ACL_TRACE))
2818 /* nor it is my oper
2819 * doing trace */
2820 )
2821 {
2822 continue; /* then don't show the client */
2823 }
2824
2825 /* Report unknown connections to opers with +w set */
2826 if (IsUnknown(a2cptr) &&
2827 !(IsAnOper(sptr) && SendWallops(sptr)))
2828 {
2829 continue;
2830 }
2831 trace_one(sptr, a2cptr);
2832 }
2833 }
2834 sendto_one(sptr, replies[RPL_TRACEEND], ME, BadTo(parv[0]),
2835 showsid ? me.serv->sid : acptr->name, version, debugmode);
2836
2837 return 2;
2838 }
2839
2840 /*
2841 * m_etrace
2842 * parv[0] = sender prefix
2843 */
m_etrace(aClient * cptr,aClient * sptr,int parc,char * parv[])2844 int m_etrace(aClient *cptr, aClient *sptr, int parc, char *parv[])
2845 {
2846 aClient *acptr;
2847 int i = 0;
2848
2849 if (!MyClient(sptr) || !is_allowed(sptr, ACL_TRACE))
2850 return m_nopriv(cptr, sptr, parc, parv);
2851
2852 if (parc > 1)
2853 {
2854 if ((acptr = find_person(parv[1], NULL)) && MyClient(acptr))
2855 sendto_one(sptr, replies[RPL_ETRACEFULL],
2856 ME, sptr->name,
2857 IsAnOper(acptr) ? "Oper" : "User",
2858 get_client_class(acptr),
2859 acptr->name, acptr->user->username,
2860 acptr->user->host, acptr->user->sip,
2861 #ifdef XLINE
2862 acptr->user2, acptr->user3,
2863 #else
2864 "-", "-",
2865 #endif
2866 acptr->info);
2867 }
2868 else
2869 {
2870 for (i = 0; i <= highest_fd; i++)
2871 {
2872 if (!(acptr = local[i]))
2873 continue;
2874
2875 if (!IsPerson(acptr))
2876 continue;
2877
2878 sendto_one(sptr, replies[RPL_ETRACEFULL],
2879 ME, sptr->name,
2880 IsAnOper(acptr) ? "Oper" : "User",
2881 get_client_class(acptr),
2882 acptr->name, acptr->user->username,
2883 acptr->user->host, acptr->user->sip,
2884 #ifdef XLINE
2885 acptr->user2, acptr->user3,
2886 #else
2887 "-", "-",
2888 #endif
2889 acptr->info);
2890 }
2891 }
2892
2893 sendto_one(sptr, replies[RPL_ETRACEEND], ME, sptr->name, ME,
2894 version, debugmode);
2895 return 2;
2896 }
2897
2898 #ifdef ENABLE_SIDTRACE
m_sidtrace(aClient * cptr,aClient * sptr,int parc,char * parv[])2899 int m_sidtrace(aClient *cptr, aClient *sptr, int parc, char *parv[])
2900 {
2901 aClient *acptr;
2902
2903 if (!MyClient(sptr) || !is_allowed(sptr, ACL_SIDTRACE))
2904 return m_nopriv(cptr, sptr, parc, parv);
2905
2906 for (acptr = client; acptr; acptr = acptr->next)
2907 {
2908 if (!IsPerson(acptr))
2909 continue;
2910
2911 if (strncmp(acptr->user->uid, me.serv->sid, SIDLEN-1))
2912 continue;
2913
2914 sendto_one(sptr, replies[RPL_ETRACEFULL],
2915 ME, sptr->name,
2916 IsAnOper(acptr) ? "Oper" : "User",
2917 MyClient(acptr) ? get_client_class(acptr) : -1,
2918 acptr->name, acptr->user->username,
2919 acptr->user->host, acptr->user->sip,
2920 #ifdef XLINE
2921 MyClient(acptr) ? acptr->user2 : "-",
2922 MyClient(acptr) ? acptr->user3 : "-",
2923 #else
2924 "-", "-",
2925 #endif
2926 acptr->info);
2927 }
2928
2929 sendto_one(sptr, replies[RPL_ETRACEEND], ME, sptr->name, "*",
2930 version, debugmode);
2931
2932 return 3;
2933 }
2934 #endif
2935
2936 /*
2937 ** m_motd
2938 ** parv[0] = sender prefix
2939 ** parv[1] = servername
2940 */
m_motd(aClient * cptr,aClient * sptr,int parc,char * parv[])2941 int m_motd(aClient *cptr, aClient *sptr, int parc, char *parv[])
2942 {
2943 register aMotd *temp;
2944 struct tm *tm;
2945
2946 if (!IsUnknown(sptr))
2947 {
2948 if (check_link(sptr))
2949 {
2950 sendto_one(sptr, replies[RPL_TRYAGAIN], ME, BadTo(parv[0]), "MOTD");
2951 return 5;
2952 }
2953 if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1,parc,parv)!=HUNTED_ISME)
2954 return 5;
2955 }
2956 tm = localtime(&motd_mtime);
2957 if (motd == NULL)
2958 {
2959 sendto_one(sptr, replies[ERR_NOMOTD], ME, BadTo(parv[0]));
2960 return 1;
2961 }
2962 sendto_one(sptr, replies[RPL_MOTDSTART], ME, BadTo(parv[0]), ME);
2963 sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", ME, RPL_MOTD,
2964 BadTo(parv[0]), tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year,
2965 tm->tm_hour, tm->tm_min);
2966 temp = motd;
2967 for(temp=motd;temp != NULL;temp = temp->next)
2968 sendto_one(sptr, replies[RPL_MOTD], ME, BadTo(parv[0]), temp->line);
2969 sendto_one(sptr, replies[RPL_ENDOFMOTD], ME, BadTo(parv[0]));
2970 return IsUnknown(sptr) ? 5 : 2;
2971 }
2972
2973 /*
2974 ** m_close - added by Darren Reed Jul 13 1992.
2975 */
m_close(aClient * cptr,aClient * sptr,int parc,char * parv[])2976 int m_close(aClient *cptr, aClient *sptr, int parc, char *parv[])
2977 {
2978 Reg aClient *acptr;
2979 Reg int i;
2980 int closed = 0;
2981
2982 if (!is_allowed(sptr, ACL_CLOSE))
2983 return m_nopriv(cptr, sptr, parc, parv);
2984
2985 for (i = highest_fd; i; i--)
2986 {
2987 if (!(acptr = local[i]))
2988 continue;
2989 if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
2990 !IsHandshake(acptr))
2991 continue;
2992 sendto_one(sptr, replies[RPL_CLOSING], ME, BadTo(parv[0]),
2993 get_client_name(acptr, TRUE), acptr->status);
2994 (void)exit_client(acptr, acptr, &me, "Oper Closing");
2995 closed++;
2996 }
2997 sendto_one(sptr, replies[RPL_CLOSEEND], ME, BadTo(parv[0]), closed);
2998 sendto_flag(SCH_NOTICE, "%s closed %d unknown connections", sptr->name,
2999 closed);
3000 #ifdef DELAY_CLOSE
3001 closed = istat.is_delayclosewait;
3002 delay_close(-2);
3003 sendto_flag(SCH_NOTICE, "%s closed %d delayed connections", sptr->name,
3004 closed);
3005 #endif
3006 return 1;
3007 }
3008
3009 /* End Of Burst command
3010 ** parv[0] - server sending the EOB
3011 ** parv[1] - optional comma separated list of servers for which this EOB
3012 ** is also valid.
3013 */
m_eob(aClient * cptr,aClient * sptr,int parc,char * parv[])3014 int m_eob(aClient *cptr, aClient *sptr, int parc, char *parv[])
3015 {
3016 char eobbuf[BUFSIZE];
3017 char *e;
3018 char *sid;
3019 char *p = NULL;
3020 int eobmaxlen;
3021 aClient *acptr;
3022
3023 if (!IsServer(sptr))
3024 {
3025 return 0;
3026 }
3027 if (IsBursting(sptr))
3028 {
3029 if (MyConnect(sptr))
3030 {
3031 sendto_flag(SCH_NOTICE,
3032 "End of burst from %s after %d seconds.",
3033 sptr->name, timeofday - sptr->firsttime);
3034 }
3035 else
3036 {
3037 if (!IsMasked(sptr))
3038 {
3039 sendto_flag(SCH_NOTICE, "End of burst from %s",
3040 sptr->name);
3041 }
3042 }
3043 SetEOB(sptr);
3044 istat.is_eobservers++;
3045 if (sptr->hopcount == 1)
3046 {
3047 sendto_one(sptr, ":%s EOBACK", me.serv->sid);
3048 }
3049
3050 if (parc < 2)
3051 {
3052 sendto_serv_v(sptr, SV_UID, ":%s EOB", sptr->serv->sid);
3053 return 1;
3054 }
3055
3056 }
3057 else
3058 {
3059 if (parc < 2)
3060 {
3061 sendto_flag(SCH_ERROR,
3062 "Received another EOB for server %s (%s)",
3063 sptr->serv->sid, sptr->name);
3064 return 1;
3065 }
3066 }
3067
3068 eobmaxlen = BUFSIZE
3069 - 1 /* ":" */
3070 - SIDLEN /* my SID */
3071 - 6 /* " EOB :" */
3072 - 2; /* "\r\n" */
3073
3074 /* space for last comma and SID (calculation moved
3075 * from "if (e - eobbuf > eobmaxlen)" inside following loop)
3076 */
3077 eobmaxlen -= SIDLEN + 1;
3078
3079 e = eobbuf;
3080
3081 for (; (sid = strtoken(&p, parv[1], ",")); parv[1] = NULL)
3082 {
3083 acptr = NULL;
3084
3085 acptr = find_sid(sid, NULL);
3086 if (!acptr)
3087 {
3088 sendto_flag(SCH_SERVER,
3089 "Received EOB for unknown SID (%s) from (%s), "
3090 "dropping link",
3091 sid, cptr->name);
3092 return exit_client(cptr, cptr, &me,
3093 "Unknown SID in EOB");
3094 }
3095
3096 if (acptr->from != cptr)
3097 {
3098 sendto_flag(SCH_NOTICE,
3099 "Received EOB for (%s) from wrong direction "
3100 "(%s != %s), dropping link",
3101 sid, sptr->name, acptr->from->name);
3102 return exit_client(cptr, cptr, &me,
3103 "Wrong EOB Direction");
3104 }
3105
3106 if (!IsBursting(acptr))
3107 {
3108 sendto_flag(SCH_ERROR,
3109 "Received another EOB for server %s (%s) from "
3110 "%s (%s) via %s", sid, acptr->name,
3111 sptr->serv->sid, sptr->name, cptr->name);
3112
3113 continue;
3114 }
3115
3116
3117 sendto_flag(SCH_DEBUG, "Received EOB for %s [%s] (mass)",
3118 acptr->name, acptr->serv->sid);
3119
3120 /* SIDLEN + 1 = ",SID" */
3121 if (((int) (e - eobbuf)) > eobmaxlen)
3122 {
3123 *e = '\0';
3124 /* We have exceeded available space in buf.
3125 * eobbuf always starts with comma, * so +1 gets
3126 * rid of it */
3127 sendto_serv_v(sptr, SV_UID, ":%s EOB :%s",
3128 sptr->serv->sid, eobbuf + 1);
3129 e = eobbuf;
3130 }
3131
3132 SetEOB(acptr);
3133 istat.is_eobservers++;
3134 /* regenerate buffer - it might be fake sid,
3135 ** which will change at this point - jv
3136 */
3137 *e++ = ',';
3138 memcpy(e, acptr->serv->sid, SIDLEN);
3139 e += SIDLEN;
3140
3141 }
3142
3143 /* Send the rest, if any */
3144 if (e > eobbuf)
3145 {
3146 *e = '\0';
3147 sendto_serv_v(sptr, SV_UID, ":%s EOB :%s",
3148 sptr->serv->sid, eobbuf + 1);
3149 }
3150 else
3151 {
3152 sendto_serv_v(sptr, SV_UID, ":%s EOB", sptr->serv->sid);
3153 }
3154
3155 check_split();
3156
3157 return 1;
3158 }
3159
m_eoback(aClient * cptr,aClient * sptr,int parc,char * parv[])3160 int m_eoback(aClient *cptr, aClient *sptr, int parc, char *parv[])
3161 {
3162 cptr->flags &= ~FLAGS_CBURST;
3163 if (cptr->serv && cptr->serv->byuid[0])
3164 {
3165 /* no need to report link break few days later, is there? --B. */
3166 cptr->serv->byuid[0] = '\0';
3167 }
3168 return 0;
3169 }
3170
3171
m_die(aClient * cptr,aClient * sptr,int parc,char * parv[])3172 int m_die(aClient *cptr, aClient *sptr, int parc, char *parv[])
3173 {
3174 Reg aClient *acptr;
3175 Reg int i;
3176 char killer[HOSTLEN * 2 + USERLEN + 5];
3177
3178 if (!is_allowed(sptr, ACL_DIE))
3179 return m_nopriv(cptr, sptr, parc, parv);
3180
3181 strcpy(killer, get_client_name(sptr, TRUE));
3182 for (i = 0; i <= highest_fd; i++)
3183 {
3184 if (!(acptr = local[i]))
3185 continue;
3186 if (IsClient(acptr) || IsService(acptr))
3187 {
3188 sendto_one(acptr,
3189 ":%s NOTICE %s :Server Terminating. %s",
3190 ME, acptr->name, killer);
3191 acptr->exitc = EXITC_DIE;
3192 if (IsClient(acptr))
3193 exit_client(acptr, acptr, &me, "Server died");
3194 /* services are kept for logging purposes */
3195 }
3196 else if (IsServer(acptr))
3197 sendto_one(acptr, ":%s ERROR :Terminated by %s",
3198 ME, killer);
3199 }
3200 flush_connections(me.fd);
3201 (void)s_die(0);
3202 return 0;
3203 }
3204
m_set(aClient * cptr,aClient * sptr,int parc,char * parv[])3205 int m_set(aClient *cptr, aClient *sptr, int parc, char *parv[])
3206 {
3207 typedef struct
3208 {
3209 int id;
3210 char *command;
3211 } SetEntry;
3212
3213 SetEntry set_table[] =
3214 {
3215 { TSET_POOLSIZE, "POOLSIZE" },
3216 { TSET_ACONNECT, "ACONNECT" },
3217 { TSET_CACCEPT, "CACCEPT" },
3218 { TSET_SPLIT, "SPLIT" },
3219 { 0, NULL }
3220 };
3221 int i, acmd = 0;
3222
3223 if (!is_allowed(sptr, ACL_SET))
3224 return m_nopriv(cptr, sptr, parc, parv);
3225
3226 if (parc > 1)
3227 {
3228 /* Find specified command */
3229 for (i = 0; set_table[i].command != NULL; i++)
3230 {
3231 if (!mycmp(parv[1], set_table[i].command))
3232 {
3233 acmd = set_table[i].id;
3234 break;
3235 }
3236 }
3237 /* Invalid option requested */
3238 if (!acmd)
3239 {
3240 sendto_one(sptr, ":%s NOTICE %s :Invalid option %s",
3241 ME, parv[0], parv[1]);
3242 }
3243 }
3244 else
3245 {
3246 /* No arguments, list all avaible options */
3247 acmd = TSET_SHOWALL;
3248 }
3249
3250 if (parc > 2)
3251 {
3252 /* Change settings */
3253 switch (acmd)
3254 {
3255 case TSET_ACONNECT:
3256 {
3257 if (!mycmp(parv[2], "ON"))
3258 {
3259 iconf.aconnect = 1;
3260 }
3261 else if (!mycmp(parv[2], "OFF"))
3262 {
3263 iconf.aconnect = 0;
3264 }
3265 else if (!mycmp(parv[2], "ND"))
3266 {
3267 iconf.aconnect = 2;
3268 }
3269 else
3270 {
3271 sendto_one(sptr, ":%s NOTICE %s SET "
3272 ":Illegal value for ACONNECT. "
3273 "Possible values: ON OFF ND",
3274 ME, parv[0]);
3275 break;
3276 }
3277 sendto_flag(SCH_NOTICE, "%s changed value of "
3278 "ACONNECT to %s", sptr->name, parv[2]);
3279 break;
3280 } /* TSET_ACONNECT */
3281
3282 case TSET_POOLSIZE:
3283 {
3284 int tmp;
3285 tmp = atoi(parv[2]);
3286 if (poolsize > tmp)
3287 {
3288 sendto_one(sptr,
3289 ":%s NOTICE %s SET :Poolsize"
3290 " can not be made smaller", ME,
3291 parv[0]);
3292
3293 }
3294 else
3295 {
3296 sendto_flag(SCH_NOTICE,
3297 "%s changed value of poolsize"
3298 " from %d to %d", sptr->name,
3299 poolsize, tmp);
3300 poolsize = tmp;
3301 }
3302 break;
3303 } /* TSET_POOLSIZE */
3304 case TSET_CACCEPT:
3305 if (!mycmp(parv[2], "OFF"))
3306 {
3307 iconf.caccept = 0;
3308 }
3309 else if (!mycmp(parv[2], "ON"))
3310 {
3311 iconf.caccept = 1;
3312 /* Well... give admin the chance. */
3313 if (!firstrejoindone)
3314 {
3315 activate_delayed_listeners();
3316 }
3317 }
3318 else if (!mycmp(parv[2], "SPLIT"))
3319 {
3320 iconf.caccept = 2;
3321 }
3322 else
3323 {
3324 sendto_one(sptr, ":%s NOTICE %s SET "
3325 ":Illegal value for CACCEPT. "
3326 "Possible values: ON OFF SPLIT",
3327 ME, parv[0]);
3328 break;
3329 }
3330 sendto_flag(SCH_NOTICE, "%s changed value of "
3331 "CACCEPT to %s", sptr->name, parv[2]);
3332 break;
3333 case TSET_SPLIT:
3334 {
3335 int tmp;
3336
3337 tmp = atoi(parv[2]);
3338 if (tmp < SPLIT_SERVERS)
3339 tmp = SPLIT_SERVERS;
3340 if (tmp != iconf.split_minservers)
3341 {
3342 sendto_flag(SCH_NOTICE, "%s changed"
3343 " value of SPLIT_SERVERS"
3344 " from %d to %d", sptr->name,
3345 iconf.split_minservers, tmp);
3346 iconf.split_minservers = tmp;
3347 }
3348 if (parc > 3)
3349 {
3350 tmp = atoi(parv[3]);
3351 if (tmp < SPLIT_USERS)
3352 tmp = SPLIT_USERS;
3353 }
3354 else
3355 tmp = iconf.split_minusers;
3356 if (tmp != iconf.split_minusers)
3357 {
3358 sendto_flag(SCH_NOTICE, "%s changed"
3359 " value of SPLIT_USERS"
3360 " from %d to %d", sptr->name,
3361 iconf.split_minusers, tmp);
3362 iconf.split_minusers = tmp;
3363 }
3364 check_split();
3365 break;
3366 }
3367 } /* switch(acmd) */
3368 } /* parc > 2 */
3369
3370 if (acmd)
3371 {
3372 if (acmd & TSET_POOLSIZE)
3373 {
3374 sendto_one(sptr, ":%s NOTICE %s :POOLSIZE = %d",
3375 ME, parv[0], poolsize);
3376 }
3377 if (acmd & TSET_ACONNECT)
3378 {
3379 sendto_one(sptr, ":%s NOTICE %s :ACONNECT = %s", ME,
3380 parv[0], iconf.aconnect == 2 ? "ND" :
3381 (iconf.aconnect == 1 ? "ON" : "OFF"));
3382 }
3383 if (acmd & TSET_CACCEPT)
3384 {
3385 sendto_one(sptr, ":%s NOTICE %s :CACCEPT = %s", ME,
3386 parv[0], iconf.caccept == 2 ? "SPLIT" :
3387 iconf.caccept == 1 ? "ON" : "OFF");
3388 }
3389 if (acmd & TSET_SPLIT)
3390 {
3391 sendto_one(sptr, ":%s NOTICE %s :SPLIT = SS %d SU %d",
3392 ME, parv[0], iconf.split_minservers,
3393 iconf.split_minusers);
3394 }
3395 }
3396 return 1;
3397 }
3398
3399 /*
3400 ** storing server names in User structures is a real waste,
3401 ** the following functions change it to only store a pointer.
3402 ** A better way might be to store in Server structure and use servp. -krys
3403 */
3404
3405 static char **server_name = NULL;
3406 static int server_max = 0, server_num = 0;
3407
3408 /*
3409 ** find_server_string
3410 **
3411 ** Given an index, this will return a pointer to the corresponding
3412 ** (already allocated) string
3413 */
find_server_string(int snum)3414 char *find_server_string(int snum)
3415 {
3416 if (snum < server_num && snum >= 0)
3417 return server_name[snum];
3418 /* request for a bogus snum value, something is wrong */
3419 sendto_flag(SCH_ERROR, "invalid index for server_name[] : %d (%d,%d)",
3420 snum, server_num, server_max);
3421 return NULL;
3422 }
3423
3424 /*
3425 ** find_server_num
3426 **
3427 ** Given a server name, this will return the index of the corresponding
3428 ** string. This index can be used with find_server_name_from_num().
3429 ** If the string doesn't exist already, it will be allocated.
3430 */
find_server_num(char * sname)3431 int find_server_num(char *sname)
3432 {
3433 Reg int i = 0;
3434
3435 while (i < server_num)
3436 {
3437 if (!strcasecmp(server_name[i], sname))
3438 break;
3439 i++;
3440 }
3441 if (i < server_num)
3442 return i;
3443 if (i == server_max)
3444 {
3445 /* server_name[] array is full, let's make it bigger! */
3446 if (server_name)
3447 server_name = (char **) MyRealloc((char *)server_name,
3448 sizeof(char *)*(server_max+=50));
3449 else
3450 server_name = (char **) MyMalloc(sizeof(char *)*(server_max=50));
3451 }
3452 server_name[server_num] = mystrdup(sname);
3453 return server_num++;
3454 }
3455
3456 /*
3457 ** check_link (added 97/12 to prevent abuse)
3458 ** routine which tries to find out how healthy a link is.
3459 ** useful to know if more strain may be imposed on the link or not.
3460 **
3461 ** returns 0 if link load is light, -1 otherwise.
3462 */
check_link(aClient * cptr)3463 static int check_link(aClient *cptr)
3464 {
3465 /* This matches opers, servers, services and local clients, so they
3466 ** are not subject to RPL_TRYAGAIN. --B. */
3467 if (cptr->status != STAT_CLIENT || MyConnect(cptr))
3468 return 0;
3469 if (!(bootopt & BOOT_PROT))
3470 return 0;
3471
3472 /* changing cptr to get link where it came from */
3473 cptr = cptr->from;
3474 ircstp->is_ckl++;
3475
3476 /* SendQ is already (too) high */
3477 if ((int)DBufLength(&cptr->sendQ) > 65536)
3478 {
3479 cptr->serv->lastload = timeofday;
3480 ircstp->is_cklQ++;
3481 return -1;
3482 }
3483 /* link is too young */
3484 if (timeofday - cptr->firsttime < 60)
3485 {
3486 ircstp->is_ckly++;
3487 return -1;
3488 }
3489 /* last request more than 30 seconds ago => OK */
3490 if (timeofday - cptr->serv->lastload > 30)
3491 {
3492 cptr->serv->lastload = timeofday;
3493 ircstp->is_cklok++;
3494 return 0;
3495 }
3496 /* last request between 15 and 30 seconds ago, but little SendQ */
3497 if (timeofday - cptr->serv->lastload > 15
3498 && (int)DBufLength(&cptr->sendQ) < CHREPLLEN)
3499 {
3500 cptr->serv->lastload = timeofday;
3501 ircstp->is_cklq++;
3502 return 0;
3503 }
3504 ircstp->is_cklno++;
3505 return -1;
3506 }
3507
3508 /*
3509 ** check_servername
3510 ** Simple check for validity of server name.
3511 ** Hostlen, valid chars and whether it contains at least one char
3512 ** and one dot (dot in servername equals no collision between
3513 ** servername and nickname (no more ultimate jupes ;>)). --Beeth
3514 **
3515 ** Returns 0 if ok, all else is some kind of error, which serves
3516 ** as index in check_servername_errors[] table.
3517 */
check_servername(char * hostname)3518 int check_servername(char *hostname)
3519 {
3520 register char *ch;
3521 int dots, chars, rc;
3522
3523 dots = 0;
3524 chars = 0;
3525 rc = 0;
3526
3527 if (strlen(hostname) > HOSTLEN)
3528 {
3529 rc = 1;
3530 }
3531 else
3532 {
3533 for (ch = hostname; *ch; ch++)
3534 {
3535 if (*ch == '.')
3536 {
3537 dots++;
3538 continue;
3539 }
3540 if ((*ch >= 'a' && *ch <= 'z')
3541 || (*ch >= 'A' && *ch <= 'Z')
3542 || *ch == '-' || *ch == '*')
3543 {
3544 chars++;
3545 continue;
3546 }
3547 if (isdigit(*ch))
3548 {
3549 continue;
3550 }
3551 /* all else is invalid as servername! */
3552 rc = 2;
3553 break;
3554 }
3555 if (!rc && !dots)
3556 {
3557 /* not a single dot? not allowed. */
3558 rc = 3;
3559 }
3560 if (!rc && !chars)
3561 {
3562 /* no chars? not allowed. */
3563 rc = 2;
3564 }
3565 }
3566
3567 return rc;
3568 }
3569
3570 /*
3571 ** adds server to server tree
3572 */
add_server_to_tree(aClient * acptr)3573 void add_server_to_tree(aClient *acptr)
3574 {
3575 acptr->serv->up->serv->servers++;
3576
3577 if (acptr->serv->up->serv->down)
3578 {
3579 acptr->serv->up->serv->down->serv->left = acptr;
3580 }
3581
3582 acptr->serv->right = acptr->serv->up->serv->down;
3583 acptr->serv->up->serv->down = acptr;
3584
3585 return;
3586 }
3587
3588 /*
3589 ** Removes a server from the server tree.
3590 */
remove_server_from_tree(aClient * cptr)3591 void remove_server_from_tree(aClient *cptr)
3592 {
3593 cptr->serv->up->serv->servers--;
3594
3595 if (cptr->serv->down)
3596 {
3597 /* FIXME - debug abort(). this must be *never* true
3598 * at this point - jv */
3599 abort();
3600 }
3601
3602 if (cptr->serv->right)
3603 {
3604 cptr->serv->right->serv->left = cptr->serv->left;
3605 }
3606
3607 if (cptr->serv->left)
3608 {
3609 cptr->serv->left->serv->right = cptr->serv->right;
3610 }
3611
3612 if (cptr == cptr->serv->up->serv->down)
3613 {
3614 cptr->serv->up->serv->down = cptr->serv->right;
3615 }
3616
3617 return;
3618 }
3619
dump_map_sid(aClient * sptr,char * mask,aClient * root,char * pbuf,int size)3620 static void dump_map_sid(aClient *sptr, char *mask, aClient *root, char *pbuf, int size)
3621 {
3622 int i = 1;
3623 aClient *acptr;
3624
3625 *pbuf= '\0';
3626 if (IsBursting(root))
3627 {
3628 snprintf(pbuf, size, "%s %d %s %s bursting %ds",
3629 IsMasked(root) ? root->serv->maskedby->name : root->name,
3630 root->serv->usercnt[0] + root->serv->usercnt[1],
3631 root->serv->sid,
3632 BadTo(root->serv->verstr),
3633 MyConnect(root) ? (int) (timeofday - root->firsttime) : -1);
3634 }
3635 else
3636 {
3637 snprintf(pbuf, size, "%s %d %s %s",
3638 IsMasked(root) ? root->serv->maskedby->name : root->name,
3639 root->serv->usercnt[0] + root->serv->usercnt[1],
3640 root->serv->sid,
3641 BadTo(root->serv->verstr));
3642 }
3643
3644 if (!mask || 0==match(mask,
3645 (IsMasked(root) ? root->serv->maskedby->name : root->name)))
3646 {
3647 sendto_one(sptr, replies[RPL_MAP], ME, BadTo(sptr->name), buf);
3648 }
3649
3650 if (root->serv->down)
3651 {
3652 /* we have children */
3653
3654 if (pbuf > buf + 3)
3655 {
3656 /* we aren't 1st level child of &me */
3657 pbuf[-2] = ' ';
3658 if (pbuf[-3] == '`')
3659 {
3660 pbuf[-3] = ' ';
3661 }
3662 }
3663 }
3664
3665 for (acptr = root->serv->down; acptr; acptr = acptr->serv->right)
3666 {
3667 *pbuf = ' ';
3668 if (i < root->serv->servers)
3669 {
3670 *(pbuf + 1) = '|';
3671 }
3672 else
3673 {
3674 /* last child of root */
3675 *(pbuf + 1) = '`';
3676 }
3677 *(pbuf + 2) = '-';
3678 *(pbuf + 3) = ' ';
3679 /* "pbuf + 4" and "size - 4" because each nesting
3680 ** we add 4 chars in front of output line --B. */
3681 dump_map_sid(sptr, mask, acptr, pbuf + 4, size - 4);
3682 i++;
3683 }
3684 }
3685
3686
dump_map(aClient * sptr,char * mask,aClient * root,aClient ** prevserver,char * pbuf)3687 static void dump_map(aClient *sptr, char *mask, aClient *root, aClient **prevserver, char *pbuf)
3688 {
3689 aClient *prev = NULL;
3690 aClient *acptr;
3691
3692 /* Check if we still have space 5 - tree + \0 */
3693 if (pbuf - buf > BUFSIZE - (HOSTLEN + 5))
3694 {
3695 return;
3696 }
3697
3698 /* Display itself if not masked */
3699 if (!IsMasked(root))
3700 {
3701 *pbuf= '\0';
3702 strcat(pbuf, root->name);
3703 if (!mask || !match(mask, root->name))
3704 sendto_one(sptr, replies[RPL_MAP], ME, BadTo(sptr->name), buf);
3705 }
3706
3707 /* Clean up the output line */
3708 if (root->serv->down)
3709 {
3710 /* we have children */
3711
3712 if (pbuf > buf + 3)
3713 {
3714 /* we aren't 1st level child of &me*/
3715 pbuf[-2] = ' ';
3716 if (pbuf[-3] == '`')
3717 {
3718 pbuf[-3] = ' ';
3719 }
3720 }
3721 }
3722
3723 /* Iterate over children */
3724 for (acptr = root->serv->down; acptr; acptr = acptr->serv->right)
3725 {
3726
3727 if (!IsMasked(acptr))
3728 {
3729 /* Check if we already found not masked server
3730 * in this masked tree */
3731 if (*prevserver)
3732 {
3733 *pbuf = ' ';
3734 *(pbuf + 1) = '|';
3735 *(pbuf + 2) = '-';
3736 *(pbuf + 3) = ' ';
3737
3738 /* prev - with new previous server ptr */
3739 dump_map(sptr, mask, *prevserver, &prev, pbuf + 4);
3740 }
3741 /* store this server */
3742 *prevserver = acptr;
3743 }
3744 else
3745 {
3746 /* Masked server found - check it's leaves */
3747 dump_map(sptr, mask, acptr, prevserver, pbuf);
3748 }
3749 /* Display the last found server if we are on the correct
3750 * level */
3751 if (!acptr->serv->right && *prevserver &&
3752 (!acptr->serv->up || !IsMasked(acptr->serv->up)))
3753 {
3754 *pbuf = ' ';
3755 *(pbuf + 1) = '`';
3756 *(pbuf + 2) = '-';
3757 *(pbuf + 3) = ' ';
3758 dump_map(sptr, mask, *prevserver, &prev, pbuf + 4);
3759 *prevserver = NULL;
3760 }
3761 }
3762 }
3763
3764 /* MAP command - prints fancy tree of the network.
3765 ** parv[0] - Requesting user.
3766 ** parv[1] - optional parameter "s" which causes alternate version
3767 ** of map with SIDs and versions to be printed.
3768 */
m_map(aClient * cptr,aClient * sptr,int parc,char * parv[])3769 int m_map(aClient *cptr, aClient *sptr, int parc, char *parv[])
3770 {
3771 aClient *acptr = NULL;
3772 int sids = 0;
3773 char *mask = NULL;
3774
3775 if (parc > 1)
3776 {
3777 if (parv[parc-1][0] == 's' && parv[parc-1][1] == '\0')
3778 {
3779 sids = parc - 1;
3780 }
3781 if (sids != 1)
3782 {
3783 mask = parv[1];
3784 }
3785 }
3786 if (sids)
3787 {
3788 /* print full dump of the network */
3789 sendto_one(sptr, replies[RPL_MAPSTART], ME, BadTo(sptr->name),
3790 "Server users SID version");
3791 dump_map_sid(sptr, mask, &me, buf, sizeof(buf) -
3792 strlen(BadTo(sptr->name)) - strlen(ME) - 8);
3793 sendto_one(sptr, replies[RPL_MAPEND], ME, BadTo(sptr->name));
3794 return 2;
3795 }
3796 sendto_one(sptr, replies[RPL_MAPSTART], ME, BadTo(sptr->name),
3797 "Server");
3798 dump_map(sptr, mask, &me, &acptr, buf);
3799 sendto_one(sptr, replies[RPL_MAPEND], ME, BadTo(sptr->name));
3800 return 2;
3801 }
3802
report_listeners(aClient * sptr,char * to)3803 static void report_listeners(aClient *sptr, char *to)
3804 {
3805 aConfItem *tmp;
3806 aClient *acptr;
3807 char *what;
3808
3809 for (acptr = ListenerLL; acptr; acptr = acptr->next)
3810 {
3811 tmp = acptr->confs->value.aconf;
3812 if (IsIllegal(tmp))
3813 what = "dead";
3814 else if (IsListenerInactive(acptr))
3815 what = "inactive";
3816 else if (IsConfDelayed(tmp))
3817 {
3818 if (iconf.caccept == 0)
3819 what = "noaccept";
3820 else if (iconf.caccept == 2 && iconf.split == 1)
3821 what = "splitnoaccept";
3822 else
3823 what = "active";
3824 }
3825 else
3826 what = "active";
3827
3828 sendto_one(sptr, ":%s %d %s %d %s %s %u %lu %llu %lu %llu %u"
3829 " %u %s",
3830 ME, RPL_STATSLINKINFO, to,
3831 tmp->port, BadTo(tmp->host),
3832 pline_flags_to_string(tmp->flags),
3833 (uint)DBufLength(&acptr->sendQ),
3834 acptr->sendM, acptr->sendB,
3835 acptr->receiveM, acptr->receiveB,
3836 timeofday - acptr->firsttime,
3837 tmp->clients, what);
3838 }
3839 }
3840
3841 /*
3842 ** allows ENCAPsulation of commands
3843 ** parv[0] is ignored (though it's source)
3844 ** parv[1] is target mask
3845 ** parv[2] is command
3846 ** the rest is optional and is used by command as its own params
3847 */
3848
m_encap(aClient * cptr,aClient * sptr,int parc,char * parv[])3849 int m_encap(aClient *cptr, aClient *sptr, int parc, char *parv[])
3850 {
3851 char buf[BUFSIZE];
3852 int i, len;
3853
3854 /* Prepare ENCAP buffer... */
3855 len = sprintf(buf, ":%s ENCAP", sptr->serv->sid);
3856 for (i = 1; i < parc; i++)
3857 {
3858 if (len + strlen(parv[i]) >= BUFSIZE-2)
3859 {
3860 /* This can get cut. */
3861 sendto_flag(SCH_ERROR, "ENCAP too long (%s)", buf);
3862 /* Sending incomplete ENCAP means data corruption.
3863 ** Should we squit the link that fed us this? --B. */
3864 return 1;
3865 }
3866 if (i >= 3 && i == parc - 1)
3867 len += sprintf(buf+len, " :%s", parv[i]);
3868 else
3869 len += sprintf(buf+len, " %s", parv[i]);
3870 }
3871 /* ...and broadcast it. */
3872 sendto_serv_v(cptr, SV_UID, "%s", buf);
3873
3874 /* FIXME: in 2.11.1 */
3875 /* Do we match parv[1]? */
3876 /* Copying things from parse() */
3877 /* STAT_ENCAP handler for parv[2] */
3878 /* Call handler function with parc-2, parv+2 */
3879
3880 return 0;
3881 }
3882
3883 /* announces server DIE */
m_sdie(aClient * cptr,aClient * sptr,int parc,char * parv[])3884 int m_sdie(aClient *cptr, aClient *sptr, int parc, char *parv[])
3885 {
3886 sendto_serv_v(cptr, SV_UID, ":%s SDIE", sptr->serv->sid);
3887 return 0;
3888 }
3889
3890 /* Register server to the network.
3891 *
3892 * to be called whenever server associates client struct.
3893 * Also registers the server in global svrtop list.
3894 */
register_server(aClient * cptr)3895 int register_server(aClient *cptr)
3896 {
3897
3898 if (svrtop)
3899 {
3900 svrtop->prevs = cptr->serv;
3901 cptr->serv->nexts = svrtop;
3902 }
3903 svrtop = cptr->serv;
3904
3905 return 0;
3906 }
3907
3908 /* Unregister server from the network.
3909 *
3910 * to be called when a server loses associated client struct.
3911 * Also removes given server from global svrtop list.
3912 */
unregister_server(aClient * cptr)3913 int unregister_server(aClient *cptr)
3914 {
3915 if (cptr->serv->nexts)
3916 cptr->serv->nexts->prevs = cptr->serv->prevs;
3917
3918 if (cptr->serv->prevs)
3919 cptr->serv->prevs->nexts = cptr->serv->nexts;
3920
3921 if (svrtop == cptr->serv)
3922 svrtop = cptr->serv->nexts;
3923
3924 cptr->serv->prevs = NULL;
3925 cptr->serv->nexts = NULL;
3926 cptr->serv->bcptr = NULL;
3927
3928 return 0;
3929 }
3930