1 /************************************************************************
2  *   IRC - Internet Relay Chat, ircd/s_user.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_user.c,v 1.280 2010/08/12 16:29:30 bif Exp $";
26 #endif
27 
28 #include "os.h"
29 #include "s_defines.h"
30 #define S_USER_C
31 #include "s_externs.h"
32 #undef S_USER_C
33 
34 static void	save_user (aClient *, aClient *, char *);
35 
36 static char buf[BUFSIZE], buf2[BUFSIZE];
37 
38 static int user_modes[]	     = { FLAGS_OPER, 'o',
39 				 FLAGS_LOCOP, 'O',
40 				 FLAGS_INVISIBLE, 'i',
41 				 FLAGS_WALLOP, 'w',
42 				 FLAGS_RESTRICT, 'r',
43 				 FLAGS_AWAY, 'a',
44 				 0, 0 };
45 
46 /*
47 ** m_functions execute protocol messages on this server:
48 **
49 **	cptr	is always NON-NULL, pointing to a *LOCAL* client
50 **		structure (with an open socket connected!). This
51 **		identifies the physical socket where the message
52 **		originated (or which caused the m_function to be
53 **		executed--some m_functions may call others...).
54 **
55 **	sptr	is the source of the message, defined by the
56 **		prefix part of the message if present. If not
57 **		or prefix not found, then sptr==cptr.
58 **
59 **		(!IsServer(cptr)) => (cptr == sptr), because
60 **		prefixes are taken *only* from servers...
61 **
62 **		(IsServer(cptr))
63 **			(sptr == cptr) => the message didn't
64 **			have the prefix.
65 **
66 **			(sptr != cptr && IsServer(sptr) means
67 **			the prefix specified servername. (?)
68 **
69 **			(sptr != cptr && !IsServer(sptr) means
70 **			that message originated from a remote
71 **			user (not local).
72 **
73 **		combining
74 **
75 **		(!IsServer(sptr)) means that, sptr can safely
76 **		taken as defining the target structure of the
77 **		message in this server.
78 **
79 **	*Always* true (if 'parse' and others are working correct):
80 **
81 **	1)	sptr->from == cptr  (note: cptr->from == cptr)
82 **
83 **	2)	MyConnect(sptr) <=> sptr == cptr (e.g. sptr
84 **		*cannot* be a local connection, unless it's
85 **		actually cptr!). [MyConnect(x) should probably
86 **		be defined as (x == x->from) --msa ]
87 **
88 **	parc	number of variable parameter strings (if zero,
89 **		parv is allowed to be NULL)
90 **
91 **	parv	a NULL terminated list of parameter pointers,
92 **
93 **			parv[0], sender (prefix string), if not present
94 **				this points to an empty string.
95 **			parv[1]...parv[parc-1]
96 **				pointers to additional parameters
97 **			parv[parc] == NULL, *always*
98 **
99 **		note:	it is guaranteed that parv[0]..parv[parc-1] are all
100 **			non-NULL pointers.
101 */
102 
103 /*
104 ** next_client
105 **	Local function to find the next matching client. The search
106 **	can be continued from the specified client entry. Normal
107 **	usage loop is:
108 **
109 **	for (x = client; x = next_client(x,mask); x = x->next)
110 **		HandleMatchingClient;
111 **
112 ** Parameters:
113 **	aClient *next	First client to check
114 **	char	*ch	Search string (may include wilds)
115 **
116 */
next_client(aClient * next,char * ch)117 aClient	*next_client(aClient *next, char *ch)
118 {
119 	Reg	aClient	*tmp = next;
120 
121 	next = find_client(ch, tmp);
122 	if (tmp && tmp->prev == next)
123 		return NULL;
124 	if (next != tmp)
125 		return next;
126 	for ( ; next; next = next->next)
127 		if (!match(ch,next->name) || !match(next->name,ch))
128 			break;
129 	return next;
130 }
131 
132 /*
133 ** hunt_server
134 **
135 **	Do the basic thing in delivering the message (command)
136 **	across the relays to the specific server (server) for
137 **	actions.
138 **
139 **	Note:	The command is a format string and *MUST* be
140 **		of prefixed style (e.g. ":%s COMMAND %s ...").
141 **		Command can have only max 8 parameters.
142 **
143 **	server	parv[server] is the parameter identifying the
144 **		target server.
145 **
146 **	*WARNING*
147 **		parv[server] is replaced with the pointer to the
148 **		real servername from the matched client (I'm lazy
149 **		now --msa).
150 **
151 **	returns: (see #defines)
152 */
hunt_server(aClient * cptr,aClient * sptr,char * command,int server,int parc,char * parv[])153 int	hunt_server(aClient *cptr, aClient *sptr, char *command, int server,
154 		int parc, char *parv[])
155 {
156 	aClient *acptr;
157 
158 	/*
159 	** Assume it's me, if no server
160 	*/
161 	if (parc <= server || BadPtr(parv[server]) ||
162 	    match(ME, parv[server]) == 0 ||
163 	    match(parv[server], ME) == 0)
164 		return (HUNTED_ISME);
165 	/*
166 	** These are to pickup matches that would cause the following
167 	** message to go in the wrong direction while doing quick fast
168 	** non-matching lookups.
169 	*/
170 	if ((acptr = find_client(parv[server], NULL)))
171 		if (acptr->from == sptr->from && !MyConnect(acptr))
172 			acptr = NULL;
173 	/* Match SID */
174 	if (!acptr && (acptr = find_sid(parv[server], NULL)))
175 		if (acptr->from == sptr->from && !MyConnect(acptr))
176 			acptr = NULL;
177 	/* Match *.masked.servers */
178 	if (!acptr && (acptr = find_server(parv[server], NULL)))
179 		if (acptr->from == sptr->from && !MyConnect(acptr))
180 			acptr = NULL;
181 	/* Remote services@servers */
182 	if (!acptr && (acptr = find_service(parv[server], NULL)))
183 		if (acptr->from == sptr->from && !MyConnect(acptr))
184 			acptr = NULL;
185 	if (!acptr)
186 		for (acptr = client, (void)collapse(parv[server]);
187 		     (acptr = next_client(acptr, parv[server]));
188 		     acptr = acptr->next)
189 		    {
190 			if (acptr->from == sptr->from && !MyConnect(acptr))
191 				continue;
192 			/*
193 			 * Fix to prevent looping in case the parameter for
194 			 * some reason happens to match someone from the from
195 			 * link --jto
196 			 */
197 			if (IsRegistered(acptr) && (acptr != cptr))
198 				break;
199 		    }
200 	 if (acptr)
201 	    {
202 		if (!IsRegistered(acptr))
203 			return HUNTED_ISME;
204 		if (IsMe(acptr) || MyClient(acptr) || MyService(acptr))
205 			return HUNTED_ISME;
206 		if (match(acptr->name, parv[server]))
207 			parv[server] = acptr->name;
208 		if (IsService(sptr)
209 		    && (IsServer(acptr->from)
210 			&& match(sptr->service->dist,acptr->name) != 0
211 			&& match(sptr->service->dist,acptr->serv->sid) != 0))
212 		    {
213 			sendto_one(sptr, replies[ERR_NOSUCHSERVER], ME, BadTo(parv[0]),
214 				   parv[server]);
215 			return(HUNTED_NOSUCH);
216 		    }
217 		sendto_one(acptr, command, parv[0],
218 			   parv[1], parv[2], parv[3], parv[4],
219 			   parv[5], parv[6], parv[7], parv[8]);
220 		return(HUNTED_PASS);
221 	    }
222 	sendto_one(sptr, replies[ERR_NOSUCHSERVER], ME, BadTo(parv[0]), parv[server]);
223 	return(HUNTED_NOSUCH);
224 }
225 
226 /*
227 ** 'do_nick_name' ensures that the given parameter (nick) is
228 ** really a proper string for a nickname (note, the 'nick'
229 ** may be modified in the process...)
230 **
231 **	RETURNS the length of the final NICKNAME (0, if
232 **	nickname is illegal)
233 **
234 **  Nickname characters are in range
235 **	'A'..'}', '_', '-', '0'..'9'
236 **  anything outside the above set will terminate nickname.
237 **  In addition, the first character cannot be '-' or a digit.
238 **  Finally forbid the use of "anonymous" because of possible
239 **  abuses related to anonymous channnels. -kalt
240 **
241 */
242 
do_nick_name(char * nick,int server)243 int	do_nick_name(char *nick, int server)
244 {
245 	Reg	char	*ch;
246 
247 	if (*nick == '-') /* first character '-' */
248 		return 0;
249 
250 	if (isdigit(*nick) && !server) /* first character in [0..9] */
251 		return 0;
252 
253 	if (strcasecmp(nick, "anonymous") == 0)
254 		return 0;
255 
256 #ifdef MINLOCALNICKLEN
257 	if (!server && nick[MINLOCALNICKLEN-1] == '\0')
258 		return 0;
259 #endif
260 
261 	for (ch = nick; *ch && (ch-nick) < (server?NICKLEN:LOCALNICKLEN); ch++)
262 	{
263 		if (!isvalidnick(*ch))
264 		{
265 			break;
266 		}
267 	}
268 
269 	*ch = '\0';
270 
271 	return (ch - nick);
272 }
273 
274 
275 /*
276 ** canonize
277 **
278 ** reduce a string of duplicate list entries to contain only the unique
279 ** items.  Unavoidably O(n^2).
280 */
canonize(char * buffer)281 char	*canonize(char *buffer)
282 {
283 	static	char	cbuf[BUFSIZ];
284 	Reg	char	*s, *t, *cp = cbuf;
285 	Reg	int	l = 0;
286 	char	*p = NULL, *p2;
287 
288 	*cp = '\0';
289 
290 	for (s = strtoken(&p, buffer, ","); s; s = strtoken(&p, NULL, ","))
291 	    {
292 		if (l)
293 		    {
294 			for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t;
295 			     t = strtoken(&p2, NULL, ","))
296 				if (!mycmp(s, t))
297 					break;
298 				else if (p2)
299 					p2[-1] = ',';
300 		    }
301 		else
302 			t = NULL;
303 		if (!t)
304 		    {
305 			if (l)
306 				*(cp-1) = ',';
307 			else
308 				l = 1;
309 			(void)strcpy(cp, s);
310 			if (p)
311 				cp += (p - s);
312 		    }
313 		else if (p2)
314 			p2[-1] = ',';
315 	    }
316 	return cbuf;
317 }
318 
319 /*
320 ** register_user
321 **	This function is called when both NICK and USER messages
322 **	have been accepted for the client, in whatever order. Only
323 **	after this the UNICK message is propagated.
324 */
325 
register_user(aClient * cptr,aClient * sptr,char * nick,char * username)326 int	register_user(aClient *cptr, aClient *sptr, char *nick, char *username)
327 {
328 	Reg	aConfItem *aconf;
329 	aClient	*acptr;
330 	anUser	*user = sptr->user;
331 	char	*parv[3];
332 #ifndef NO_PREFIX
333 	char	prefix;
334 #endif
335 	int	i;
336 #ifdef XLINE
337 	static char savedusername[USERLEN+1];
338 
339 	strncpyzt(savedusername, username, USERLEN+1);
340 #endif
341 
342 	user->last = timeofday;
343 	parv[0] = sptr->name;
344 	parv[1] = parv[2] = NULL;
345 
346 	if (MyConnect(sptr))
347 	{
348 		char *reason = NULL;
349 #ifdef RESTRICT_USERNAMES
350 		char *lbuf = NULL;
351 #endif
352 #if defined(USE_IAUTH)
353 		static time_t last = 0;
354 		static u_int count = 0;
355 #endif
356 #ifdef XLINE
357 		aConfItem *xtmp;
358 
359 		/* Just for clarification, so there's less confusion:
360 		   X-lines read from config have their fields stored
361 		   in aConf in the following fields:
362 		   host, passwd, name, name2, name3, source_ip.
363 		   (see s_conf.c/initconf(), look for XLINE);
364 		   these are used to check against USER and NICK
365 		   commands parameters during registration:
366 		   USER 1st 2nd 3rd :4th
367 		   NICK 5th
368 		   additionally user ip and/or hostname are
369 		   being matched against X-line last field
370 		   (conveniently kept in aconf->source_ip). --B. */
371 
372 		for (xtmp = conf; xtmp; xtmp = xtmp->next)
373 		{
374 			if (xtmp->status != CONF_XLINE)
375 				continue;
376 			if (!BadPtr(xtmp->host) &&
377 				match(xtmp->host, username))
378 				continue;
379 			if (!BadPtr(xtmp->passwd) &&
380 				match(xtmp->passwd, sptr->user2))
381 				continue;
382 			if (!BadPtr(xtmp->name) &&
383 				match(xtmp->name, sptr->user3))
384 				continue;
385 			if (!BadPtr(xtmp->name2) &&
386 				match(xtmp->name2, sptr->info))
387 				continue;
388 			if (!BadPtr(xtmp->name3) &&
389 				match(xtmp->name3, nick))
390 				continue;
391 			if (!BadPtr(xtmp->source_ip) &&
392 				(match(xtmp->source_ip, (sptr->hostp ?
393 				sptr->hostp->h_name : sptr->sockhost)) &&
394 				match(xtmp->source_ip, sptr->user->sip) &&
395 				strchr(xtmp->source_ip, '/') &&
396 				match_ipmask(xtmp->source_ip, sptr, 0)))
397 				continue;
398 			SetXlined(sptr);
399 			break;
400 		}
401 
402 		if (IsXlined(sptr))
403 		{
404 			sptr->exitc = EXITC_XLINE;
405 			return exit_client(cptr, sptr, &me,
406 				XLINE_EXIT_REASON);
407 		}
408 #endif
409 
410 #if defined(USE_IAUTH)
411 		if (iauth_options & XOPT_EARLYPARSE && DoingXAuth(cptr))
412 		{
413 			cptr->flags |= FLAGS_WXAUTH;
414 			/* fool check_pings() and give iauth more time! */
415 			cptr->firsttime = timeofday;
416 			cptr->lasttime = timeofday;
417 			strncpyzt(sptr->user->username, username, USERLEN+1);
418 			if (sptr->passwd[0])
419 				sendto_iauth("%d P %s", sptr->fd, sptr->passwd);
420 			sendto_iauth("%d U %s", sptr->fd, sptr->user->username);
421 			return 1;
422 		}
423 		if (!DoneXAuth(sptr) && (iauth_options & XOPT_REQUIRED))
424 		{
425 			if (iauth_options & XOPT_NOTIMEOUT)
426 			{
427 				count += 1;
428 				if (timeofday - last > 300)
429 				    {
430 					sendto_flag(SCH_AUTH,
431 	    "iauth may be not running! (refusing new user connections)");
432 					last = timeofday;
433 				    }
434 				sptr->exitc = EXITC_AUTHFAIL;
435 			}
436 			else
437 				sptr->exitc = EXITC_AUTHTOUT;
438 			return exit_client(cptr, cptr, &me,
439 				"Authentication failure! - no iauth?");
440 		}
441 		if (timeofday - last > 300 && count)
442 		{
443 			sendto_flag(SCH_AUTH, "%d users rejected.", count);
444 			count = 0;
445 		}
446 
447 		/* this should not be needed, but there's a bug.. -kalt */
448 		/* haven't seen any notice like this, ever.. no bug no more? */
449 		if (*cptr->username == '\0')
450 		{
451 			sendto_flag(SCH_AUTH,
452 				    "Ouch! Null username for %s (%d %X)",
453 				    get_client_name(cptr, TRUE), cptr->fd,
454 				    cptr->flags);
455 			sendto_iauth("%d E Null username [%s] %X", cptr->fd,
456 				     get_client_name(cptr, TRUE), cptr->flags);
457 			return exit_client(cptr, sptr, &me,
458 					   "Fatal Bug - Try Again");
459 		}
460 #endif
461 #ifdef RESTRICT_USERNAMES
462 		/*
463 		** Do not allow special chars in the username.
464 		*/
465 		if ((sptr->flags & FLAGS_GOTID) &&
466 			! (*sptr->username == '-' ||
467 			index(sptr->username, '@')))
468 		{
469 			/* got ident and it is not OTHER
470 			 * (which could be encrypted), so check
471 			 * this one for validity */
472 			lbuf = sptr->username;
473 		}
474 		else
475 		{
476 			/* either no ident or ident OTHER */
477 			lbuf = username;
478 		}
479 		if (!isvalidusername(lbuf))
480 		{
481 			ircstp->is_ref++;
482 			sendto_flag(SCH_LOCAL, "Invalid username:  %s@%s.",
483 				lbuf, sptr->sockhost);
484 			sptr->exitc = EXITC_REF;
485 			return exit_client(cptr, sptr, &me, "Invalid username");
486 		}
487 #endif
488 		/*
489 		** the following insanity used to be after check_client()
490 		** but check_client()->attach_Iline() now needs to know the
491 		** username for global u@h limits.
492 		** moving this shit here shouldn't be a problem. -krys
493 		** what a piece of $#@!.. restricted can only be known
494 		** *after* attach_Iline(), so it matters and I have to move
495 		** come of it back below.  so global u@h limits really suck.
496 		*/
497 #ifndef	NO_PREFIX
498 		/*
499 		** ident is fun.. ahem
500 		** prefixes used:
501 		** 	none	I line with ident
502 		**	^	I line with OTHER type ident
503 		**	~	I line, no ident
504 		** 	+	i line with ident
505 		**	=	i line with OTHER type ident
506 		**	-	i line, no ident
507 		*/
508 		if (!(sptr->flags & FLAGS_GOTID))
509 			prefix = '~';
510 		else
511 			if (*sptr->username == '-' ||
512 			    index(sptr->username, '@'))
513 				prefix = '^';
514 			else
515 				prefix = '\0';
516 
517 		/* OTHER type idents have '-' prefix (from s_auth.c),       */
518 		/* and they are not supposed to be used as userid (rfc1413) */
519 		/* @ isn't valid in usernames (m_user()) */
520 		if (sptr->flags & FLAGS_GOTID && *sptr->username != '-' &&
521 		    index(sptr->username, '@') == NULL)
522 			strncpyzt(buf2, sptr->username, USERLEN+1);
523 		else /* No ident, or unusable ident string */
524 		     /* because username may point to user->username */
525 			strncpyzt(buf2, username, USERLEN+1);
526 
527 		if (prefix)
528 		{
529 			*user->username = prefix;
530 			strncpy(&user->username[1], buf2, USERLEN);
531 		}
532 		else
533 			strncpy(user->username, buf2, USERLEN+1);
534 		user->username[USERLEN] = '\0';
535 		/* eos */
536 #else
537 		strncpyzt(user->username, username, USERLEN+1);
538 #endif
539 
540 		if (sptr->exitc == EXITC_AREF || sptr->exitc == EXITC_AREFQ)
541 		{
542 			if (sptr->exitc == EXITC_AREF)
543 				sendto_flag(SCH_LOCAL,
544 					    "Denied connection from %s.",
545 					    get_client_host(sptr));
546 			return exit_client(cptr, cptr, &me,
547 			         sptr->reason ? sptr->reason : "Denied access");
548 		}
549 		if ((i = check_client(sptr)))
550 		{
551 			struct msg_set { char shortm; char *longm; };
552 #define EXIT_MSG_COUNT 8
553 			static struct msg_set exit_msg[EXIT_MSG_COUNT] = {
554 			{ EXITC_BADPASS, "Bad password" },
555 			{ EXITC_GUHMAX, "Too many user connections (global)" },
556 			{ EXITC_GHMAX, "Too many host connections (global)" },
557 			{ EXITC_LUHMAX, "Too many user connections (local)" },
558 			{ EXITC_LHMAX, "Too many host connections (local)" },
559 			{ EXITC_YLINEMAX, "Too many connections" },
560 			{ EXITC_NOILINE, "Unauthorized connection" },
561 			{ EXITC_FAILURE, "Connect failure" } };
562 
563 			if (i > -1)
564 			{
565 				i = -1;
566 			}
567 			i += EXIT_MSG_COUNT;
568 			if (i > EXIT_MSG_COUNT)
569 			{
570 				i = EXIT_MSG_COUNT;
571 			}
572 #undef EXIT_MSG_COUNT
573 
574 			ircstp->is_ref++;
575 			sptr->exitc = exit_msg[i].shortm;
576 			if (exit_msg[i].shortm != EXITC_BADPASS)
577 			{
578 				sendto_flag(SCH_LOCAL, "%s from %s.",
579 					exit_msg[i].longm,
580 					get_client_host(sptr));
581 			}
582 			return exit_client(cptr, cptr, &me, exit_msg[i].longm);
583 		}
584 #ifndef	NO_PREFIX
585 		if (IsRestricted(sptr))
586 		{
587 			if (!(sptr->flags & FLAGS_GOTID))
588 				prefix = '-';
589 			else
590 				if (*sptr->username == '-' ||
591 				    index(sptr->username, '@'))
592 					prefix = '=';
593 				else
594 					prefix = '+';
595 			*user->username = prefix;
596 			strncpy(&user->username[1], buf2, USERLEN);
597 			user->username[USERLEN] = '\0';
598 		}
599 #endif
600 
601 		aconf = sptr->confs->value.aconf;
602 #ifdef UNIXPORT
603 		if (IsUnixSocket(sptr))
604 		{
605 			strncpyzt(user->host, me.sockhost, HOSTLEN+1);
606 		}
607 		else
608 #endif
609 		{
610 			if (IsConfNoResolveMatch(aconf))
611 			{
612 				/* sockhost contains resolved hostname (if any),
613 				 * which we'll use in match_modeid to match. */
614 				strncpyzt(user->host, user->sip,
615 					HOSTLEN+1);
616 			}
617 			else
618 			{
619 				strncpyzt(user->host, sptr->sockhost,
620 					HOSTLEN+1);
621 			}
622 		}
623 
624 		/* hmpf, why that? --B. */
625 		/* so already authenticated clients don't have password
626 		** kept in ircd memory? --B. */
627 		bzero(sptr->passwd, sizeof(sptr->passwd));
628 		/*
629 		 * following block for the benefit of time-dependent K:-lines
630 		 * how come "time-dependant"? I don't see it. --B.
631 		 */
632 		if (!IsKlineExempt(sptr) && find_kill(sptr, 0, &reason))
633 		{
634 			sendto_flag(SCH_LOCAL, "K-lined %s@%s.",
635 				    user->username, sptr->sockhost);
636 			ircstp->is_ref++;
637 			sptr->exitc = EXITC_KLINE;
638 			if (reason)
639 				sprintf(buf, "K-lined: %.80s", reason);
640 			return exit_client(cptr, sptr, &me,
641 				(reason) ? buf : "K-lined");
642 		}
643 	}
644 	else
645 	{
646 		/* Received from other server in UNICK */
647 		strncpyzt(user->username, username, USERLEN+1);
648 	}
649 
650 	SetClient(sptr);
651 	if (!MyConnect(sptr))
652 	{
653 		acptr = find_server(user->server, NULL);
654 		if (acptr && acptr->from != cptr)
655 		{
656 			/* I think this is not possible anymore. --B. */
657 			sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s])",
658 				ME, user->uid, ME, user->server,
659 				acptr->from->name, acptr->from->sockhost);
660 			sptr->flags |= FLAGS_KILLED;
661 			return exit_client(cptr, sptr, &me,
662 				"UNICK server wrong direction");
663 		}
664 		send_umode(NULL, sptr, 0, SEND_UMODES, buf);
665 	}
666 	/* below !MyConnect, as it can remove user */
667 	if (IsInvisible(sptr))		/* Can be initialized in m_user() */
668 	{
669 		istat.is_user[1]++;	/* Local and server defaults +i */
670 		user->servp->usercnt[1]++;
671 	}
672 	else
673 	{
674 		user->servp->usercnt[0]++;
675 		istat.is_user[0]++;
676 	}
677 
678 	check_split();
679 
680 	if ((istat.is_user[1] + istat.is_user[0]) > istat.is_m_users)
681 	{
682 
683 		istat.is_m_users = istat.is_user[1] + istat.is_user[0];
684 		if (timeofday - istat.is_m_users_t >= CLCHSEC)
685 		{
686 			sendto_flag(SCH_NOTICE,
687 				"New highest global client connection: %d",
688 				istat.is_m_users);
689 			istat.is_m_users_t = timeofday;
690 		}
691 	}
692 
693 	if (MyConnect(sptr))
694 	{
695 		char **isup;
696 
697 		istat.is_unknown--;
698 		istat.is_myclnt++;
699 		if (istat.is_myclnt > istat.is_m_myclnt)
700 		{
701 
702 			istat.is_m_myclnt = istat.is_myclnt;
703 			if (timeofday - istat.is_m_myclnt_t >= CLCHSEC)
704 			{
705 				sendto_flag(SCH_NOTICE,
706 					"New highest local client "
707 					"connection: %d", istat.is_m_myclnt);
708 				istat.is_m_myclnt_t = timeofday;
709 			}
710 		}
711 		if (istat.is_myclnt % CLCHNO == 0 &&
712 			istat.is_myclnt != istat.is_l_myclnt)
713 		{
714 			sendto_flag(SCH_NOTICE,
715 				"Local %screase from %d to %d clients "
716 				"in %d seconds",
717 				istat.is_myclnt>istat.is_l_myclnt?"in":"de",
718 				istat.is_l_myclnt, istat.is_myclnt,
719 				timeofday - istat.is_l_myclnt_t);
720 			istat.is_l_myclnt_t = timeofday;
721 			istat.is_l_myclnt = istat.is_myclnt;
722 		}
723 		strcpy(sptr->user->uid, next_uid());
724 		if (nick[0] == '0' && nick[1] == '\0')
725 		{
726 			strncpyzt(nick, sptr->user->uid, UIDLEN + 1);
727 			(void)strcpy(sptr->name, nick);
728 			(void)add_to_client_hash_table(nick, sptr);
729 		}
730 # if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_CONN)
731 		sendto_flag(SCH_CLIENT, "%s %s %s %s CONN %s"
732 # if (CLIENTS_CHANNEL_LEVEL & CCL_CONNINFO)
733 #  ifdef XLINE
734          " %s %s %s"
735 #  endif
736 			" :%s"
737 # endif
738 			, user->uid, nick, user->username,
739 			user->host, user->sip
740 # if (CLIENTS_CHANNEL_LEVEL & CCL_CONNINFO)
741 #  ifdef XLINE
742          , savedusername, sptr->user2, sptr->user3
743 #  endif
744 			, sptr->info
745 # endif
746 			);
747 #endif
748 		sprintf(buf, "%s!%s@%s", nick, user->username, user->host);
749 		add_to_uid_hash_table(sptr->user->uid, sptr);
750 		sptr->exitc = EXITC_REG;
751 		sendto_one(sptr, replies[RPL_WELCOME], ME, BadTo(nick), buf);
752 		/* This is a duplicate of the NOTICE but see below...*/
753 		sendto_one(sptr, replies[RPL_YOURHOST], ME, BadTo(nick),
754 			   get_client_name(&me, FALSE), version);
755 		sendto_one(sptr, replies[RPL_CREATED], ME, BadTo(nick), creation);
756 		sendto_one(sptr, replies[RPL_MYINFO], ME, BadTo(parv[0]),
757 			   ME, version);
758 
759 		isup = isupport;
760 		while (*isup)
761 		{
762 			sendto_one(sptr,replies[RPL_ISUPPORT], ME,
763 			BadTo(parv[0]),	*isup);
764 			isup++;
765 		}
766 
767 		sendto_one(sptr, replies[RPL_YOURID], ME, BadTo(parv[0]),
768 			sptr->user->uid);
769 		(void)m_lusers(sptr, sptr, 1, parv);
770 		(void)m_motd(sptr, sptr, 1, parv);
771 		if (IsRestricted(sptr))
772 			sendto_one(sptr, replies[ERR_RESTRICTED], ME, BadTo(nick));
773 		if (IsConfNoResolve(sptr->confs->value.aconf))
774 		{
775 			sendto_one(sptr, ":%s NOTICE %s :Due to an administrative"
776 				" decision, your hostname is not shown.",
777 				ME, nick);
778 		}
779 		else if (IsConfNoResolveMatch(sptr->confs->value.aconf))
780 		{
781 			sendto_one(sptr, ":%s NOTICE %s :Due to an administrative"
782 				" decision, your hostname is not shown,"
783 				" but still matches channel MODEs.",
784 				ME, nick);
785 		}
786 		send_umode(sptr, sptr, 0, ALL_UMODES, buf);
787 		nextping = timeofday;
788 
789 #ifdef SPLIT_CONNECT_NOTICE
790 		if (IsSplit())
791 		{
792 			sendto_one(sptr, ":%s NOTICE %s :%s", ME, nick,
793 				   SPLIT_CONNECT_NOTICE);
794 		}
795 #endif
796 	}
797 
798 	for (i = fdas.highest; i >= 0; i--)
799 	{
800 		/* Find my leaf servers and feed the new client to them */
801 		if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
802 			acptr == cptr || IsMe(acptr))
803 		{
804 			continue;
805 		}
806 		sendto_one(acptr,
807 				":%s UNICK %s %s %s %s %s %s :%s",
808 				user->servp->sid, nick, user->uid,
809 				user->username, user->host, user->sip,
810 				(*buf) ? buf : "+", sptr->info);
811 	}	/* for(my-leaf-servers) */
812 #ifdef	USE_SERVICES
813 #if 0
814 	check_services_butone(SERVICE_WANT_NICK, user->servp, NULL,
815 			      "NICK %s :%d", nick, sptr->hopcount+1);
816 	check_services_butone(SERVICE_WANT_USER, user->servp, sptr,
817 			      ":%s USER %s %s %s :%s", nick, user->username,
818 			      user->host, user->server, sptr->info);
819 	if (MyConnect(sptr))	/* all modes about local users */
820 		send_umode(NULL, sptr, 0, ALL_UMODES, buf);
821 	check_services_butone(SERVICE_WANT_UMODE, user->servp, sptr,
822 			      ":%s MODE %s :%s", nick, nick, buf);
823 #endif
824 	if (MyConnect(sptr))	/* all modes about local users */
825 		send_umode(NULL, sptr, 0, ALL_UMODES, buf);
826 	check_services_num(sptr, buf);
827 #endif
828 #ifdef USE_HOSTHASH
829 	add_to_hostname_hash_table(user->host, user);
830 #endif
831 #ifdef USE_IPHASH
832 	add_to_ip_hash_table(user->sip, user);
833 #endif
834 	return 1;
835 }
836 
837 /*
838 ** m_nick
839 **	parv[0] = sender prefix
840 **	parv[1] = nickname
841 */
m_nick(aClient * cptr,aClient * sptr,int parc,char * parv[])842 int	m_nick(aClient *cptr, aClient *sptr, int parc, char *parv[])
843 {
844 	aClient *acptr;
845 	int	delayed = 0;
846 	char	nick[NICKLEN+2], *user, *host;
847 	Link	*lp = NULL;
848 	int	allowednicklen;
849 
850 	if (MyConnect(cptr) && IsUnknown(cptr) &&
851 		IsConfServeronly(cptr->acpt->confs->value.aconf))
852 	{
853 		sendto_flag(SCH_LOCAL, "User connection to server-only P-line "
854 			"from %s", get_client_host(cptr));
855 		find_bounce(cptr, -1, -1);
856 		return exit_client(cptr, cptr, &me, "Server only port");
857 	}
858 	if (IsService(sptr))
859    	    {
860 		sendto_one(sptr, replies[ERR_ALREADYREGISTRED], ME, BadTo(parv[0]));
861 		return 1;
862 	    }
863 
864 	/* local clients' nick size can be LOCALNICKLEN max */
865 	allowednicklen = MyConnect(sptr) ? LOCALNICKLEN : NICKLEN;
866 	strncpyzt(nick, parv[1], allowednicklen + 1);
867 
868 	if (IsServer(cptr))
869 	{
870 		if (parc != 2)
871 		{
872 			char buf[BUFSIZE];
873 			int k;
874 
875 badparamcountkills:
876 			sendto_flag(SCH_NOTICE,
877 				"Bad NICK param count (%d) for %s from %s via %s",
878 				parc, parv[1], sptr->name,
879 				get_client_name(cptr, FALSE));
880 			buf[0] = '\0';
881 			for (k = 1; k < parc; k++)
882 			{
883 				strcat(buf, " ");
884 				strcat(buf, parv[k]);
885 			}
886 			sendto_flag(SCH_ERROR,
887 				"Bad NICK param count (%d) from %s via %s: %s NICK%s",
888 				parc, sptr->name,
889 				get_client_name(cptr, FALSE),
890 				parv[0], buf[0] ? buf : "");
891 			return 0;
892 		}
893 		else /* parc == 2 */
894 		{
895 			/* :old NICK new */
896 			user = sptr->user->username;
897 			host = sptr->user->host;
898 		}
899 	}
900 	else
901 	{
902 		if (sptr->user)
903 		{
904 			user = sptr->user->username;
905 			host = sptr->user->host;
906 		}
907 		else
908 			user = host = "";
909 	}
910 	/* Only local unregistered clients, I hope. --B. */
911 	if (MyConnect(sptr) && IsUnknown(sptr)
912 		&& nick[0] == '0' && nick[1] == '\0')
913 	{
914 		/* Allow registering with nick "0", this will be
915 		** overwritten in register_user() */
916 #ifdef DISABLE_NICK0_REGISTRATION
917 		sendto_one(sptr, replies[ERR_ERRONEOUSNICKNAME], ME,
918 			BadTo(parv[0]), nick);
919 		return 2;
920 #else
921 		goto nickkilldone;
922 #endif
923 	}
924 
925 	if (MyPerson(sptr))
926 	{
927 		if (!strcmp(sptr->name, nick))
928 		{
929 			/*
930 			** This is just ':old NICK old' type thing.
931 			** Just forget the whole thing here. There is
932 			** no point forwarding it to anywhere.
933 			*/
934 			return 2; /* NICK Message ignored */
935 		}
936 		/* "NICK 0" or "NICK UID" received */
937 		if ((nick[0] == '0' && nick[1] == '\0') ||
938 		    !mycmp(nick, sptr->user->uid))
939 		{
940 			/* faster equivalent of
941 			** !strcmp(sptr->name, sptr->user->uid) */
942 			if (isdigit(sptr->name[0]))
943 			{
944 				/* user nick is already an UID */
945 				return 2; /* NICK message ignored */
946 			}
947 			else
948 			{
949 				/* user changing his nick to UID */
950 				strncpyzt(nick, sptr->user->uid, UIDLEN + 1);
951 				goto nickkilldone;
952 			}
953 		}
954 	}
955 	if (IsServer(cptr) && isdigit(nick[0])
956 		&& !strncasecmp(me.serv->sid, nick, SIDLEN))
957 	{
958 		/* Remote server send us remote user changing his nick
959 		** to uid-like with our! sid. Burn the bastard. --B. */
960 		sendto_flag(SCH_KILL, "Bad SID Nick Prefix: %s From: %s %s",
961 				   parv[1], parv[0],
962 				   get_client_name(cptr, FALSE));
963                 sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s] != %s)",
964                                    me.name, sptr->user->uid, me.name,
965                                    sptr->name, sptr->from->name,
966                                    get_client_name(cptr, TRUE));
967                 sptr->flags |= FLAGS_KILLED;
968                 (void) exit_client(NULL, sptr, &me, "Fake SID Nick Prefix");
969                 return exit_client(NULL, cptr, &me, "Fake SID Nick Prefix");
970 	}
971 	/*
972 	 * if do_nick_name() returns a null name OR if the server sent a nick
973 	 * name and do_nick_name() changed it in some way (due to rules of nick
974 	 * creation) then reject it. If from a server and we reject it,
975 	 * we have to KILL it. -avalon 4/4/92
976 	 */
977 	if (do_nick_name(nick, IsServer(cptr)) == 0 ||
978 		strncmp(nick, parv[1], allowednicklen))
979 	{
980 		sendto_one(sptr, replies[ERR_ERRONEOUSNICKNAME], ME, BadTo(parv[0]),
981 			   parv[1]);
982 
983 		if (IsServer(cptr))
984 		    {
985 			ircstp->is_kill++;
986 			sendto_flag(SCH_KILL, "Bad Nick: %s From: %s %s",
987 				   parv[1], parv[0],
988 				   get_client_name(cptr, FALSE));
989 			if (sptr != cptr && sptr->user) /* bad nick change */
990 			    {
991 				sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])",
992 					   ME, sptr->user->uid, ME, parv[1],
993 					   nick, cptr->name);
994 				sendto_serv_butone(cptr,
995 					":%s KILL %s :%s (%s <- %s!%s@%s)",
996 					ME, sptr->user->uid, ME,
997 					get_client_name(cptr, FALSE),
998 					parv[0], user, host);
999 				sptr->flags |= FLAGS_KILLED;
1000 				return exit_client(cptr,sptr,&me,"BadNick");
1001 			    }
1002 		    }
1003 		return 2;
1004 	}
1005 
1006 	if (!(acptr = find_client(nick, NULL)))
1007 	    {
1008 		aClient	*acptr2;
1009 
1010 		if (IsServer(cptr) || !(bootopt & BOOT_PROT))
1011 			goto nickkilldone;
1012 		if ((acptr2 = get_history(nick, (long)(KILLCHASETIMELIMIT))) &&
1013 		    !MyConnect(acptr2))
1014 			/*
1015 			** Lock nick for KCTL so one cannot nick collide
1016 			** (due to kill chase) people who recently changed
1017 			** their nicks. --Beeth
1018 			*/
1019 			delayed = 1;
1020 		else
1021 			/*
1022 			** Let ND work
1023 			*/
1024 			delayed = find_history(nick, (long)(DELAYCHASETIMELIMIT));
1025 		if (!delayed)
1026 			goto nickkilldone;  /* No collisions, all clear... */
1027 	    }
1028 	/*
1029 	** If acptr == sptr, then we have a client doing a nick
1030 	** change between *equivalent* nicknames as far as server
1031 	** is concerned (user is changing the case of his/her
1032 	** nickname or somesuch)
1033 	*/
1034 	if (acptr == sptr)
1035 	{
1036 		/*
1037 		** Allows change of case in his/her nick
1038 		*/
1039 		goto nickkilldone; /* -- go and process change */
1040 	}
1041 	/*
1042 	** Note: From this point forward it can be assumed that
1043 	** acptr != sptr (points to different client structures).
1044 	*/
1045 	/*
1046 	** If the older one is "non-person", the new entry is just
1047 	** allowed to overwrite it. Just silently drop non-person,
1048 	** and proceed with the nick. This should take care of the
1049 	** "dormant nick" way of generating collisions...
1050 	*/
1051 	if (acptr && IsUnknown(acptr) && MyConnect(acptr))
1052 	    {
1053 		(void) exit_client(acptr, acptr, &me, "Overridden");
1054 		goto nickkilldone;
1055 	    }
1056 	/*
1057 	** Decide, we really have a nick collision and deal with it
1058 	*/
1059 	if (!IsServer(cptr))
1060 	    {
1061 		/*
1062 		** NICK is coming from local client connection. Just
1063 		** send error reply and ignore the command.
1064 		*/
1065 		sendto_one(sptr, replies[(delayed) ? ERR_UNAVAILRESOURCE
1066 						   : ERR_NICKNAMEINUSE],
1067 					 ME, BadTo(parv[0]), nick);
1068 		return 2; /* NICK message ignored */
1069 	    }
1070 	/*
1071 	** NICK was coming from a server connection. Means that the same
1072 	** nick is registered for different users by different server.
1073 	** This is either a race condition (two users coming online about
1074 	** same time, or net reconnecting) or just two net fragments becoming
1075 	** joined and having same nicks in use. We cannot have TWO users with
1076 	** same nick--purge this NICK from the system with a KILL... >;)
1077 	**
1078 	** Since 2.11, we SAVE both users, not KILL.
1079 	*/
1080 
1081 	/*
1082 	** This seemingly obscure test (sptr == cptr) differentiates
1083 	** between "NICK new" (TRUE) and ":old NICK new" (FALSE) forms.
1084 	*/
1085 	if (sptr == cptr)
1086 	{
1087 		/* 2.11+ do not introduce clients with NICK. --B. */
1088 		goto badparamcountkills;
1089 	}
1090 
1091 	/*
1092 	** Since it's not a new client, it must have an UID here,
1093 	** so SAVE them both.
1094 	*/
1095 	/* assert(sptr->user!=NULL); assert(acptr->user!=NULL); */
1096 	{
1097 		char	path[BUFSIZE];
1098 
1099 		/* Save acptr */
1100 		sprintf(path, "(%s@%s[%s](%s) <- %s@%s[%s])",
1101 			acptr->user->username,	acptr->user->host,
1102 			acptr->from->name, acptr->name,	user, host, cptr->name);
1103 		save_user(NULL, acptr, path);
1104 
1105 		/* Save sptr */
1106 		sprintf(path, "(%s@%s[%s] <- %s@%s[%s](%s))",
1107 			acptr->user->username, acptr->user->host,
1108 			acptr->from->name, user, host, cptr->name, sptr->name);
1109 		save_user(NULL, sptr, path);
1110 
1111 		/* Everything is done */
1112 		ircstp->is_save++;
1113 		return 2;
1114 	}
1115 
1116 nickkilldone:
1117 	if (IsServer(sptr))
1118 	{
1119 		/* 2.11+ do not introduce clients with NICK. --B. */
1120 		goto badparamcountkills;
1121 	}
1122 	else if (sptr->name[0])		/* NICK received before, changing */
1123 	{
1124 		if (MyConnect(sptr))
1125 		{
1126 			if (!IsPerson(sptr))    /* Unregistered client */
1127 				return 2;       /* Ignore new NICKs */
1128 			/*
1129 			** Restricted clients cannot change nicks
1130 			** with exception of changing nick from SAVEd UID.
1131 			** We could check for this earlier, so we would not
1132 			** do all those checks, just return error. --Beeth
1133 			*/
1134 			if (IsRestricted(sptr) && !isdigit(*parv[0]))
1135 			{
1136 				sendto_one(sptr, replies[ERR_RESTRICTED],
1137 					ME, BadTo(parv[0]));
1138 				return 2;
1139 			}
1140 			/* Can the user speak on all channels? */
1141 			for (lp = sptr->user->channel; lp; lp = lp->next)
1142 				if (can_send(sptr, lp->value.chptr) &&
1143 				    !IsQuiet(lp->value.chptr))
1144 					break;
1145 			/* If (lp), we give bigger penalty at the end. */
1146 #ifdef DISABLE_NICKCHANGE_WHEN_BANNED
1147 			if (lp)
1148 			{
1149 				sendto_one(sptr, replies[ERR_CANNOTSENDTOCHAN],
1150 					ME, BadTo(parv[0]),
1151 					lp->value.chptr->chname);
1152 				return 2;
1153 			}
1154 #endif
1155 		}
1156 		/*
1157 		** Client just changing his/her nick. If he/she is
1158 		** on a channel, send note of change to all clients
1159 		** on that channel. Propagate notice to other servers.
1160 		*/
1161 		sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick);
1162 #if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_NICK)
1163 		if (MyConnect(sptr))
1164 			sendto_flag(SCH_CLIENT, "%s %s %s %s NICK %s",
1165 				sptr->user->uid, parv[0],
1166 				sptr->user->username, sptr->user->host, nick);
1167 #endif
1168 		if (sptr->user) /* should always be true.. */
1169 		{
1170 			add_history(sptr, sptr);
1171 #ifdef	USE_SERVICES
1172 			check_services_butone(SERVICE_WANT_NICK,
1173 					      sptr->user->servp, sptr,
1174 					      ":%s NICK :%s", parv[0], nick);
1175 #endif
1176 		}
1177 		else
1178 			sendto_flag(SCH_NOTICE,
1179 				    "Illegal NICK change: %s -> %s from %s",
1180 				    parv[0], nick, get_client_name(cptr,TRUE));
1181 		sendto_serv_butone(cptr, ":%s NICK :%s", sptr->user->uid, nick);
1182 		if (sptr->name[0])
1183 			(void)del_from_client_hash_table(sptr->name, sptr);
1184 		(void)strcpy(sptr->name, nick);
1185 	}
1186 	else
1187 	{
1188 		/* Client setting NICK the first time */
1189 
1190 		/* This had to be copied here to avoid problems.. */
1191 		(void)strcpy(sptr->name, nick);
1192 		if (sptr->user)
1193 		{
1194 			/*
1195 			** USER already received, now we have NICK.
1196 			** *NOTE* For servers "NICK" *must* precede the
1197 			** user message (giving USER before NICK is possible
1198 			** only for local client connection!). register_user
1199 			** may reject the client and call exit_client for it
1200 			** --must test this and exit m_nick too!!!
1201 			*/
1202 			if (register_user(cptr, sptr, nick,
1203 					  sptr->user->username)
1204 			    == FLUSH_BUFFER)
1205 				return FLUSH_BUFFER;
1206 		}
1207 		/* If we returned from register_user, then the user registered
1208 		** and sptr->name is not "0" anymore; add_to_client_hash_table
1209 		** (few lines down) would be called second time for that client
1210 		** because register_user does that for "NICK 0" after copying
1211 		** UID onto client nick.
1212 		** OTOH, if no USER was yet received, isdigit is true only for
1213 		** client trying to register with "NICK 0". As we would have
1214 		** returned without adding "0" to client hash table anyway,
1215 		** we can safely return here. --B. */
1216 		if (isdigit(sptr->name[0]))
1217 		{
1218 			return 3;
1219 		}
1220 	}
1221 	/* Registered client doing "NICK 0" already has UID in sptr->name.
1222 	** If sptr->name is "0" here, it means there was no "USER" (thanks
1223 	** to that fiction's "isdigit" check above after register_user), so
1224 	** do not add_to_client_hash_table with nick "0", let register_user
1225 	** fill in UID first and add that to client hash table. --B. */
1226 	if (sptr->name[0] != '0' || sptr->name[1] != '\0')
1227 	{
1228 		/* Finally set new nick name. */
1229 		(void)add_to_client_hash_table(nick, sptr);
1230 	}
1231 	if (lp)
1232 		return 15;
1233 	else
1234 		return 3;
1235 }
1236 
1237 /*
1238 ** m_unick
1239 **	parv[0] = sender prefix
1240 **	parv[1] = nickname
1241 **	parv[2] = uid
1242 **	parv[3] = username (login name, account)
1243 **	parv[4] = client host name
1244 **	parv[5] = client ip
1245 **	parv[6] = users mode
1246 **	parv[7] = users real name info
1247 */
m_unick(aClient * cptr,aClient * sptr,int parc,char * parv[])1248 int	m_unick(aClient *cptr, aClient *sptr, int parc, char *parv[])
1249 {
1250 	aClient *acptr;
1251 	char	*uid, nick[NICKLEN+2], *user, *host, *realname;
1252 
1253 	strncpyzt(nick, parv[1], NICKLEN+1);
1254 	uid = parv[2];
1255 	user = parv[3];
1256 	host = parv[4];
1257 	realname = parv[7];
1258 
1259 	/*
1260 	 * if do_nick_name() returns a null name OR if the server sent a nick
1261 	 * name and do_nick_name() changed it in some way (due to rules of nick
1262 	 * creation) then reject it. If from a server and we reject it,
1263 	 * and KILL it. -avalon 4/4/92
1264 	 */
1265 	if (do_nick_name(nick, 1) == 0 || strcmp(nick, parv[1]))
1266 	{
1267 		sendto_one(sptr, replies[ERR_ERRONEOUSNICKNAME], ME, BadTo(parv[0]),
1268 			parv[1]);
1269 
1270 		ircstp->is_kill++;
1271 		sendto_flag(SCH_KILL, "Bad UNick: %s From: %s %s", parv[1],
1272 			parv[0], get_client_name(cptr, FALSE));
1273 		sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])", ME, uid, ME,
1274 			parv[1], nick, cptr->name);
1275 		return 2;
1276 	}
1277 
1278 	/*
1279 	** Check validity of UID.
1280 	*/
1281 	if (!check_uid(uid, sptr->serv->sid))
1282 	{
1283 		/* This is so bad, that I really don't want to deal with it! */
1284 		sendto_ops_butone(NULL, ME,
1285 			"Bad UID (%s) from %s",
1286 			uid, get_client_name(cptr, FALSE));
1287 		return exit_client(cptr, cptr, &me, "Bad UID");
1288 	}
1289 
1290 	/*
1291 	** Check against UID collisions,
1292 	** they should never happen, but never say never.
1293 	*/
1294 	acptr = find_uid(uid, NULL);
1295 	if (acptr)
1296 	{
1297 		/* This is so bad, that I really don't want to deal with it! */
1298 		sendto_ops_butone(NULL, ME,
1299 			"UID collision for %s from %s",
1300 			uid, get_client_name(cptr, FALSE));
1301 		return exit_client(cptr, cptr, &me, "UID collision");
1302 	}
1303 
1304 	/*
1305 	** Check against NICK collisions,
1306 	** and if possible save the two users.
1307 	*/
1308 	acptr = find_client(nick, NULL);
1309 	if (acptr)
1310 	    {
1311 		/*
1312 		** If the older one is "non-person", the new entry is just
1313 		** allowed to overwrite it. Just silently drop non-person,
1314 		** and proceed with the unick.
1315 		*/
1316 		if (IsUnknown(acptr) && MyConnect(acptr))
1317 		{
1318 			(void) exit_client(acptr, acptr, &me, "Overridden");
1319 		}
1320 		else
1321 		/*
1322 		** Ouch, this new client is trying to take an already
1323 		** existing nickname..
1324 		*/
1325 		if (*acptr->user->uid)
1326 		    {
1327 			char	path[BUFSIZE];
1328 
1329 			/* both users have a UID, save them */
1330 
1331 			/* Save the other user.  Send it to all servers. */
1332 			sprintf(path, "(%s@%s)%s <- (%s@%s)%s",
1333 				acptr->user->username, acptr->user->host,
1334 				acptr->user->server, user, host, cptr->name);
1335 			save_user(NULL, acptr, path);
1336 
1337 			/*
1338 			** We need to send a SAVE for the new user back.
1339 			** It isn't introduced yet, so we can't just call
1340 			** save_user().
1341 			*/
1342 			sendto_one(cptr,
1343 				":%s SAVE %s :%s (%s@%s)%s <- (%s@%s)%s",
1344 				me.serv->sid, uid, ME,
1345 				acptr->user->username, acptr->user->host,
1346 				acptr->user->server, user, host, cptr->name);
1347 
1348 			/* Just introduce him with the uid to the rest. */
1349 			strcpy(nick, uid);
1350 			ircstp->is_save++;
1351 		    }
1352 		else
1353 		    {
1354 			/*
1355 			** sadly, both have to be killed because:
1356 			** - we cannot rely on cptr do kill acptr
1357 			**   as the new user introduced here may have changed
1358 			**   nicknames before the collision happens on cptr
1359 			** - sending a kill to cptr means nick chasing will
1360 			**   get to the new user introduced here.
1361 			*/
1362 			sendto_one(acptr,
1363 				   replies[ERR_NICKCOLLISION], ME, BadTo(acptr->name),
1364 				   acptr->name, user, host);
1365 			sendto_flag(SCH_KILL,
1366 			    "Nick collision on %s (%s@%s)%s <- (%s@%s)%s",
1367 				    acptr->name,
1368 				    (acptr->user)?acptr->user->username:"???",
1369 				    (acptr->user) ? acptr->user->host : "???",
1370 				    acptr->from->name,
1371 				    user, host, get_client_name(cptr, FALSE));
1372 			ircstp->is_kill++;
1373 			sendto_serv_butone(NULL,
1374 				   ":%s KILL %s :%s ((%s@%s)%s <- (%s@%s)%s)",
1375 				   ME, acptr->name, ME,
1376 				   (acptr->user) ? acptr->user->username:"???",
1377 				   (acptr->user) ? acptr->user->host : "???",
1378 				   acptr->from->name, user, host,
1379 				   get_client_name(cptr, FALSE));
1380 			acptr->flags |= FLAGS_KILLED;
1381 			return exit_client(NULL, acptr, &me, "Nick collision");
1382 		    }
1383 	    }
1384 
1385 	/*
1386 	** the following is copied from m_user() as we need only
1387 	** few things from it here, as we assume (should we?) it
1388 	** is all ok since UNICK can come only from other server
1389 	*/
1390 	acptr = make_client(cptr);
1391 	add_client_to_list(acptr);
1392 	(void)make_user(acptr, strlen(parv[5]));
1393 	/* more corrrect is this, but we don't yet have ->mask, so...
1394 	acptr->user->servp = find_server_name(sptr->serv->mask->serv->snum);
1395 	... just remember to change it one day --Beeth */
1396 	acptr->user->servp = sptr->serv;
1397 	sptr->serv->refcnt++;
1398 	acptr->user->server = find_server_string(sptr->serv->snum);
1399 	if (strlen(realname) > REALLEN)
1400 	{
1401 		realname[REALLEN] = '\0';
1402 	}
1403 	acptr->info = mystrdup(realname);
1404 	strncpyzt(acptr->user->username, parv[3], USERLEN+1);
1405 	strncpyzt(acptr->user->host, host, sizeof(acptr->user->host));
1406 	reorder_client_in_list(acptr);
1407 
1408 	/*
1409 	** NOTE: acptr->name has to be set *after* calling m_user();
1410 	** else it will already introduce the client which
1411 	** can't have the uid set yet.
1412 	** the extended m_nick() does things the other way around..
1413 	** I hope this will not cause trouble sometime later. -kalt
1414 	** You could do things like m_nick(), but you then you should
1415 	** stop it from making a call to register_user().
1416 	*/
1417 	/* The nick is already checked for size, and is a local var. */
1418 	strcpy(acptr->name, nick);
1419 	add_to_client_hash_table(nick, acptr);
1420 	/* we don't have hopcount in unick, we take it from sptr */
1421 	acptr->hopcount = sptr->hopcount;
1422 	/* The client is already killed if the uid is too long. */
1423 	strcpy(acptr->user->uid, uid);
1424 	strcpy(acptr->user->sip, parv[5]);
1425 	add_to_uid_hash_table(uid, acptr);
1426 	{
1427 	    char	*pv[4];
1428 
1429 	    pv[0] = ME;
1430 	    pv[1] = acptr->name;
1431 	    pv[2] = parv[6];
1432 	    pv[3] = NULL;
1433 	    m_umode(NULL, acptr, 3, pv);
1434 	}
1435 	register_user(cptr, acptr, nick, user);
1436 	return 0;
1437 }
1438 
1439 /*
1440 ** m_message (used in m_private() and m_notice())
1441 ** the general function to deliver MSG's between users/channels
1442 **
1443 **	parv[0] = sender prefix
1444 **	parv[1] = receiver list
1445 **	parv[2] = message text
1446 **
1447 ** massive cleanup
1448 ** rev argv 6/91
1449 **
1450 */
1451 
m_message(aClient * cptr,aClient * sptr,int parc,char * parv[],int notice)1452 static	int	m_message(aClient *cptr, aClient *sptr, int parc,
1453 		char *parv[], int notice)
1454 {
1455 	Reg	aClient	*acptr;
1456 	Reg	char	*s;
1457 	aChannel *chptr;
1458 	char	*nick, *server, *p, *cmd, *user, *host;
1459 	int	count = 0, penalty = 0, syntax = 0;
1460 
1461 	cmd = notice ? "NOTICE" : "PRIVMSG";
1462 
1463 	if (MyConnect(sptr))
1464 		parv[1] = canonize(parv[1]);
1465 	for (p = NULL, nick = strtoken(&p, parv[1], ","); nick;
1466 	     nick = strtoken(&p, NULL, ","), penalty++)
1467 	    {
1468 		/*
1469 		** restrict destination list to MAXPENALTY/2 recipients to
1470 		** solve SPAM problem --Yegg
1471 		*/
1472 		if (2*penalty >= MAXPENALTY) {
1473 		    if (!notice)
1474 			    sendto_one(sptr, replies[ERR_TOOMANYTARGETS],
1475 				       ME, BadTo(parv[0]),
1476 				       "Too many",nick,"No Message Delivered");
1477 		    continue;
1478 		}
1479 		/*
1480 		** nickname addressed?
1481 		*/
1482 		if (((IsServer(cptr) || IsService(cptr))
1483 			&& (acptr = find_uid(nick, NULL))) ||
1484 			(acptr = find_person(nick, NULL)))
1485 		    {
1486 			if (!notice && MyConnect(sptr) &&
1487 			    acptr->user && (acptr->user->flags & FLAGS_AWAY))
1488 				send_away(sptr, acptr);
1489 			sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
1490 					  parv[0], cmd, acptr->name, parv[2]);
1491 			continue;
1492 		    }
1493 		/*
1494 		** channel msg?
1495 		*/
1496 		if ((IsPerson(sptr) || IsService(sptr) || IsServer(sptr)) &&
1497 		    (chptr = find_channel(nick, NullChn)))
1498 		    {
1499 			if (can_send(sptr, chptr) == 0 || IsServer(sptr))
1500 				sendto_channel_butone(cptr, sptr, chptr,
1501 						      ":%s %s %s :%s",
1502 						      parv[0], cmd, nick,
1503 						      parv[2]);
1504 			else if (!notice)
1505 				sendto_one(sptr, replies[ERR_CANNOTSENDTOCHAN],
1506 					   ME, BadTo(parv[0]), nick);
1507 			continue;
1508 		    }
1509 
1510 		/*
1511 		** the following two cases allow masks in NOTICEs
1512 		** (for OPERs only)
1513 		**
1514 		** Armin, 8Jun90 (gruner@informatik.tu-muenchen.de)
1515 		**
1516 		** NOTE: 2.11 changed syntax from $/#-mask to $$/$#-mask
1517 		*/
1518 		if (IsAnOper(sptr))
1519 		{
1520 			if (*nick == '$')
1521 			{
1522 				if (*(nick+1) == '$')
1523 				{
1524 					syntax = MATCH_SERVER;
1525 				}
1526 				else if (*(nick+1) == '#')
1527 				{
1528 					syntax = MATCH_HOST;
1529 				}
1530 			}
1531 		}
1532 		if (syntax)
1533 		{
1534 			if (!(s = (char *)rindex(nick, '.')))
1535 			{
1536 				sendto_one(sptr, replies[ERR_NOTOPLEVEL],
1537 					   ME, BadTo(parv[0]), nick);
1538 				continue;
1539 			}
1540 			while (*++s)
1541 				if (*s == '.' || *s == '*' || *s == '?')
1542 					break;
1543 			if (*s == '*' || *s == '?')
1544 			{
1545 				sendto_one(sptr, replies[ERR_WILDTOPLEVEL],
1546 					ME, BadTo(parv[0]), nick);
1547 				continue;
1548 			}
1549 			sendto_match_butone(
1550 				IsServer(cptr) ? cptr : NULL,
1551 				sptr, nick + 2, syntax,
1552 				":%s %s %s :%s", parv[0],
1553 				cmd, nick, parv[2]);
1554 			continue;
1555 		}	/* syntax */
1556 
1557 		/*
1558 		** nick!user@host addressed?
1559 		*/
1560 		if ((user = (char *)index(nick, '!')) &&
1561 		    (host = (char *)index(nick, '@')))
1562 		    {
1563 			*user = '\0';
1564 			*host = '\0';
1565 			if ((acptr = find_person(nick, NULL)) &&
1566 			    !mycmp(user+1, acptr->user->username) &&
1567 			    !mycmp(host+1, acptr->user->host))
1568 			    {
1569 				sendto_prefix_one(acptr, sptr, ":%s %s %s :%s",
1570 						  parv[0], cmd, nick, parv[2]);
1571 				*user = '!';
1572 				*host = '@';
1573 				continue;
1574 			    }
1575 			*user = '!';
1576 			*host = '@';
1577 		    }
1578 
1579 		/*
1580 		** user[%host]@server addressed?
1581 		*/
1582 		if ((server = (char *)index(nick, '@')) &&
1583 		    (acptr = find_server(server + 1, NULL)))
1584 		    {
1585 			/*
1586 			** Not destined for a user on me :-(
1587 			*/
1588 			if (!IsMe(acptr))
1589 			    {
1590 				sendto_one(acptr,":%s %s %s :%s", parv[0],
1591 					   cmd, nick, parv[2]);
1592 				continue;
1593 			    }
1594 			*server = '\0';
1595 
1596 			if ((host = (char *)index(nick, '%')))
1597 				*host++ = '\0';
1598 
1599 			/*
1600 			** Look for users which match the destination host
1601 			** (no host == wildcard) and if one and one only is
1602 			** found connected to me, deliver message!
1603 			*/
1604 			acptr = find_userhost(nick, host, NULL, &count);
1605 			if (server)
1606 				*server = '@';
1607 			if (host)
1608 				*--host = '%';
1609 			if (acptr)
1610 			    {
1611 				if (count == 1)
1612 					sendto_prefix_one(acptr, sptr,
1613 							  ":%s %s %s :%s",
1614 					 		  parv[0], cmd,
1615 							  nick, parv[2]);
1616 				else if (!notice)
1617 					sendto_one(sptr, replies[ERR_TOOMANYTARGETS],
1618 						   ME, BadTo(parv[0]), "Duplicate", nick,
1619 						   "No Message Delivered");
1620 				continue;
1621 			    }
1622 		    }
1623 		else if ((host = (char *)index(nick, '%')))
1624 		    {
1625 			/*
1626 			** user%host addressed?
1627 			*/
1628 			*host++ = '\0';
1629 			acptr = find_userhost(nick, host, NULL, &count);
1630 			*--host = '%';
1631 			if (acptr)
1632 			    {
1633 				if (count == 1)
1634 					sendto_prefix_one(acptr, sptr,
1635 							  ":%s %s %s :%s",
1636 					 		  parv[0], cmd,
1637 							  nick, parv[2]);
1638 				else if (!notice)
1639 					sendto_one(sptr, replies[ERR_TOOMANYTARGETS],
1640 						   ME, BadTo(parv[0]), "Duplicate", nick,
1641 						   "No Message Delivered");
1642 				continue;
1643 			    }
1644 		    }
1645 		if (!notice)
1646 			sendto_one(sptr, replies[ERR_NOSUCHNICK], ME, BadTo(parv[0]),
1647 				   nick);
1648 	    }
1649     return penalty;
1650 }
1651 
1652 /*
1653 ** m_private
1654 **	parv[0] = sender prefix
1655 **	parv[1] = receiver list
1656 **	parv[2] = message text
1657 */
1658 
m_private(aClient * cptr,aClient * sptr,int parc,char * parv[])1659 int	m_private(aClient *cptr, aClient *sptr, int parc, char *parv[])
1660 {
1661 	return m_message(cptr, sptr, parc, parv, 0);
1662 }
1663 
1664 /*
1665 ** m_notice
1666 **	parv[0] = sender prefix
1667 **	parv[1] = receiver list
1668 **	parv[2] = notice text
1669 */
1670 
m_notice(aClient * cptr,aClient * sptr,int parc,char * parv[])1671 int	m_notice(aClient *cptr, aClient *sptr, int parc, char *parv[])
1672 {
1673 	return m_message(cptr, sptr, parc, parv, 1);
1674 }
1675 
1676 /*
1677 ** who_one
1678 **	sends one RPL_WHOREPLY to sptr concerning acptr & repchan
1679 */
who_one(aClient * sptr,aClient * acptr,aChannel * repchan,Link * lp)1680 static	void	who_one(aClient *sptr, aClient *acptr, aChannel *repchan,
1681 		Link *lp)
1682 {
1683 	char	status[5];
1684 	int	i = 0;
1685 
1686 	if (acptr->user->flags & FLAGS_AWAY)
1687 		status[i++] = 'G';
1688 	else
1689 		status[i++] = 'H';
1690 	if (IsAnOper(acptr))
1691 		status[i++] = '*';
1692 	if ((repchan != NULL) && (lp == NULL))
1693 		lp = find_user_link(repchan->members, acptr);
1694 	if (lp != NULL)
1695 	    {
1696 		if (lp->flags & CHFL_CHANOP)
1697 			status[i++] = '@';
1698 		else if (lp->flags & CHFL_VOICE)
1699 			status[i++] = '+';
1700 	    }
1701 	status[i] = '\0';
1702 	sendto_one(sptr, replies[RPL_WHOREPLY], ME, BadTo(sptr->name),
1703 		   (repchan) ? (repchan->chname) : "*", acptr->user->username,
1704 		   acptr->user->host, acptr->user->server, acptr->name,
1705 		   status, acptr->hopcount, acptr->user->servp->sid, acptr->info);
1706 }
1707 
1708 
1709 /*
1710 ** who_channel
1711 **	lists all users on a given channel
1712 */
who_channel(aClient * sptr,aChannel * chptr,int oper)1713 static	void	who_channel(aClient *sptr, aChannel *chptr, int oper)
1714 {
1715 	Reg	Link	*lp;
1716 	int	member;
1717 
1718 	if (!IsAnonymous(chptr))
1719 	{
1720 		member = IsMember(sptr, chptr);
1721 		if (member || !SecretChannel(chptr))
1722 		{
1723 			for (lp = chptr->members; lp; lp = lp->next)
1724 			{
1725 				if (oper && !IsAnOper(lp->value.cptr))
1726 				{
1727 					continue;
1728 				}
1729 				if (IsInvisible(lp->value.cptr) && !member)
1730 				{
1731 					continue;
1732 				}
1733 				who_one(sptr, lp->value.cptr, chptr, lp);
1734 			}
1735 		}
1736 	}
1737 	else if ((lp = find_user_link(chptr->members, sptr)))
1738 	{
1739 		who_one(sptr, lp->value.cptr, chptr, lp);
1740 	}
1741 }
1742 
1743 /*
1744 ** who_find
1745 **	lists all (matching) users.
1746 **	CPU intensive, but what can be done?
1747 **
1748 **	Reduced CPU load - 05/2001
1749 */
who_find(aClient * sptr,char * mask,int oper)1750 static	void	who_find(aClient *sptr, char *mask, int oper)
1751 {
1752 	aChannel *chptr = NULL;
1753 	Link	*lp,*lp2;
1754 	aClient	*acptr;
1755 
1756 	/* first, show INvisible matching users on common channels */
1757 	if (sptr->user) /* service can request who as well */
1758 	for (lp = sptr->user->channel; lp ;lp = lp->next)
1759 	{
1760 		chptr = lp->value.chptr;
1761 		if (IsAnonymous(chptr))
1762 			continue;
1763 		for (lp2 = chptr->members; lp2 ;lp2 = lp2->next)
1764 		{
1765 			acptr = lp2->value.cptr;
1766 
1767 			if (!IsInvisible(acptr)
1768 			    || (acptr->flags & FLAGS_HIDDEN))
1769 			{
1770 				continue;
1771 			}
1772 
1773 			if (oper && !IsAnOper(acptr))
1774 			{
1775 				continue;
1776 			}
1777 
1778 			/* Mark user with FLAGS_HIDDEN to prevent multiple
1779 			 * checking.
1780 			 */
1781 
1782 			acptr->flags |= FLAGS_HIDDEN;
1783 			if (!mask ||
1784 			     match(mask, acptr->name) == 0 ||
1785 			     match(mask, acptr->user->username) == 0 ||
1786 			     match(mask, acptr->user->host) == 0 ||
1787 			     match(mask, acptr->user->server) == 0 ||
1788 			     match(mask, acptr->info) == 0)
1789 				who_one(sptr, acptr, chptr, NULL);
1790 
1791 		}
1792 	}
1793 
1794 	for (acptr = client; acptr; acptr = acptr->next)
1795 	{
1796 
1797 		if (!IsPerson(acptr))
1798 			continue;
1799 
1800 		/* clear the flag */
1801 		if (acptr->flags & FLAGS_HIDDEN)
1802 		{
1803 			acptr->flags &= ~FLAGS_HIDDEN;
1804 			continue;
1805 		}
1806 
1807 		/* allow local opers to see matching clients
1808 		 * on _LOCAL_ server and show the user himself */
1809 		if (IsInvisible(acptr) && (acptr != sptr)
1810 		    && !(MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
1811 		   )
1812 		{
1813 			continue;
1814 		}
1815 
1816 		/* we wanted only opers */
1817 		if (oper && !IsAnOper(acptr))
1818 		{
1819 			continue;
1820 		}
1821 
1822 		/*
1823 		** This is brute force solution, not efficient...? ;(
1824 		** Show entry, if no mask or any of the fields match
1825 		** the mask. --msa
1826 		*/
1827 		if (!mask ||
1828 		     match(mask, acptr->name) == 0 ||
1829 		     match(mask, acptr->user->username) == 0 ||
1830 		     match(mask, acptr->user->host) == 0 ||
1831 		     match(mask, acptr->user->server) == 0 ||
1832 		     match(mask, acptr->info) == 0)
1833 			who_one(sptr, acptr, NULL, NULL);
1834 	}
1835 
1836 }
1837 
1838 
1839 /*
1840 ** m_who
1841 **	parv[0] = sender prefix
1842 **	parv[1] = nickname mask list
1843 **	parv[2] = additional selection flag, only 'o' for now.
1844 */
m_who(aClient * cptr,aClient * sptr,int parc,char * parv[])1845 int	m_who(aClient *cptr, aClient *sptr, int parc, char *parv[])
1846 {
1847 	aChannel *chptr;
1848 	int	oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */
1849 	int	penalty = 0;
1850 	char	*p, *mask, *channame;
1851 
1852 	if (parc < 2)
1853 	{
1854 		who_find(sptr, NULL, oper);
1855 		sendto_one(sptr, replies[RPL_ENDOFWHO], ME, BadTo(parv[0]), "*");
1856 		/* it was very CPU intensive */
1857 		return MAXPENALTY;
1858 	}
1859 
1860 	/* get rid of duplicates */
1861 	parv[1] = canonize(parv[1]);
1862 
1863 	for (p = NULL, mask = strtoken(&p, parv[1], ",");
1864 	    mask && penalty <= MAXPENALTY;
1865 		mask = strtoken(&p, NULL, ","))
1866 	{
1867 		channame = NULL;
1868 		penalty += 1;
1869 
1870 		/* find channel user last joined, we might need it later */
1871 		if (sptr->user && sptr->user->channel)
1872 			channame = sptr->user->channel->value.chptr->chname;
1873 
1874 		if (clean_channelname(mask) == -1)
1875 			/* maybe we should tell user? --B. */
1876 			continue;
1877 
1878 		/*
1879 		** We can never have here !mask
1880 		** or *mask == '\0', since it would be equal
1881 		** to parc == 1, that is 'WHO' and/or would not
1882 		** pass through above for loop.
1883 		*/
1884 		if (mask[1] == '\0' && mask[0] == '0')
1885 		{
1886 			/*
1887 			** 'WHO 0' - do who_find() later
1888 			*/
1889 			mask = NULL;
1890 			channame = NULL;
1891 		}
1892 		else if (mask[1] == '\0' && mask[0] == '*')
1893 		{
1894 			/*
1895 			** 'WHO *'
1896 			** If user was on any channel, list the one
1897 			** he joined last.
1898 			*/
1899 			mask = NULL;
1900 		}
1901 		else
1902 		{
1903 			/*
1904 			** Try if mask was channelname and if yes, do
1905 			** who_channel, else if mask was nick, do who_one.
1906 			** Else do horrible who_find()
1907 			*/
1908 			channame = mask;
1909 		}
1910 
1911 		if (IsChannelName(channame))
1912 		{
1913 			chptr = find_channel(channame, NULL);
1914 			if (chptr)
1915 			{
1916 				who_channel(sptr, chptr, oper);
1917 			}
1918 			else
1919 			{
1920 				/*
1921 				** 'WHO #nonexistant'.
1922 				*/
1923 				penalty += 1;
1924 			}
1925 		}
1926 		else
1927 		{
1928 			aClient	*acptr = NULL;
1929 
1930 			if (mask)
1931 			{
1932 				/*
1933 				** Here mask can be NULL. It doesn't matter,
1934 				** since find_client would return NULL.
1935 				** Just saving one function call. ;)
1936 				*/
1937 				acptr = find_client(mask, NULL);
1938 				if (acptr && !IsClient(acptr))
1939 				{
1940 					acptr = NULL;
1941 				}
1942 			}
1943 			if (acptr)
1944 			{
1945 				/* We found client, so send WHO for it */
1946 				who_one(sptr, acptr, NULL, NULL);
1947 			}
1948 			else
1949 			{
1950 				/*
1951 				** All nice chances lost above.
1952 				** We must hog our server with that.
1953 				*/
1954 
1955 				/* simplify mask */
1956 				(void)collapse(mask);
1957 
1958 				who_find(sptr, mask, oper);
1959 				penalty += MAXPENALTY;
1960 			}
1961 		}
1962 		sendto_one(sptr, replies[RPL_ENDOFWHO], ME, BadTo(parv[0]),
1963 			   BadPtr(mask) ?  "*" : mask);
1964 	}
1965 	return penalty;
1966 }
1967 
1968 /* send_whois() is used by m_whois() to send whois reply to sptr, for acptr */
send_whois(aClient * sptr,aClient * acptr)1969 static	void	send_whois(aClient *sptr, aClient *acptr)
1970 {
1971 	static anUser UnknownUser =
1972 	    {
1973 		NULL,	/* channel */
1974 		NULL,   /* invited */
1975 		NULL,	/* uwas */
1976 		NULL,	/* away */
1977 		0,	/* last */
1978 		1,      /* refcount */
1979 		0,	/* joined */
1980 		0,	/* flags */
1981 		NULL,	/* servp */
1982 		0, NULL, NULL,	/* hashc, uhnext, bcptr */
1983 		"<Unknown>",	/* user */
1984 		"0",		/* uid */
1985 		"<Unknown>",	/* host */
1986 		"<Unknown>",	/* server */
1987 	    };
1988 	Link	*lp;
1989 	anUser	*user;
1990 	aChannel *chptr;
1991 	aClient *a2cptr;
1992 	int len, mlen;
1993 	char *name;
1994 
1995 	user = acptr->user ? acptr->user : &UnknownUser;
1996 	name = (!*acptr->name) ? "?" : acptr->name;
1997 
1998 	a2cptr = find_server(user->server, NULL);
1999 
2000 	sendto_one(sptr, replies[RPL_WHOISUSER], ME, BadTo(sptr->name),
2001 		   name, user->username, user->host, acptr->info);
2002 
2003 	mlen = strlen(ME) + strlen(sptr->name) + 6 + strlen(name);
2004 
2005 	for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next)
2006 	    {
2007 		chptr = lp->value.chptr;
2008 		if ((!IsAnonymous(chptr) || acptr == sptr) &&
2009 		    ShowChannel(sptr, chptr))
2010 		    {
2011 			if (len + strlen(chptr->chname)
2012 			    > (size_t) BUFSIZE - 4 - mlen)
2013 			    {
2014 				sendto_one(sptr, ":%s %d %s %s :%s", ME,
2015 					   RPL_WHOISCHANNELS, sptr->name, name,
2016 					   buf);
2017 				*buf = '\0';
2018 				len = 0;
2019 			    }
2020 			if (is_chan_op(acptr, chptr))
2021 				*(buf + len++) = '@';
2022 			else if (has_voice(acptr, chptr))
2023 				*(buf + len++) = '+';
2024 			if (len)
2025 				*(buf + len) = '\0';
2026 			(void)strcpy(buf + len, chptr->chname);
2027 			len += strlen(chptr->chname);
2028 			(void)strcat(buf + len, " ");
2029 			len++;
2030 		    }
2031 	    }
2032 	if (buf[0] != '\0')
2033 		sendto_one(sptr, replies[RPL_WHOISCHANNELS], ME, BadTo(sptr->name), name,
2034 			   buf);
2035 
2036 	sendto_one(sptr, replies[RPL_WHOISSERVER], ME, BadTo(sptr->name),
2037 		   name, user->server,
2038 		   a2cptr ? a2cptr->info:"*Not On This Net*");
2039 
2040 	if (user->flags & FLAGS_AWAY)
2041 		send_away(sptr, user->bcptr);
2042 
2043 	if (IsAnOper(acptr))
2044 		sendto_one(sptr, replies[RPL_WHOISOPERATOR], ME, BadTo(sptr->name), name);
2045 
2046 	if (acptr->user && MyConnect(acptr))
2047 		sendto_one(sptr, replies[RPL_WHOISIDLE], ME, BadTo(sptr->name),
2048 			   name, (long)(timeofday - user->last)
2049 #ifdef WHOIS_SIGNON_TIME
2050 			, (long)acptr->firsttime
2051 #endif
2052 			);
2053 }
2054 
2055 /*
2056 ** m_whois
2057 **	parv[0] = sender prefix
2058 **	parv[1] = nickname masklist
2059 */
m_whois(aClient * cptr,aClient * sptr,int parc,char * parv[])2060 int	m_whois(aClient *cptr, aClient *sptr, int parc, char *parv[])
2061 {
2062 	Link	*lp;
2063 	aClient *acptr;
2064 	aChannel *chptr;
2065 	char	*nick, *tmp, *tmp2;
2066 	char	*p = NULL;
2067 	int	found = 0;
2068 
2069     	if (parc < 2)
2070 	    {
2071 		sendto_one(sptr, replies[ERR_NONICKNAMEGIVEN], ME, BadTo(parv[0]));
2072 		return 1;
2073 	    }
2074 
2075 	if (parc > 2)
2076 	    {
2077 		if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) !=
2078 		    HUNTED_ISME)
2079 			return 3;
2080 		parv[1] = parv[2];
2081 	    }
2082 
2083 	tmp = mystrdup(parv[1]);
2084 
2085 	for (tmp2 = canonize(tmp); (nick = strtoken(&p, tmp2, ","));
2086 		tmp2 = NULL)
2087 	    {
2088 		int	invis, showperson, member, wilds;
2089 
2090 		found &= 0x0f;	/* high/boolean, low/counter */
2091 		(void)collapse(nick);
2092 		wilds = (index(nick, '?') || index(nick, '*'));
2093 		/*
2094 		 * We're no longer allowing remote users to generate
2095 		 * requests with wildcard, nor local users with more
2096 		 * than one wildcard target per command.
2097 		 * Max 3 targets per command allowed.
2098 		 */
2099 		if ((wilds && (!MyConnect(sptr) || p)) || found++ > 3)
2100 			break;
2101 
2102 		if (!wilds)
2103 		    {
2104 			acptr = hash_find_client(nick, (aClient *)NULL);
2105 			if (!acptr || !IsPerson(acptr))
2106 				sendto_one(sptr,
2107 					   replies[ERR_NOSUCHNICK], ME, BadTo(parv[0]),
2108 					   nick);
2109 			else
2110 				send_whois(sptr, acptr);
2111 			continue;
2112 		    }
2113 
2114 		for (acptr = client; (acptr = next_client(acptr, nick));
2115 		     acptr = acptr->next)
2116 		    {
2117 			if (IsServer(acptr) || IsService(acptr))
2118 				continue;
2119 			/*
2120 			 * I'm always last :-) and acptr->next == NULL!!
2121 			 */
2122 			if (IsMe(acptr))
2123 				break;
2124 			/*
2125 			 * 'Rules' established for sending a WHOIS reply:
2126 			 * - if wildcards are being used don't send a reply if
2127 			 *   the querier isnt any common channels and the
2128 			 *   client in question is invisible and wildcards are
2129 			 *   in use (allow exact matches only);
2130 			 * - only send replies about common or public channels
2131 			 *   the target user(s) are on;
2132 			 */
2133 			invis = (acptr->user) ?
2134 				(acptr->user->flags & FLAGS_INVISIBLE) : 0;
2135 			member = (acptr->user && acptr->user->channel) ? 1 : 0;
2136 			showperson = (wilds && !invis && !member) || !wilds;
2137 			for (lp = (acptr->user) ? acptr->user->channel : NULL;
2138 			     lp; lp = lp->next)
2139 			    {
2140 				chptr = lp->value.chptr;
2141 				if (IsAnonymous(chptr))
2142 					continue;
2143 				member = IsMember(sptr, chptr);
2144 				if (invis && !member)
2145 					continue;
2146 				if (member || (!invis && PubChannel(chptr)))
2147 				    {
2148 					showperson = 1;
2149 					break;
2150 				    }
2151 				if (!invis && HiddenChannel(chptr) &&
2152 				    !SecretChannel(chptr))
2153 					showperson = 1;
2154 			    }
2155 			if (!showperson)
2156 				continue;
2157 
2158 			found |= 0x10;
2159 
2160 			send_whois(sptr, acptr);
2161 		    }
2162 		if (!(found & 0x10))
2163 		    {
2164 			if (strlen(nick) > (size_t) NICKLEN)
2165 				nick[NICKLEN] = '\0';
2166 			sendto_one(sptr, replies[ERR_NOSUCHNICK], ME, BadTo(parv[0]),
2167 				   nick);
2168 		    }
2169 		if (p)
2170 			p[-1] = ',';
2171 	    }
2172 	sendto_one(sptr, replies[RPL_ENDOFWHOIS], ME, BadTo(parv[0]), parv[1]);
2173 
2174 	MyFree(tmp);
2175 
2176 	return 2;
2177 }
2178 
2179 /*
2180 ** m_user
2181 **	parv[0] = sender prefix
2182 **	parv[1] = username (login name, account)
2183 **	parv[2] = user modes
2184 **	parv[3] = unused
2185 **	parv[4] = real name info
2186 **
2187 ** NOTE: As of 2.11.1 we no longer call m_user() internally. --B.
2188 */
m_user(aClient * cptr,aClient * sptr,int parc,char * parv[])2189 int	m_user(aClient *cptr, aClient *sptr, int parc, char *parv[])
2190 {
2191 #define	UFLAGS	(FLAGS_INVISIBLE|FLAGS_WALLOP|FLAGS_RESTRICT)
2192 	struct umodes_arr_s
2193 	{
2194 		char umode;
2195 		int flag;
2196 	} umodes_arr[] =
2197 	{ {'i', FLAGS_INVISIBLE},
2198 	  {'r', FLAGS_RESTRICT},
2199 	  {'w', FLAGS_WALLOP},
2200 	  {'\0', 0}
2201 	};
2202 
2203 	char	*username, *umodes, *server, *realname;
2204 	anUser	*user;
2205 	char	ipbuf[BUFSIZE];
2206 	int	what,i;
2207 	char 	*s;
2208 
2209 	if (MyConnect(cptr) && IsUnknown(cptr) &&
2210 		IsConfServeronly(cptr->acpt->confs->value.aconf))
2211 	{
2212 		sendto_flag(SCH_LOCAL, "User connection to server-only P-line "
2213 			"from %s", get_client_host(cptr));
2214 		find_bounce(cptr, -1, -1);
2215 		return exit_client(cptr, cptr, &me, "Server only port");
2216 	}
2217 	/* Reject new USER */
2218 	if (IsServer(sptr) || IsService(sptr) || sptr->user)
2219 	    {
2220 		sendto_one(sptr, replies[ERR_ALREADYREGISTRED], ME, BadTo(parv[0]));
2221 		return 1;
2222    	    }
2223 	if ((username = (char *)index(parv[1],'@')))
2224 		*username = '\0';
2225 
2226 	/* Copy parameters into better documenting variables */
2227 
2228 	username = parv[1];
2229 	umodes   = parv[2];
2230 	server   = parv[3];
2231 	realname = parv[4];
2232 
2233 #ifdef INET6
2234 	inetntop(AF_INET6, (char *)&sptr->ip, ipbuf, sizeof(ipbuf));
2235 #else
2236 	strcpy(ipbuf, (char *)inetntoa((char *)&sptr->ip));
2237 #endif
2238 	user = make_user(sptr, strlen(ipbuf));
2239 	strcpy(user->sip, ipbuf);
2240 
2241 	user->servp = me.serv;
2242 	me.serv->refcnt++;
2243 #ifdef	DEFAULT_INVISIBLE
2244 	SetInvisible(sptr);
2245 #endif
2246 	/* parse desired user modes sent in USER */
2247 	/* rfc behaviour - bits */
2248 	if (isdigit(*umodes))
2249 	{
2250 		for (s = umodes+1; *s; s++)
2251 			if (!isdigit(*s))
2252 				break;
2253 		if (*s == '\0')
2254 			/* allows only umodes specified in UFLAGS - see above */
2255 			sptr->user->flags |= (UFLAGS & atoi(umodes));
2256 	}
2257 	else	/* new behaviour */
2258 	{
2259 		/* 0 here is intentional. User MUST specify + or -,
2260 		 * as we don't want to restrict (broken) clients which send
2261 		 * their hostname in mode field (and happen to have r there).
2262 		 * - jv
2263 		 */
2264 		what = 0;
2265 		for (s = umodes; *s; s++)
2266 		{
2267 			switch (*s)
2268 			{
2269 				case '+':
2270 					what = MODE_ADD;
2271 					continue;
2272 				case '-':
2273 					what = MODE_DEL;
2274 					continue;
2275 				default:
2276 					break;
2277 			}
2278 			/* If mode does not start with - or +, don't bother. */
2279 			if (what == 0)
2280 				break;
2281 			for (i = 0; umodes_arr[i].umode != '\0'; i++)
2282 			{
2283 				if (*s == umodes_arr[i].umode)
2284 				{
2285 					if (what == MODE_ADD)
2286 					{
2287 						sptr->user->flags |=
2288 							umodes_arr[i].flag;
2289 					}
2290 					if (what == MODE_DEL)
2291 					{
2292 						sptr->user->flags &=
2293 							~(umodes_arr[i].flag);
2294 					}
2295 				}
2296 			}
2297 		}
2298 	}
2299 	user->server = find_server_string(me.serv->snum);
2300 
2301 	reorder_client_in_list(sptr);
2302 	if (sptr->info != DefInfo)
2303 		MyFree(sptr->info);
2304 	if (strlen(realname) > REALLEN)
2305 		realname[REALLEN] = '\0';
2306 	sptr->info = mystrdup(realname);
2307 #ifdef XLINE
2308 	sptr->user2 = mystrdup(umodes);
2309 	sptr->user3 = mystrdup(server);
2310 #endif
2311 	if (sptr->name[0]) /* NICK already received, now we have USER... */
2312 	{
2313 		return register_user(cptr, sptr, sptr->name, username);
2314 	}
2315 	else
2316 	{
2317 		strncpyzt(sptr->user->username, username, USERLEN+1);
2318 	}
2319 	return 2;
2320 }
2321 
2322 /* Fear www proxy abusers... aliased to QUIT, muhaha --B. */
m_post(aClient * cptr,aClient * sptr,int parc,char * parv[])2323 int	m_post(aClient *cptr, aClient *sptr, int parc, char *parv[])
2324 {
2325 	sendto_flag(SCH_LOCAL, "Denied http-post connection from %s.",
2326 		cptr->sockhost);
2327 	return m_quit(cptr, sptr, parc, parv);
2328 }
2329 
2330 /*
2331 ** m_quit
2332 **	parv[0] = sender prefix
2333 **	parv[1] = comment
2334 */
m_quit(aClient * cptr,aClient * sptr,int parc,char * parv[])2335 int	m_quit(aClient *cptr, aClient *sptr, int parc, char *parv[])
2336 {
2337 	static	char comment[TOPICLEN+1];
2338 
2339 	if (IsServer(sptr))
2340 		return 0;
2341 
2342 	if (MyConnect(sptr))
2343 	{
2344 		(void) snprintf(comment, TOPICLEN, "\"%s",
2345 			(parc > 1 && parv[1]) ? parv[1] : "");
2346 		(void) strcat(comment, "\"");
2347 	}
2348 	else
2349 	{
2350 		(void) snprintf(comment, TOPICLEN + 1, "%s",
2351 			(parc > 1 && parv[1]) ? parv[1] : "");
2352 	}
2353 	return exit_client(cptr, sptr, sptr, comment);
2354 }
2355 
2356 /*
2357 ** m_kill
2358 **	parv[0] = sender prefix
2359 **	parv[1] = kill victim
2360 **	parv[2] = kill path
2361 */
m_kill(aClient * cptr,aClient * sptr,int parc,char * parv[])2362 int	m_kill(aClient *cptr, aClient *sptr, int parc, char *parv[])
2363 {
2364 	aClient *acptr = NULL;
2365 	char	*inpath = cptr->name;
2366 	char	*user, *path, *killer;
2367 	int	chasing = 0;
2368 
2369 	if (!is_allowed(sptr, ACL_KILL))
2370 		return m_nopriv(cptr, sptr, parc, parv);
2371 
2372 	user = parv[1];
2373 	path = parv[2];
2374 
2375 	if (IsAnOper(cptr) && strlen(path) > (size_t) TOPICLEN)
2376 		path[TOPICLEN] = '\0';
2377 
2378 	/* first, _if coming from a server_ check for kill on UID */
2379 	if (IsServer(cptr))
2380 		acptr = find_uid(user, NULL);
2381 	if (acptr == NULL)
2382 		acptr = find_client(user, NULL);
2383 	if (acptr == NULL)
2384 	    {
2385 		/*
2386 		** If the user has recently changed nick, we automaticly
2387 		** rewrite the KILL for this new nickname--this keeps
2388 		** servers in synch when nick change and kill collide
2389 		*/
2390 		if (!(acptr = get_history(user, (long)KILLCHASETIMELIMIT)))
2391 		    {
2392 			if (!IsServer(sptr))
2393 				sendto_one(sptr, replies[ERR_NOSUCHNICK],
2394 					   ME, BadTo(parv[0]), user);
2395 			return 1;
2396 		    }
2397 		sendto_one(sptr,":%s NOTICE %s :KILL changed from %s to %s",
2398 			   ME, parv[0], user, acptr->name);
2399 		chasing = 1;
2400 	    }
2401 	if (!MyConnect(acptr) && !is_allowed(cptr, ACL_KILLREMOTE))
2402 	    {
2403 		return m_nopriv(cptr, sptr, parc, parv);
2404 	    }
2405 	if (IsServer(acptr) || IsMe(acptr))
2406 	    {
2407 		sendto_flag(SCH_ERROR, "%s tried to KILL server %s: %s %s %s",
2408 			    sptr->name, acptr->name, parv[0], parv[1], parv[2]);
2409 		sendto_one(sptr, replies[ERR_CANTKILLSERVER], ME, BadTo(parv[0]),
2410 			   acptr->name);
2411 		return 1;
2412 	    }
2413 	if (!IsServer(cptr))
2414 	    {
2415 		/*
2416 		** The kill originates from this server, initialize path.
2417 		** (In which case the 'path' may contain user suplied
2418 		** explanation ...or some nasty comment, sigh... >;-)
2419 		**
2420 		**	...!operhost!oper
2421 		**	...!operhost!oper (comment)
2422 		*/
2423 #ifdef UNIXPORT
2424 		if (IsUnixSocket(cptr)) /* Don't use get_client_name syntax */
2425 			inpath = ME;
2426 		else
2427 #endif
2428 			inpath = cptr->sockhost;
2429 		sprintf(buf, "%s%s (%s)",
2430 			cptr->name, IsOper(sptr) ? "" : "(L)", path);
2431 		path = buf;
2432 	    }
2433 	/*
2434 	** Notify all *local* opers about the KILL (this includes the one
2435 	** originating the kill, if from this server--the special numeric
2436 	** reply message is not generated anymore).
2437 	**
2438 	** Note: "acptr->name" is used instead of "user" because we may
2439 	**	 have changed the target because of the nickname change.
2440 	*/
2441 	if (IsService(acptr))
2442 	{
2443 		sendto_flag(SCH_KILL, "Received KILL message for %s[%s]. "
2444 			"From %s Path: %s!%s", acptr->name,
2445 			isdigit(acptr->service->servp->sid[0]) ?
2446 			acptr->service->servp->sid : "2.10", parv[0], inpath,
2447 			path);
2448 	}
2449 	else
2450 	{
2451 		sendto_flag(SCH_KILL, "Received KILL message for "
2452 			"%s!%s@%s[%s/%s]. From %s Path: %s!%s",
2453 			acptr->name, acptr->user->username, acptr->user->host,
2454 			acptr->user->servp->bcptr->name,
2455 			isdigit(acptr->user->servp->sid[0]) ?
2456 			acptr->user->servp->sid : "2.10", parv[0], inpath,
2457 			path);
2458 	}
2459 #if defined(USE_SYSLOG) && defined(SYSLOG_KILL)
2460 	if (IsOper(sptr))
2461 	{
2462 		if (IsService(acptr))
2463 		{
2464 			syslog(LOG_DEBUG, "KILL From %s For %s[%s] Path %s!%s",
2465 				parv[0], acptr->name,
2466 				isdigit(acptr->service->servp->sid[0]) ?
2467 				acptr->service->servp->sid : "2.10",
2468 				inpath, path);
2469 		}
2470 		else
2471 		{
2472 			syslog(LOG_DEBUG, "KILL From %s For %s!%s@%s[%s/%s] "
2473 				"Path %s!%s", parv[0], acptr->name,
2474 				acptr->user->username, acptr->user->host,
2475 				acptr->user->servp->bcptr->name,
2476 				isdigit(acptr->user->servp->sid[0]) ?
2477 				acptr->user->servp->sid : "2.10",
2478 				inpath, path);
2479 		}
2480 	}
2481 #endif
2482 	/*
2483 	** And pass on the message to other servers. Note, that if KILL
2484 	** was changed, the message has to be sent to all links, also
2485 	** back.
2486 	** Suicide kills are NOT passed on --SRB
2487 	*/
2488 	if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr))
2489 	    {
2490 		if (acptr->user)
2491 		    {
2492 			sendto_serv_v(cptr, SV_UID, ":%s KILL %s :%s!%s",
2493 				      parv[0], acptr->user->uid, inpath, path);
2494 		    }
2495 		else
2496 			sendto_serv_butone(cptr, ":%s KILL %s :%s!%s",
2497 					   parv[0], acptr->name, inpath, path);
2498 		if (chasing && !IsClient(cptr))
2499 			sendto_one(cptr, ":%s KILL %s :%s!%s",
2500 				   ME, acptr->name, inpath, path);
2501 		acptr->flags |= FLAGS_KILLED;
2502 	    }
2503 #ifdef	USE_SERVICES
2504 	check_services_butone(SERVICE_WANT_KILL, NULL, sptr,
2505 			      ":%s KILL %s :%s!%s", parv[0], acptr->name,
2506 			      inpath, path);
2507 #endif
2508 
2509 	/*
2510 	** Tell the victim she/he has been zapped, but *only* if
2511 	** the victim is on current server--no sense in sending the
2512 	** notification chasing the above kill, it won't get far
2513 	** anyway (as this user don't exist there any more either)
2514 	*/
2515 	if (MyConnect(acptr))
2516 		sendto_prefix_one(acptr, sptr,":%s KILL %s :%s!%s",
2517 				  parv[0], acptr->name, inpath, path);
2518 	/*
2519 	** Set FLAGS_KILLED. This prevents exit_one_client from sending
2520 	** the unnecessary QUIT for this. (This flag should never be
2521 	** set in any other place)
2522 	*/
2523 	if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr))
2524 	    {
2525 		acptr->exitc = EXITC_KILL;
2526 		sprintf(buf2, "Local Kill by %s (%s)", sptr->name, parv[2]);
2527 	    }
2528 	else
2529 	    {
2530 		if ((killer = index(path, ' ')))
2531 		    {
2532 			while (killer > path && *killer != '!')
2533 				killer--;
2534 			if (killer != path)
2535 				killer++;
2536 		    }
2537 		else
2538 			killer = path;
2539 		sprintf(buf2, "Killed (%s)", killer);
2540 	    }
2541 	return exit_client(cptr, acptr, sptr, buf2);
2542 }
2543 
2544 /***********************************************************************
2545  * m_away() - Added 14 Dec 1988 by jto.
2546  *	    Not currently really working, I don't like this
2547  *	    call at all...
2548  *
2549  *	    ...trying to make it work. I don't like it either,
2550  *	      but perhaps it's worth the load it causes to net.
2551  *	      This requires flooding of the whole net like NICK,
2552  *	      USER, MODE, etc messages...  --msa
2553  ***********************************************************************/
2554 
2555 /*
2556 ** m_away
2557 **	parv[0] = sender prefix
2558 **	parv[1] = away message
2559 */
m_away(aClient * cptr,aClient * sptr,int parc,char * parv[])2560 int	m_away(aClient *cptr, aClient *sptr, int parc, char *parv[])
2561 {
2562 	Reg	char	*away, *awy2 = parv[1];
2563 	int	len;
2564 
2565 	away = sptr->user->away;
2566 
2567 	if (parc < 2 || !*awy2)	/* Marking as not away */
2568 	    {
2569 		if (away)
2570 		    {
2571 			istat.is_away--;
2572 			istat.is_awaymem -= (strlen(away) + 1);
2573 			MyFree(away);
2574 			sptr->user->away = NULL;
2575 		    }
2576 		if (sptr->user->flags & FLAGS_AWAY)
2577 			sendto_serv_butone(cptr, ":%s MODE %s :-a",
2578 				sptr->user->uid, parv[0]);
2579 		/* sendto_serv_butone(cptr, ":%s AWAY", parv[0]); */
2580 		if (MyConnect(sptr))
2581 			sendto_one(sptr, replies[RPL_UNAWAY], ME, BadTo(parv[0]));
2582 #ifdef	USE_SERVICES
2583 		check_services_butone(SERVICE_WANT_AWAY, NULL, sptr,
2584 				      ":%s AWAY", parv[0]);
2585 #endif
2586 		sptr->user->flags &= ~FLAGS_AWAY;
2587 		return 1;
2588 	    }
2589 
2590 	/* Marking as away */
2591 
2592 	if ((len = strlen(awy2)) > (size_t) TOPICLEN)
2593 	    {
2594 		len = TOPICLEN;
2595 		awy2[TOPICLEN] = '\0';
2596 	    }
2597 	len++;
2598 	/* sendto_serv_butone(cptr, ":%s AWAY :%s", parv[0], awy2); */
2599 #ifdef	USE_SERVICES
2600 	check_services_butone(SERVICE_WANT_AWAY, NULL, sptr,
2601 			      ":%s AWAY :%s", parv[0], awy2);
2602 #endif
2603 
2604 	if (away)
2605 	    {
2606 		istat.is_awaymem -= (strlen(away) + 1);
2607 		away = (char *)MyRealloc(away, len);
2608 		istat.is_awaymem += len;
2609 	    }
2610 	else
2611 	    {
2612 		istat.is_away++;
2613 		istat.is_awaymem += len;
2614 		away = (char *)MyMalloc(len);
2615 		sendto_serv_butone(cptr, ":%s MODE %s :+a",
2616 			sptr->user->uid, parv[0]);
2617 	    }
2618 
2619 	sptr->user->flags |= FLAGS_AWAY;
2620 	if (MyConnect(sptr))
2621 	    {
2622 		sptr->user->away = away;
2623 		(void)strcpy(away, awy2);
2624 		sendto_one(sptr, replies[RPL_NOWAWAY], ME, BadTo(parv[0]));
2625 	    }
2626 	return 2;
2627 }
2628 
2629 /*
2630 ** m_ping
2631 **	parv[0] = sender prefix
2632 **	parv[1] = origin
2633 **	parv[2] = destination
2634 */
m_ping(aClient * cptr,aClient * sptr,int parc,char * parv[])2635 int	m_ping(aClient *cptr, aClient *sptr, int parc, char *parv[])
2636 {
2637 	aClient *acptr;
2638 	char	*origin, *destination;
2639 
2640 	origin = parv[1];
2641 	destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */
2642 
2643 	acptr = find_client(origin, NULL);
2644 	if (!acptr)
2645 		acptr = find_server(origin, NULL);
2646 	if (!acptr || acptr != sptr)
2647 		origin = cptr->name;
2648 	if (!BadPtr(destination) && match(destination, ME) != 0)
2649 	{
2650 		if ((acptr = find_server(destination, NULL)))
2651 			sendto_one(acptr, ":%s PING %s :%s", parv[0],
2652 				origin, destination);
2653 	    	else
2654 		{
2655 			sendto_one(sptr, replies[ERR_NOSUCHSERVER],
2656 				ME, BadTo(parv[0]), destination);
2657 			return 1;
2658 		}
2659 	}
2660 	else
2661 		sendto_one(sptr, ":%s PONG %s :%s", ME,
2662 			(destination) ? destination : ME, parv[1]);
2663 	return 1;
2664 }
2665 
2666 /*
2667 ** m_pong
2668 **	parv[0] = sender prefix
2669 **	parv[1] = origin
2670 **	parv[2] = destination
2671 */
m_pong(aClient * cptr,aClient * sptr,int parc,char * parv[])2672 int	m_pong(aClient *cptr, aClient *sptr, int parc, char *parv[])
2673 {
2674 	aClient *acptr;
2675 	char	*origin, *destination;
2676 
2677 	if (parc < 2 || *parv[1] == '\0')
2678 	    {
2679 		sendto_one(sptr, replies[ERR_NOORIGIN], ME, BadTo(parv[0]));
2680 		return 1;
2681 	    }
2682 
2683 	origin = parv[1];
2684 	destination = parv[2];
2685 
2686 	sptr->flags &= ~FLAGS_PINGSENT;
2687 	if (destination)
2688 	{
2689 		acptr = find_target(destination, cptr);
2690 	}
2691 	else
2692 	{
2693 		acptr = &me;
2694 	}
2695 	if (!acptr)
2696 	{
2697 		sendto_one(sptr, replies[ERR_NOSUCHSERVER], ME, BadTo(parv[0]),
2698 			   destination);
2699 		return 2;
2700 	}
2701 	if (!IsMe(acptr))
2702 	{
2703 		if (!(MyClient(sptr) && mycmp(origin, sptr->name)))
2704 			sendto_one(acptr,":%s PONG %s %s",
2705 					   parv[0], origin, destination);
2706 		return 2;
2707 	}
2708 	return 1;
2709 }
2710 
2711 
2712 /*
2713 ** m_oper
2714 **	parv[0] = sender prefix
2715 **	parv[1] = oper name
2716 **	parv[2] = oper password
2717 */
m_oper(aClient * cptr,aClient * sptr,int parc,char * parv[])2718 int	m_oper(aClient *cptr, aClient *sptr, int parc, char *parv[])
2719 {
2720 	aConfItem *aconf;
2721 	char	*name, *password, *encr;
2722 	char	*logstring = NULL;
2723 
2724 	name = parv[1];
2725 	password = parv[2];
2726 
2727 	if (IsAnOper(sptr))
2728 	{
2729 		if (MyConnect(sptr))
2730 			sendto_one(sptr, replies[RPL_YOUREOPER], ME, BadTo(parv[0]));
2731 		return 1;
2732 	}
2733 	if (!(aconf = find_Oline(name, sptr)))
2734 	{
2735 		sendto_one(sptr, replies[ERR_NOOPERHOST], ME, BadTo(parv[0]));
2736 		return 1;
2737 	}
2738 	if (aconf->clients >= MaxLinks(Class(aconf)))
2739 	{
2740 		sendto_one(sptr, ":%s %d %s :Too many opers", ME, ERR_NOOPERHOST, BadTo(parv[0]));
2741 		return 1;
2742 	}
2743 #ifdef CRYPT_OPER_PASSWORD
2744 	/* pass whole aconf->passwd as salt, let crypt() deal with it */
2745 
2746 	if (password && aconf->passwd)
2747 	    {
2748 		extern	char *crypt();
2749 
2750 		encr = crypt(password, aconf->passwd);
2751 		if (encr == NULL)
2752 		    {
2753 			sendto_flag(SCH_ERROR, "crypt() returned NULL");
2754 			sendto_one(sptr,replies[ERR_PASSWDMISMATCH], ME,BadTo(parv[0]));
2755 			return 3;
2756 		    }
2757 	    }
2758 	else
2759 		encr = "";
2760 #else
2761 	encr = password;
2762 #endif  /* CRYPT_OPER_PASSWORD */
2763 
2764 	if ((aconf->status & CONF_OPS) &&
2765 	    StrEq(encr, aconf->passwd) && !attach_conf(sptr, aconf))
2766 	{
2767 		int old = (sptr->user->flags & ALL_UMODES);
2768 		char *s;
2769 
2770 		s = index(aconf->host, '@');
2771 		*s++ = '\0';
2772 #ifndef	NO_OPER_REMOTE
2773 		if (aconf->flags & ACL_LOCOP)
2774 #else
2775 		if ((match(s,me.sockhost) && !IsLocal(sptr)) ||
2776 		    aconf->flags & ACL_LOCOP)
2777 #endif
2778 			SetLocOp(sptr);
2779 		else
2780 			SetOper(sptr);
2781 		*--s =  '@';
2782 		sendto_flag(SCH_NOTICE, "%s (%s@%s) is now operator (%c)",
2783 			    parv[0], sptr->user->username, sptr->user->host,
2784 			   IsOper(sptr) ? 'o' : 'O');
2785 		send_umode_out(cptr, sptr, old);
2786  		sendto_one(sptr, replies[RPL_YOUREOPER], ME, BadTo(parv[0]));
2787 #ifdef	USE_SERVICES
2788 		check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
2789 				      sptr, ":%s MODE %s :+%c", parv[0],
2790 				      parv[0], IsOper(sptr) ? 'o' : 'O');
2791 #endif
2792 		if (IsAnOper(sptr))
2793 		{
2794 			istat.is_oper++;
2795 			sptr->user->servp->usercnt[2]++;
2796 		}
2797 		logstring = "";
2798 	}
2799 	else /* Wrong password or attach_conf() failed */
2800 	{
2801 		(void)detach_conf(sptr, aconf);
2802 		if (!StrEq(encr, aconf->passwd))
2803 			sendto_one(sptr,replies[ERR_PASSWDMISMATCH], ME, BadTo(parv[0]));
2804 		else
2805 			sendto_one(sptr,":%s %d %s :Too many connections",
2806 				ME, ERR_PASSWDMISMATCH, BadTo(parv[0]));
2807 #ifdef FAILED_OPERLOG
2808 		sendto_flag(SCH_NOTICE, "FAILED OPER attempt by %s!%s@%s",
2809 			parv[0], sptr->user->username, sptr->user->host);
2810 		logstring = "FAILED ";
2811 #endif
2812 	}
2813 
2814 	if (logstring)
2815 	{
2816 #if defined(USE_SYSLOG) && defined(SYSLOG_OPER)
2817 		syslog(LOG_INFO, "%sOPER (%s) by (%s!%s@%s) [%s@%s]",
2818 			logstring,
2819 			name, parv[0], sptr->user->username, sptr->user->host,
2820 			sptr->auth,
2821 #ifdef UNIXPORT
2822 			IsUnixSocket(sptr) ? sptr->sockhost :
2823 #endif
2824 #ifdef INET6
2825                        inet_ntop(AF_INET6, (char *)&sptr->ip, ipv6string,
2826 			       sizeof(ipv6string))
2827 #else
2828                        inetntoa((char *)&sptr->ip)
2829 #endif
2830 		       );
2831 #endif /* defined(USE_SYSLOG) && defined(SYSLOG_OPER) */
2832 
2833 #ifdef FNAME_OPERLOG
2834 	      {
2835 		int     logfile;
2836 
2837 		/*
2838 		 * This conditional makes the logfile active only after
2839 		 * it's been created - thus logging can be turned off by
2840 		 * removing the file.
2841 		 *
2842 		 * stop NFS hangs...most systems should be able to open a
2843 		 * file in 3 seconds. -avalon (curtesy of wumpus)
2844 		 */
2845 		(void)alarm(3);
2846 		if (IsPerson(sptr) &&
2847 		    (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND
2848 #ifdef LOGFILES_ALWAYS_CREATE
2849 					|O_CREAT, S_IRUSR|S_IWUSR
2850 #endif
2851 			)) != -1)
2852 		{
2853 			(void)alarm(0);
2854 		  	sprintf(buf, "%s %sOPER (%s) by (%s!%s@%s)"
2855 				     " [%s@%s]\n",
2856 			 	myctime(timeofday),
2857 				logstring,
2858 				name, parv[0],
2859 				sptr->user->username, sptr->user->host,
2860 				sptr->auth,
2861 #ifdef UNIXPORT
2862 				IsUnixSocket(sptr) ? sptr->sockhost :
2863 #endif
2864 #ifdef INET6
2865 				inetntop(AF_INET6, (char *)&sptr->ip,
2866 					ipv6string, sizeof(ipv6string))
2867 #else
2868 				inetntoa((char *)&sptr->ip)
2869 #endif
2870 				);
2871 			(void)alarm(3);
2872 		  	(void)write(logfile, buf, strlen(buf));
2873 		  	(void)alarm(0);
2874 		  	(void)close(logfile);
2875 		}
2876 		(void)alarm(0);
2877 		/* Modification by pjg */
2878 	      }
2879 #endif /* FNAME_OPERLOG */
2880 
2881 	} /* logstring != NULL */
2882 
2883 	return 3;
2884     }
2885 
2886 /***************************************************************************
2887  * m_pass() - Added Sat, 4 March 1989
2888  ***************************************************************************/
2889 
2890 /*
2891 ** m_pass
2892 **	parv[0] = sender prefix
2893 **	parv[1] = password
2894 **	parv[2] = protocol & server versions (server only)
2895 **	parv[3] = server id & options (server only)
2896 **	parv[4] = (optional) link options (server only)
2897 */
m_pass(aClient * cptr,aClient * sptr,int parc,char * parv[])2898 int	m_pass(aClient *cptr, aClient *sptr, int parc, char *parv[])
2899 {
2900 	char *password = parv[1];
2901 
2902 	strncpyzt(cptr->passwd, password, sizeof(cptr->passwd));
2903 	if (cptr->user || cptr->service)
2904 	{
2905 		/* If we have one of these structures allocated, it means
2906 		** that PASS was issued after USER or SERVICE. No need to
2907 		** copy PASS parameters to info field, then. */
2908 		return 1;
2909 	}
2910 	/* Temporarily store PASS pwd *parameters* into info field.
2911 	** This will be used as version in m_server() and cleared
2912 	** in m_user(). */
2913 	if (parc > 2 && parv[2])
2914 	    {
2915 		strncpyzt(buf, parv[2], 15);
2916 		if (parc > 3 && parv[3])
2917 		    {
2918 			strcat(buf, " ");
2919 			strncat(buf, parv[3], 100);
2920 			if (parc > 4 && parv[4])
2921 			    {
2922 				strcat(buf, " ");
2923 				strncat(buf, parv[4], 5);
2924 			    }
2925 		    }
2926 		if (cptr->info != DefInfo)
2927 			MyFree(cptr->info);
2928 		cptr->info = mystrdup(buf);
2929 	    }
2930 	return 1;
2931 }
2932 
2933 /*
2934  * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce
2935  * the need for complicated requests like WHOIS. It returns user/host
2936  * information only (no spurious AWAY labels or channels).
2937  */
m_userhost(aClient * cptr,aClient * sptr,int parc,char * parv[])2938 int	m_userhost(aClient *cptr, aClient *sptr, int parc, char *parv[])
2939 {
2940 	char	*p = NULL;
2941 	aClient	*acptr;
2942 	Reg	char	*s;
2943 	Reg	int	i, len;
2944 	int	idx = 1;
2945 
2946 	(void)sprintf(buf, replies[RPL_USERHOST], ME, BadTo(parv[0]));
2947 	len = strlen(buf);
2948 	*buf2 = '\0';
2949 
2950 	for (i = 5, s = strtoken(&p, parv[idx], " "); i && s; i--)
2951 	     {
2952 		if ((acptr = find_person(s, NULL)))
2953 		    {
2954 			if (*buf2)
2955 				(void)strcat(buf, " ");
2956 			sprintf(buf2, "%s%s=%c%s@%s", acptr->name,
2957 				IsAnOper(acptr) ? "*" : "",
2958 				(acptr->user->flags & FLAGS_AWAY) ? '-' : '+',
2959 				acptr->user->username, acptr->user->host);
2960 			(void)strncat(buf, buf2, sizeof(buf) - len);
2961 			len += strlen(buf2);
2962 			if (len > BUFSIZE - (NICKLEN + 5 + HOSTLEN + USERLEN))
2963 			    {
2964 				sendto_one(sptr, "%s", buf);
2965 				(void)sprintf(buf, replies[RPL_USERHOST],
2966 					     ME, BadTo(parv[0]));
2967 				len = strlen(buf);
2968 				*buf2 = '\0';
2969 			    }
2970 		    }
2971 		s = strtoken(&p, (char *)NULL, " ");
2972 		if (!s && parv[++idx])
2973 		    {
2974 			p = NULL;
2975 			s = strtoken(&p, parv[idx], " ");
2976 		    }
2977 	    }
2978 	sendto_one(sptr, "%s", buf);
2979 	return 1;
2980 }
2981 
2982 /*
2983  * m_ison added by Darren Reed 13/8/91 to act as an efficent user indicator
2984  * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in
2985  * clients. Designed to reduce number of whois requests. Can process
2986  * nicknames in batches as long as the maximum buffer length.
2987  *
2988  * format:
2989  * ISON :nicklist
2990  */
2991 
m_ison(aClient * cptr,aClient * sptr,int parc,char * parv[])2992 int	m_ison(aClient *cptr, aClient *sptr, int parc, char *parv[])
2993 {
2994 	Reg	aClient *acptr;
2995 	Reg	char	*s, **pav = parv;
2996 	Reg	int	len = 0, i;
2997 	char	*p = NULL;
2998 
2999 	(void)sprintf(buf, replies[RPL_ISON], ME, BadTo(*parv));
3000 	len = strlen(buf);
3001 
3002 	for (s = strtoken(&p, *++pav, " "); s; s = strtoken(&p, NULL, " "))
3003 		if ((acptr = find_person(s, NULL)))
3004 		    {
3005 			i = strlen(acptr->name);
3006 			if (len + i > sizeof(buf) - 4)
3007 			{
3008 				/* leave room for " \r\n\0" */
3009 				break;
3010 			}
3011 			(void) strcpy(buf + len, acptr->name);
3012 			len += i;
3013 			(void) strcpy(buf + len++, " ");
3014 		    }
3015 	sendto_one(sptr, "%s", buf);
3016 	return 1;
3017 }
3018 
3019 /*
3020  * m_umode() added 15/10/91 By Darren Reed.
3021  * parv[0] - sender (can be NULL, see below..)
3022  * parv[1] - username to change mode for
3023  * parv[2] - modes to change
3024  */
m_umode(aClient * cptr,aClient * sptr,int parc,char * parv[])3025 int	m_umode(aClient *cptr, aClient *sptr, int parc, char *parv[])
3026 {
3027 	Reg	int	flag;
3028 	Reg	int	*s;
3029 	Reg	char	**p, *m;
3030 	aClient	*acptr = NULL;
3031 	int	what, setflags, penalty = 0;
3032 
3033 	what = MODE_ADD;
3034 
3035 	if (cptr && !(acptr = find_person(parv[1], NULL)))
3036 	    {
3037 		if (MyConnect(sptr))
3038 			sendto_one(sptr, replies[ERR_NOSUCHCHANNEL], ME, BadTo(parv[0]),
3039 				   parv[1]);
3040 		return 1;
3041 	    }
3042 	if (cptr == NULL)
3043 		/* internal call which has to be handled in a special way */
3044 		acptr = sptr;
3045 
3046 	if ((cptr != NULL) &&
3047 	    ((IsServer(sptr) || sptr != acptr || acptr->from != sptr->from)))
3048 	    {
3049 		if (IsServer(cptr))
3050 			sendto_ops_butone(NULL, ME,
3051 				  "MODE for User %s From %s!%s", parv[1],
3052 				  get_client_name(cptr, FALSE), sptr->name);
3053 		else
3054 			sendto_one(sptr, replies[ERR_USERSDONTMATCH], ME, BadTo(parv[0]));
3055 			return 1;
3056 	    }
3057 
3058 	if (parc < 3)
3059 	    {
3060 		m = buf;
3061 		*m++ = '+';
3062 		for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4);
3063 		     s += 2)
3064 			if (sptr->user->flags & flag)
3065 				*m++ = (char)(*(s+1));
3066 		*m = '\0';
3067 		sendto_one(sptr, replies[RPL_UMODEIS], ME, BadTo(parv[0]), buf);
3068 		return 1;
3069 	    }
3070 
3071 	/* find flags already set for user */
3072 	setflags = 0;
3073 	for (s = user_modes; (flag = *s); s += 2)
3074 		if (sptr->user->flags & flag)
3075 			setflags |= flag;
3076 
3077 	/*
3078 	 * parse mode change string(s)
3079 	 */
3080 	for (p = &parv[2]; p && *p; p++ )
3081 		for (m = *p; *m; m++)
3082 			switch(*m)
3083 			{
3084 			case '+' :
3085 				what = MODE_ADD;
3086 				break;
3087 			case '-' :
3088 				what = MODE_DEL;
3089 				break;
3090 			/* we may not get these,
3091 			 * but they shouldnt be in default
3092 			 */
3093 			case ' ' :
3094 			case '\n' :
3095 			case '\r' :
3096 			case '\t' :
3097 				break;
3098 			case 'a' : /* fall through case */
3099 				/* users should use the AWAY message */
3100 				if (cptr && !IsServer(cptr))
3101 					break;
3102 				if (what == MODE_DEL && sptr->user->away)
3103 				    {
3104 					istat.is_away--;
3105 					istat.is_awaymem -= (strlen(sptr->user->away) + 1);
3106 					MyFree(sptr->user->away);
3107 					sptr->user->away = NULL;
3108 #ifdef  USE_SERVICES
3109 				check_services_butone(SERVICE_WANT_AWAY,
3110 						      sptr->user->servp, sptr,
3111 						      ":%s AWAY", parv[0]);
3112 #endif
3113 				    }
3114 #ifdef  USE_SERVICES
3115 				if (what == MODE_ADD)
3116 				check_services_butone(SERVICE_WANT_AWAY,
3117 						      sptr->user->servp, sptr,
3118 						      ":%s AWAY :", parv[0]);
3119 #endif
3120 			default :
3121 				for (s = user_modes; (flag = *s); s += 2)
3122 					if (*m == (char)(*(s+1)))
3123 				    {
3124 					if (what == MODE_ADD)
3125 						sptr->user->flags |= flag;
3126 					else
3127 						sptr->user->flags &= ~flag;
3128 					penalty += 1;
3129 					break;
3130 				    }
3131 				if (flag == 0 && MyConnect(sptr))
3132 					sendto_one(sptr, replies[ERR_UMODEUNKNOWNFLAG],
3133 						ME, BadTo(parv[0]), *m);
3134 				break;
3135 			}
3136 	if (cptr)
3137 	    {
3138 		/* stop users making themselves operators too easily */
3139 		if (!(setflags & FLAGS_OPER) && IsOper(sptr) &&
3140 		    !IsServer(cptr))
3141 			ClearOper(sptr);
3142 		if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr))
3143 			ClearLocOp(sptr);
3144 		/* but once they are, set their status */
3145 		SetClient(sptr);
3146 		if ((setflags & FLAGS_RESTRICT) &&
3147 		    !IsRestricted(sptr))
3148 		    {
3149 			sendto_one(sptr, replies[ERR_RESTRICTED], ME, BadTo(parv[0]));
3150 			SetRestricted(sptr);
3151 			/* Can't return; here since it could mess counters */
3152 		    }
3153 		if ((setflags & (FLAGS_OPER|FLAGS_LOCOP)) && !IsAnOper(sptr) &&
3154 		    MyConnect(sptr))
3155 			det_confs_butmask(sptr, CONF_CLIENT);
3156 
3157 		/*
3158 		 * compare new flags with old flags and send string which
3159 		 * will cause servers to update correctly.
3160 		 */
3161 		if (!IsInvisible(sptr) && (setflags & FLAGS_INVISIBLE))
3162 		    {
3163 			istat.is_user[1]--;
3164 			istat.is_user[0]++;
3165 			sptr->user->servp->usercnt[1]--;
3166 			sptr->user->servp->usercnt[0]++;
3167 		    }
3168 		if (IsInvisible(sptr) && !(setflags & FLAGS_INVISIBLE))
3169 		    {
3170 			istat.is_user[1]++;
3171 			istat.is_user[0]--;
3172 			sptr->user->servp->usercnt[1]++;
3173 			sptr->user->servp->usercnt[0]--;
3174 		    }
3175 		send_umode_out(cptr, sptr, setflags);
3176 	    }
3177 
3178 	/* update counters */
3179 	if (IsOper(sptr) && !(setflags & FLAGS_OPER))
3180 	    {
3181 		istat.is_oper++;
3182 		sptr->user->servp->usercnt[2]++;
3183 #ifdef	USE_SERVICES
3184 		check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
3185 				      sptr, ":%s MODE %s :+o", parv[0],
3186 				      parv[0]);
3187 #endif
3188 	    }
3189 	else if (!IsOper(sptr) && (setflags & FLAGS_OPER))
3190 	    {
3191 		istat.is_oper--;
3192 		sptr->user->servp->usercnt[2]--;
3193 #ifdef	USE_SERVICES
3194 		check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
3195 				      sptr, ":%s MODE %s :-o", parv[0],
3196 				      parv[0]);
3197 #endif
3198 	    }
3199 	else if (MyConnect(sptr) && !IsLocOp(sptr) && (setflags & FLAGS_LOCOP))
3200 	    {
3201 		istat.is_oper--;
3202 		sptr->user->servp->usercnt[2]--;
3203 #ifdef USE_SERVICES
3204 		check_services_butone(SERVICE_WANT_OPER, sptr->user->servp,
3205 				      sptr, ":%s MODE %s :-O", parv[0],
3206 				      parv[0]);
3207 #endif
3208 	    }
3209 
3210 	return penalty;
3211 }
3212 
3213 /*
3214  * send the MODE string for user (user) to connection cptr
3215  * -avalon
3216  */
send_umode(aClient * cptr,aClient * sptr,int old,int sendmask,char * umode_buf)3217 void	send_umode(aClient *cptr, aClient *sptr, int old, int sendmask,
3218 		char *umode_buf)
3219 {
3220 	Reg	int	*s, flag;
3221 	Reg	char	*m;
3222 	int	what = MODE_NULL;
3223 
3224 	if (!sptr->user)
3225 		return;
3226 	/*
3227 	 * build a string in umode_buf to represent the change in the user's
3228 	 * mode between the new (sptr->flag) and 'old'.
3229 	 */
3230 	m = umode_buf;
3231 	*m = '\0';
3232 	for (s = user_modes; (flag = *s); s += 2)
3233 	    {
3234 		if (MyClient(sptr) && !(flag & sendmask))
3235 			continue;
3236 		if ((flag & old) && !(sptr->user->flags & flag))
3237 		    {
3238 			if (what == MODE_DEL)
3239 				*m++ = *(s+1);
3240 			else
3241 			    {
3242 				what = MODE_DEL;
3243 				*m++ = '-';
3244 				*m++ = *(s+1);
3245 			    }
3246 		    }
3247 		else if (!(flag & old) && (sptr->user->flags & flag))
3248 		    {
3249 			if (what == MODE_ADD)
3250 				*m++ = *(s+1);
3251 			else
3252 			    {
3253 				what = MODE_ADD;
3254 				*m++ = '+';
3255 				*m++ = *(s+1);
3256 			    }
3257 		    }
3258 	    }
3259 	*m = '\0';
3260 	if (*umode_buf && cptr)
3261 		sendto_one(cptr, ":%s MODE %s :%s",
3262 			   sptr->name, sptr->name, umode_buf);
3263 }
3264 
3265 /*
3266  * added Sat Jul 25 07:30:42 EST 1992
3267  */
send_umode_out(aClient * cptr,aClient * sptr,int old)3268 void	send_umode_out(aClient *cptr, aClient *sptr, int old)
3269 {
3270 	Reg	int	i;
3271 	Reg	aClient	*acptr;
3272 
3273 	send_umode(NULL, sptr, old, SEND_UMODES, buf);
3274 
3275 	if (*buf)
3276 		for (i = fdas.highest; i >= 0; i--)
3277 		    {
3278 			if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr))
3279 				continue;
3280 			if (acptr == cptr || acptr == sptr)
3281 				continue;
3282 			sendto_one(acptr, ":%s MODE %s :%s",
3283 				   sptr->user->uid, sptr->name, buf);
3284 		    }
3285 
3286 	if (cptr && MyClient(cptr))
3287 		send_umode(cptr, sptr, old, ALL_UMODES, buf);
3288 #ifdef USE_SERVICES
3289 	/* buf contains all modes for local users, and iow only for remotes */
3290 	if (*buf)
3291 		check_services_butone(SERVICE_WANT_UMODE, sptr->user->servp,
3292 				      sptr, ":%s MODE %s :%s", sptr->name,
3293 				      sptr->name, buf);
3294 #endif
3295 }
3296 
3297 /*
3298 ** save_user() added 990618 by Christope Kalt
3299 **
3300 ** This will save the user sptr, and put the nick he's currently using in
3301 ** nick delay.
3302 ** It will send SAVE to the servers that can deal with it, and just a nick
3303 ** change to the rest.
3304 ** It will adjust the path, to include the link we got the SAVE message from.
3305 ** For internal calls, set cptr to NULL.
3306 */
save_user(aClient * cptr,aClient * sptr,char * path)3307 static	void	save_user(aClient *cptr, aClient *sptr, char *path)
3308 {
3309 	if (MyConnect(sptr))
3310 	{
3311 		sendto_one(sptr, replies[RPL_SAVENICK], cptr ? cptr->name : ME,
3312 			   sptr->name, sptr->user->uid);
3313 #if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_NICK)
3314 		sendto_flag(SCH_CLIENT, "%s %s %s %s NICK %s",
3315 			sptr->user->uid, sptr->name, sptr->user->username,
3316 			sptr->user->host, sptr->user->uid);
3317 #endif
3318 	}
3319 
3320 	sendto_common_channels(sptr, ":%s NICK :%s",
3321 			       sptr->name, sptr->user->uid);
3322 	add_history(sptr, NULL);
3323 #ifdef	USE_SERVICES
3324 	check_services_butone(SERVICE_WANT_NICK, sptr->user->servp, sptr,
3325 			      ":%s NICK :%s", sptr->name, sptr->user->uid);
3326 #endif
3327 	sendto_serv_v(cptr, SV_UID, ":%s SAVE %s :%s%c%s",
3328 		cptr ? cptr->serv->sid : me.serv->sid, sptr->user->uid,
3329 		cptr ? cptr->name : ME, cptr ? '!' : ' ', path);
3330 	sendto_flag(SCH_SAVE, "Received SAVE message for %s. Path: %s!%s",
3331 		    sptr->name, cptr ? cptr->name : ME, path);
3332 	del_from_client_hash_table(sptr->name, sptr);
3333 	strcpy(sptr->name, sptr->user->uid);
3334 	add_to_client_hash_table(sptr->name, sptr);
3335 }
3336 
3337 /*
3338 ** m_save() added 990618 by Christope Kalt
3339 **	parv[0] = sender prefix
3340 **	parv[1] = saved user
3341 **	parv[2] = save path
3342 */
m_save(aClient * cptr,aClient * sptr,int parc,char * parv[])3343 int	m_save(aClient *cptr, aClient *sptr, int parc, char *parv[])
3344 {
3345 	aClient *acptr;
3346 	char *path = (parc > 2) ? parv[2] : "*no-path*";
3347 
3348 	if (parc < 2)
3349 	{
3350 		sendto_flag(SCH_ERROR, "Save with not enough parameters "
3351 			"from %s", cptr->name);
3352 		return 1;
3353 	}
3354 
3355 	/* need sanity checks here -syrk */
3356 	acptr = find_uid(parv[1], NULL);
3357 	if (acptr && strcasecmp(acptr->name, acptr->user->uid))
3358 	{
3359 		save_user(cptr, acptr, path);
3360 		ircstp->is_save++;
3361 	}
3362 
3363 	return 0;
3364 }
3365 
3366 /*
3367 ** Given client cptr and function decide access.
3368 ** Return 1 for OK, 0 for forbidden.
3369 */
3370 
is_allowed(aClient * cptr,long function)3371 int	is_allowed(aClient *cptr, long function)
3372 {
3373 	Link	*tmp;
3374 
3375 	/* We cannot judge not our clients. Yet. */
3376 	if (!MyConnect(cptr) || IsServer(cptr))
3377 		return 1;
3378 
3379 	/* minimal control, but nothing else service can do anyway. */
3380 	if (IsService(cptr))
3381 	{
3382 		if (function == ACL_TKLINE &&
3383 			(cptr->service->wants & SERVICE_WANT_TKLINE))
3384 			return 1;
3385 		if (function == ACL_KLINE &&
3386 			(cptr->service->wants & SERVICE_WANT_KLINE))
3387 			return 1;
3388 		return 0;
3389 	}
3390 
3391 	for (tmp = cptr->confs; tmp; tmp = tmp->next)
3392 	{
3393 		if (tmp->value.aconf->status & CONF_OPERATOR)
3394 			break;
3395 	}
3396 
3397 	/* no O: conf found */
3398 	if (!tmp)
3399 		return 0;
3400 
3401 	/* check access */
3402 	if ((tmp->value.aconf->flags & function))
3403 		return 1;
3404 
3405 	return 0;
3406 }
3407 
send_away(aClient * sptr,aClient * acptr)3408 void send_away(aClient *sptr, aClient *acptr)
3409 {
3410 	if (acptr->user->away)
3411 	{
3412 		sendto_one(sptr, replies[RPL_AWAY], ME, sptr->name,
3413 			acptr->name, acptr->user->away);
3414 	}
3415 	else
3416 	{
3417 #ifdef AWAY_MOREINFO
3418 		/* Building buffer and using it instead of "Gone" would be
3419 		 * a better code, but a bit slower; just rememeber about this
3420 		 * one when ever changing RPL_AWAY --B. */
3421 		sendto_one(sptr, ":%s 301 %s %s :"
3422 			"Gone, for more info use WHOIS %s %s",
3423 			ME, sptr->name, acptr->name,
3424 			acptr->name, acptr->name);
3425 #else
3426 		sendto_one(sptr, replies[RPL_AWAY], ME, sptr->name,
3427 			acptr->name, "Gone");
3428 #endif
3429 	}
3430 }
3431