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