Beispiel #1
0
void	check_split(void)
{
	if ((bootopt & BOOT_STANDALONE))
		return;

	if (istat.is_eobservers < iconf.split_minservers ||
	    istat.is_user[0] + istat.is_user[1] < iconf.split_minusers)
	{
		/* Split detected */
		if (!IsSplit())
		{
			sendto_flag(SCH_NOTICE,
				"Network split detected, split mode activated");
			iconf.split = timeofday;
		}
	}
	else
	{
		/* End of split */
		if (IsSplit())
		{
			sendto_flag(SCH_NOTICE,
				"Network rejoined, split mode deactivated");
			iconf.split = 0;
			if (!firstrejoindone)
			{
				firstrejoindone = 1;
				activate_delayed_listeners();
#ifdef CACCEPT_DEFAULT
				iconf.caccept = CACCEPT_DEFAULT;
#endif
			}
		}
	}
}
Beispiel #2
0
void	free_server(aServer *serv)
{
	aClient *cptr = serv->bcptr;
	/* decrement reference counter, and eventually free it */
	if (--serv->refcnt <= 0)
	{
		if (serv->refcnt == -211001)
		{
			/* Loop detected, break it.
			 * XXX: Remove loop detection before 2.11.0 - jv */
			sendto_flag(SCH_DEBUG, "* %#x free_server loop %s *",
				    serv, serv->namebuf);
			return;

		}
		/* Decrease (and possibly free) refcnt of the user struct
		 * of who connected this server.
		 */
		if (serv->user)
		{
			int cnt = serv->refcnt;
			serv->refcnt = -211000;	/* Loop detection */
			free_user(serv->user);
			serv->user = NULL;
			serv->refcnt = cnt;
		}

		if (serv->refcnt < 0 ||	serv->prevs || serv->nexts ||
		    serv->bcptr || serv->user)
		{
			char buf[512];

			sprintf(buf, "%d %p %p %p %p (%s)",
				serv->refcnt, (void *)serv->prevs,
				(void *)serv->nexts, (void *)serv->user,
				(void *)serv->bcptr,
				(serv->bcptr) ? serv->bcptr->name : "none");
#ifdef DEBUGMODE
			dumpcore("%#x server %s %s",
				 cptr, cptr ? cptr->name : "<noname>", buf);
			servs.inuse--;
#else
			sendto_flag(SCH_ERROR, "* %#x server %s %s *",
				    cptr, cptr ? cptr->name : "<noname>", buf);
#endif
		}

		MyFree(serv);
	}
}
Beispiel #3
0
void	free_client(aClient *cptr)
{
	if (cptr->info != DefInfo)
		MyFree(cptr->info);
	/* True only for local clients */
	if (cptr->hopcount == 0 || (IsServer(cptr) && cptr->hopcount == 1))
	{
		if (cptr->auth != cptr->username)
		{
			sendto_flag(SCH_ERROR, "Please report to ircd-bug@"
				"irc.org about cptr->auth allocated but not"
				" free()d!");
			istat.is_authmem -= strlen(cptr->auth) + 1;
			istat.is_auth -= 1;
			MyFree(cptr->auth);
		}
		if (cptr->reason)
		{
			MyFree(cptr->reason);
		}
#ifdef XLINE
		if (cptr->user2)
			MyFree(cptr->user2);
		if (cptr->user3)
			MyFree(cptr->user3);
#endif
	}
	MyFree(cptr);
}
Beispiel #4
0
/*
** exit_server(): Removes all dependent servers and clients, and
** sends the right messages to the right client/servers.
**
** We will send all SQUITs to &servers, and QUITs to local users.
** We only send 1 SQUIT to a 2.11 servers.
** We send all SQUITs to a 2.10 servers that can see it, or QUITs otherwise.
**
** Argument:
**	cptr: The real server to SQUIT.
**	acptr: One of the depended servers to SQUIT.
**	from: Originator of SQUIT.
**	comment: The original comment for the SQUIT. (Only for cptr itself.)
**	comment2: The comment for (S)QUIT reasons for the rest.
*/
static	void	exit_server(aClient *cptr, aClient *acptr, aClient *from,
			const char *comment, const char *comment2)
{
	aClient	*acptr2;
	int	flags;

	/* Remove all the servers recursively. */
	while (acptr->serv->down)
	{
		exit_server(cptr, acptr->serv->down, from, comment, comment2);
	}
	/* Here we should send "Received SQUIT" for last server,
	** but exit_client() is doing (well, almost) this --Beeth */

	/* This server doesn't have any depedent servers anymore, only
	** users/services left. */

	flags = FLAGS_SPLIT;

	/*
	** We'll mark all servers that can't see that server as hidden.
	** If we found any, we'll also mark all users on that server hidden.
	** If a user is marked hidden, and we try to send it to a currently
	** marked server, the server can't see that user's server.
	** Note that a 2.11 can see it, so we don't have to send the QUITs
	** to it.
	*/
	if (mark_blind_servers(cptr, acptr))
	{
		flags |= FLAGS_HIDDEN;
	}

	/* Quit all users and services. */
	while (GotDependantClient(acptr))
	{
		acptr2 = acptr->prev;
		acptr2->flags |= flags;
		exit_one_client(cptr->from, acptr2, from, comment2);
	}

	/* Make sure we only send the last SQUIT to a 2.11 server. */
	if (acptr == cptr)
	{
		acptr->flags |= FLAGS_SQUIT;
	}
	if (!IsMasked(acptr))
	{
		sendto_flag(SCH_SERVER,
			"Received SQUIT %s from %s (%s)", acptr->name,
			from->name,
			acptr == cptr ? comment : comment2);
	}
	exit_one_client(cptr->from, acptr, from,
		acptr == cptr ? comment : comment2);
	
	return;
}
Beispiel #5
0
void	restart(char *mesg)
{
#ifdef	USE_SYSLOG
	(void)syslog(LOG_WARNING, "Restarting Server because: %s (%u)", mesg,
		     (u_int)((char *)sbrk((size_t)0)-sbrk0));
#endif
	sendto_flag(SCH_NOTICE, "Restarting server because: %s (%u)", mesg,
		    (u_int)((char *)sbrk((size_t)0)-sbrk0));
	server_reboot();
}
Beispiel #6
0
void	outofmemory(void)
{
	if (serverbooting)
	{

		fprintf(stderr,"Fatal Error: Out of memory.\n");
		exit(-1);
	}
	Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
	sendto_flag(SCH_NOTICE, "Ouch!!! Out of memory...");
	restart("Out of Memory");
}
Beispiel #7
0
void	server_reboot(void)
{
	Reg	int	i;

	sendto_flag(SCH_NOTICE, "Aieeeee!!!  Restarting server... (%u)",
		    (u_int)((char *)sbrk((size_t)0)-sbrk0));

	Debug((DEBUG_NOTICE,"Restarting server..."));
	flush_connections(me.fd);
	/*
	** fd 0 must be 'preserved' if either the -d or -i options have
	** been passed to us before restarting.
	*/
#ifdef USE_SYSLOG
	(void)closelog();
#endif
	logfiles_close();
	for (i = 3; i < MAXCONNECTIONS; i++)
		(void)close(i);
	if (!(bootopt & (BOOT_TTY|BOOT_DEBUG)))
	{
		(void)close(2);
		(void)close(1);
	}
	if ((bootopt & BOOT_CONSOLE) || isatty(0))
		(void)close(0);
	ircd_writetune(tunefile);
	if (!(bootopt & BOOT_INETD))
	    {
		(void)execv(IRCD_PATH, myargv);
#ifdef USE_SYSLOG
		/* Have to reopen since it has been closed above */
		
		openlog(mybasename(myargv[0]), LOG_PID|LOG_NDELAY, LOG_FACILITY);
		syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", IRCD_PATH,
		       myargv[0]);
		closelog();
#endif
		Debug((DEBUG_FATAL,"Couldn't restart server: %s",
		       strerror(errno)));
	    }
	exit(-1);
}
Beispiel #8
0
Datei: send.c Projekt: ahf/irc
/*
** dead_link
**	An error has been detected. The link *must* be closed,
**	but *cannot* call ExitClient (m_bye) from here.
**	Instead, mark it with FLAGS_DEADSOCK. This should
**	generate ExitClient from the main loop.
**
**	The notice is skipped for "uninteresting" cases,
**	like Persons and yet unknown connections...
*/
static	int	dead_link(aClient *to, char *pattern, ...)
{
	char	notice[BUFSIZE];
	va_list	va;

	va_start(va, pattern);
	vsprintf(notice, pattern, va);
	va_end(va);

	SetDead(to);
	/*
	 * If because of BUFFERPOOL problem then clean dbufs now so that
	 * notices don't hurt operators below.
	 */
	DBufClear(&to->recvQ);
	DBufClear(&to->sendQ);
	if (!IsPerson(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING))
		sendto_flag(SCH_ERROR, notice);
	Debug((DEBUG_ERROR, notice));
	return -1;
}
Beispiel #9
0
/*
** off_history
**	This must be called when the client structure is about to
**	be released. History mechanism keeps pointers to client
**	structures and it must know when they cease to exist. This
**	also implicitly calls AddHistory.
*/
void	off_history(aClient *cptr)
{
	Reg	Link	*uwas;

	/*
	** If the client has uwas entry/ies, there are also entries in
	** the whowas array which point back to it.
	** They have to be removed, by pairs
	*/
	while ((uwas = cptr->user->uwas))
	    {
		if (was[uwas->value.i].ww_online != cptr)
#ifdef DEBUGMODE
			dumpcore("was[%d]: %#x != %#x", uwas->value.i,
				 was[uwas->value.i].ww_online, cptr);
#else
			sendto_flag(SCH_ERROR, "was[%d]: %#x != %#x", 
				    uwas->value.i, 
				    was[uwas->value.i].ww_online, cptr);
#endif
		/*
		** using &me to make ww_online non NULL (nicknames to be
		** locked). &me can safely be used, it is constant.
		*/
		was[uwas->value.i].ww_online = &me;
		cptr->user->uwas = uwas->next;
		free_link(uwas);
		istat.is_wwuwas--;
	    }

	istat.is_wwusers++;
	if (cptr->user->away)
	    {
		istat.is_wwaways++;
		istat.is_wwawaysmem += strlen(cptr->user->away) + 1;
	    }
		
	return;
}
Beispiel #10
0
/*
 * move the client aClient struct before its server's
 */
void	reorder_client_in_list(aClient *cptr)
{
    if (cptr->user == NULL && cptr->service == NULL)
	    return;

    /* update neighbours */
    if (cptr->next)
	    cptr->next->prev = cptr->prev;
    if (cptr->prev)
	    cptr->prev->next = cptr->next;
    else
	    client = cptr->next;

    /* re-insert */
    if (cptr->user)
	{
	    cptr->next = cptr->user->servp->bcptr;
	    cptr->prev = cptr->user->servp->bcptr->prev;
#ifdef DEBUGMODE
	    sendto_flag(SCH_DEBUG, "%p [%s] moved before server: %p [%s]", 
			cptr, cptr->name, cptr->user->servp->bcptr, 
			cptr->user->servp->bcptr->name);
#endif
	}
    else if (cptr->service)
	{
	    cptr->next = cptr->service->servp->bcptr;
	    cptr->prev = cptr->service->servp->bcptr->prev;
	}

    /* update new neighbours */
    if (cptr->prev)
	    cptr->prev->next = cptr;
    else
	    client = cptr;
    cptr->next->prev = cptr;
}
Beispiel #11
0
/*
 * sendto_iauth
 *
 *	Send the buffer to the authentication slave process.
 *	Return 0 if everything went well, -1 otherwise.
 */
int	vsendto_iauth(char *pattern, va_list va)
{
	static char abuf[BUFSIZ], *p;
	int	i, len;

	if (adfd < 0)
	{
		return -1;
	}

	vsprintf(abuf, pattern, va);
	strcat(abuf, "\n");
	p = abuf;
	len = strlen(p);

	do
	{
		i = write(adfd, abuf, len);
		if ( i == -1 )
		{
			if (errno != EAGAIN && errno != EWOULDBLOCK)
			{
				sendto_flag(SCH_AUTH, "Aiiie! lost slave "
					"authentication process");
				close(adfd);
				adfd = -1;
				start_iauth(0);
				return -1;
			}
			i = 0;
		}
		p += i;
		len -= i;
	} while (len > 0);

	return 0;
}
Beispiel #12
0
/* Checks all clients against KILL lines. (And remove them, if found.)
** Only MAXDELAYEDKILLS at a time or all, if not defined.
** Returns 1, if still work to do, 0 if finished.
*/
static	int	delayed_kills(time_t currenttime)
{
	static	time_t	dk_rehashed = 0;	/* time of last rehash we're processing */
	static	int	dk_lastfd;		/* fd we last checked */
	static	int	dk_checked;		/* # clients we checked */
	static	int	dk_killed;		/* # clients we killed */
	Reg	aClient	*cptr;
	Reg	int	i, j;

	if (dk_rehashed == 0)
	{
		dk_rehashed = currenttime;
		dk_checked = 0;
		dk_killed = 0;
		dk_lastfd = highest_fd;
	}
#ifdef MAXDELAYEDKILLS
	/* checking only this many clients each time */
	j = dk_lastfd - MAXDELAYEDKILLS + 1;
	if (j < 0)
#endif
		j = 0;

	for (i = dk_lastfd; i >= j; i--)
	{
		int	kflag = 0;
		char	*reason = NULL;

		if (!(cptr = local[i]) || !IsPerson(cptr))
		{
			/* for K:lines we're interested only in local,
			** fully registered clients */
			if (j > 0)
				j--;
			continue;
		}

		dk_checked++;
		kflag = find_kill(cptr, 0, &reason);

		/* If the client is a user and a KILL line was found
		** to be active, close this connection. */
		if (kflag == -1)
		{
			char buf[100];

			dk_killed++;
			sendto_flag(SCH_NOTICE,
				"Kill line active for %s",
				get_client_name(cptr, FALSE));
				cptr->exitc = EXITC_KLINE;
			if (!BadPtr(reason))
				sprintf(buf, "Kill line active: %.80s",
						reason);
			(void)exit_client(cptr, cptr, &me, (reason) ?
					  buf : "Kill line active");
		}
	}
	dk_lastfd = i;	/* from which fd to start next time */
	Debug((DEBUG_DEBUG, "DelayedKills killed %d and counting...",
		dk_killed));

	if (dk_lastfd < 0)
	{
		sendto_flag(SCH_NOTICE, "DelayedKills checked %d killed %d "
			"in %d sec", dk_checked, dk_killed,
			currenttime - dk_rehashed);
		dk_rehashed = 0;
		if (rehashed == 2)
		{
			/* there was rehash queued, start again */
			return 1;
		}
		return 0;
	}
	return rehashed;
}
Beispiel #13
0
static	time_t	check_pings(time_t currenttime)
{
#ifdef TIMEDKLINES
	static	time_t	lkill = 0;
#endif
	Reg	aClient	*cptr;
	Reg	int	kflag = 0;
	aClient *bysptr = NULL;
	int	ping = 0, i;
	time_t	oldest = 0, timeout;
	char	*reason = NULL;

	for (i = highest_fd; i >= 0; i--)
	    {
		if (!(cptr = local[i]) || IsListener(cptr))
			continue;

#ifdef TIMEDKLINES
		kflag = 0;
		reason = NULL;
		/* 
		** Once per TIMEDKLINES seconds.
		** (1 minute is minimum resolution in K-line field)
		*/
		if ((currenttime - lkill > TIMEDKLINES)
			&& IsPerson(cptr) && !IsKlineExempt(cptr))
		{
			kflag = find_kill(cptr, 1, &reason);
		}
#endif
		ping = IsRegistered(cptr) ? cptr->ping : ACCEPTTIMEOUT;
		Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d a %d",
			cptr->name, cptr->status, ping, kflag,
			currenttime - cptr->lasttime));
		/*
		 * Ok, so goto's are ugly and can be avoided here but this code
		 * is already indented enough so I think its justified. -avalon
		 */
		if (!kflag && IsRegistered(cptr) &&
		    (ping >= currenttime - cptr->lasttime))
			goto ping_timeout;
		/*
		 * If the server hasnt talked to us in 2*ping seconds
		 * and it has a ping time, then close its connection.
		 * If the client is a user and a KILL line was found
		 * to be active, close this connection too.
		 */
		if (kflag ||
		    ((currenttime - cptr->lasttime) >= (2 * ping) &&
		     (cptr->flags & FLAGS_PINGSENT)) ||
		    (!IsRegistered(cptr) &&
		     (currenttime - cptr->firsttime) >= ping))
		    {
			if (!IsRegistered(cptr) && 
			    (DoingDNS(cptr) || DoingAuth(cptr) ||
			     DoingXAuth(cptr)))
			    {
				if (cptr->authfd >= 0)
				    {
					(void)close(cptr->authfd);
					cptr->authfd = -1;
					cptr->count = 0;
					*cptr->buffer = '\0';
				    }
				Debug((DEBUG_NOTICE, "%s/%c%s timeout %s",
				       (DoingDNS(cptr)) ? "DNS" : "dns",
				       (DoingXAuth(cptr)) ? "X" : "x",
				       (DoingAuth(cptr)) ? "AUTH" : "auth",
				       get_client_name(cptr,TRUE)));
				del_queries((char *)cptr);
				ClearAuth(cptr);
#if defined(USE_IAUTH)
				if (DoingDNS(cptr) || DoingXAuth(cptr))
				    {
					if (DoingDNS(cptr) &&
					    (iauth_options & XOPT_EXTWAIT))
					    {
						/* iauth wants more time */
						sendto_iauth("%d d", cptr->fd);
						ClearDNS(cptr);
						cptr->lasttime = currenttime;
						continue;
					    }
					if (DoingXAuth(cptr) &&
					    (iauth_options & XOPT_NOTIMEOUT))
					    {
						cptr->exitc = EXITC_AUTHTOUT;
						sendto_iauth("%d T", cptr->fd);
						exit_client(cptr, cptr, &me,
						     "Authentication Timeout");
						continue;
					    }
					sendto_iauth("%d T", cptr->fd);
					SetDoneXAuth(cptr);
				    }
#endif
				ClearDNS(cptr);
				ClearXAuth(cptr);
				ClearWXAuth(cptr);
				cptr->firsttime = currenttime;
				cptr->lasttime = currenttime;
				continue;
			    }
			if (IsServer(cptr) || IsConnecting(cptr) ||
			    IsHandshake(cptr))
			{
				if (cptr->serv && cptr->serv->byuid[0])
				{
					bysptr = find_uid(cptr->serv->byuid,
							NULL);
				}
				/* we are interested only in *remote* opers */
				if (bysptr && !MyConnect(bysptr))
				{
					sendto_one(bysptr, ":%s NOTICE %s :"
						"No response from %s, closing"
						" link", ME, bysptr->name,
						get_client_name(cptr, FALSE));
				}
				sendto_flag(SCH_NOTICE,
					    "No response from %s closing link",
					    get_client_name(cptr, FALSE));
			}
			/*
			 * this is used for KILL lines with time restrictions
			 * on them - send a message to the user being killed
			 * first.
			 */
			if (kflag && IsPerson(cptr))
			    {
				char buf[100];

				sendto_flag(SCH_NOTICE,
					    "Kill line active for %s",
					    get_client_name(cptr, FALSE));
				cptr->exitc = EXITC_KLINE;
				if (!BadPtr(reason))
					sprintf(buf, "Kill line active: %.80s",
						reason);
				(void)exit_client(cptr, cptr, &me, (reason) ?
						  buf : "Kill line active");
			    }
			else
			    {
				cptr->exitc = EXITC_PING;
				(void)exit_client(cptr, cptr, &me,
						  "Ping timeout");
			    }
			continue;
		    }
		else if (IsRegistered(cptr) &&
			 (cptr->flags & FLAGS_PINGSENT) == 0)
		    {
			/*
			 * if we havent PINGed the connection and we havent
			 * heard from it in a while, PING it to make sure
			 * it is still alive.
			 */
			cptr->flags |= FLAGS_PINGSENT;
			/* not nice but does the job */
			cptr->lasttime = currenttime - ping;
			sendto_one(cptr, "PING :%s", me.name);
		    }
ping_timeout:
		timeout = cptr->lasttime + ping;
		while (timeout <= currenttime)
			timeout += ping;
		if (timeout < oldest || !oldest)
			oldest = timeout;
	    }
#ifdef TIMEDKLINES
	if (currenttime - lkill > 60)
		lkill = currenttime;
#endif
	if (!oldest || oldest < currenttime)
		oldest = currenttime + PINGFREQUENCY;
	if (oldest < currenttime + 30)
		oldest += 30;
	Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
		myctime(oldest), ping, oldest, currenttime));
	return (oldest);
}
Beispiel #14
0
/*
 * start_auth
 *
 * Flag the client to show that an attempt to contact the ident server on
 * the client's host.  The connect and subsequently the socket are all put
 * into 'non-blocking' mode.  Should the connect or any later phase of the
 * identifing process fail, it is aborted and the user is given a username
 * of "unknown".
 */
void	start_auth(aClient *cptr)
{
#ifndef	NO_IDENT
	struct	SOCKADDR_IN	us, them;

	SOCK_LEN_TYPE ulen, tlen;

# if defined(USE_IAUTH)
	if ((iauth_options & XOPT_REQUIRED) && adfd < 0)
		return;
# endif
	Debug((DEBUG_NOTICE,"start_auth(%x) fd %d status %d",
		cptr, cptr->fd, cptr->status));
	if ((cptr->authfd = socket(AFINET, SOCK_STREAM, 0)) == -1)
	    {
# ifdef	USE_SYSLOG
		syslog(LOG_ERR, "Unable to create auth socket for %s:%m",
			get_client_name(cptr,TRUE));
# endif
		Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s",
			get_client_name(cptr, TRUE),
			strerror(get_sockerr(cptr))));
		ircstp->is_abad++;
		return;
	    }
	if (cptr->authfd >= (MAXCONNECTIONS - 2))
	    {
		sendto_flag(SCH_ERROR, "Can't allocate fd for auth on %s",
			   get_client_name(cptr, TRUE));
		(void)close(cptr->authfd);
		return;
	    }

	set_non_blocking(cptr->authfd, cptr);

	/* get remote host peer - so that we get right interface -- jrg */
	tlen = ulen = sizeof(us);
	if (getpeername(cptr->fd, (struct sockaddr *)&them, &tlen) < 0)
	    {
		/* we probably don't need this error message -kalt */
		report_error("getpeername for auth request %s:%s", cptr);
		close(cptr->authfd);
		cptr->authfd = -1;
		return;
	    }
	them.SIN_FAMILY = AFINET;

	/* We must bind the local end to the interface that they connected
	   to: The local system might have more than one network address,
	   and RFC931 check only sends port numbers: server takes IP addresses
	   from query socket -- jrg */
	(void)getsockname(cptr->fd, (struct sockaddr *)&us, &ulen);
	us.SIN_FAMILY = AFINET;
# if defined(USE_IAUTH)
	if (adfd >= 0)
	    {
		char abuf[BUFSIZ];
#  ifdef INET6
		sprintf(abuf, "%d C %s %u ", cptr->fd,
			inetntop(AF_INET6, (char *)&them.sin6_addr, ipv6string,
				 sizeof(ipv6string)), ntohs(them.SIN_PORT));
		sprintf(abuf+strlen(abuf), "%s %u",
			inetntop(AF_INET6, (char *)&us.sin6_addr, ipv6string,
				 sizeof(ipv6string)), ntohs(us.SIN_PORT));
#  else
		sprintf(abuf, "%d C %s %u ", cptr->fd,
			inetntoa((char *)&them.sin_addr),ntohs(them.SIN_PORT));
		sprintf(abuf+strlen(abuf), "%s %u",
			inetntoa((char *)&us.sin_addr), ntohs(us.SIN_PORT));
#  endif
		if (sendto_iauth(abuf) == 0)
		    {
			close(cptr->authfd);
			cptr->authfd = -1;
			cptr->flags |= FLAGS_XAUTH;
			return;
		    }
	    }
# endif
# ifdef INET6
	Debug((DEBUG_NOTICE,"auth(%x) from %s %x %x",
	       cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr, ipv6string,
			       sizeof(ipv6string)), us.sin6_addr.s6_addr[14],
	       us.sin6_addr.s6_addr[15]));
# else
	Debug((DEBUG_NOTICE,"auth(%x) from %s",
	       cptr, inetntoa((char *)&us.sin_addr)));
# endif
	them.SIN_PORT = htons(113);
	us.SIN_PORT = htons(0);  /* bind assigns us a port */
	if (bind(cptr->authfd, (struct SOCKADDR *)&us, ulen) >= 0)
	    {
		(void)getsockname(cptr->fd, (struct SOCKADDR *)&us, &ulen);
# ifdef INET6
		Debug((DEBUG_NOTICE,"auth(%x) to %s",
			cptr, inet_ntop(AF_INET6, (char *)&them.sin6_addr,
					ipv6string, sizeof(ipv6string))));
# else
		Debug((DEBUG_NOTICE,"auth(%x) to %s",
			cptr, inetntoa((char *)&them.sin_addr)));
# endif
		(void)alarm((unsigned)4);
		if (connect(cptr->authfd, (struct SOCKADDR *)&them,
			    tlen) == -1 && errno != EINPROGRESS)
		    {
# ifdef INET6
			Debug((DEBUG_ERROR,
				"auth(%x) connect failed to %s - %d", cptr,
				inet_ntop(AF_INET6, (char *)&them.sin6_addr,
					  ipv6string, sizeof(ipv6string)), errno));
# else
			Debug((DEBUG_ERROR,
				"auth(%x) connect failed to %s - %d", cptr,
				inetntoa((char *)&them.sin_addr), errno));
# endif
			ircstp->is_abad++;
			/*
			 * No error report from this...
			 */
			(void)alarm((unsigned)0);
			(void)close(cptr->authfd);
			cptr->authfd = -1;
			return;
		    }
		(void)alarm((unsigned)0);
	    }
	else
	    {
		report_error("binding stream socket for auth request %s:%s",
			     cptr);
# ifdef INET6
		Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d",
		      cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr,
		      ipv6string, sizeof(ipv6string)),
		      ntohs(us.SIN_PORT), errno));
# else
		Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d",
		      cptr, inetntoa((char *)&us.sin_addr),
		      ntohs(us.SIN_PORT), errno));
# endif
	    }

	cptr->flags |= (FLAGS_WRAUTH|FLAGS_AUTH);
	if (cptr->authfd > highest_fd)
		highest_fd = cptr->authfd;
#endif
	return;
}
Beispiel #15
0
/*
** try_connections
**
**	Scan through configuration and try new connections.
**	Returns the calendar time when the next call to this
**	function should be made latest. (No harm done if this
**	is called earlier or later...)
*/
static	time_t	try_connections(time_t currenttime)
{
	Reg	aConfItem *aconf;
	Reg	aClient *cptr;
	aConfItem **pconf;
	int	confrq;
	time_t	next = 0;
	aClass	*cltmp;
	aConfItem *con_conf = NULL;
	int	allheld = 1;
#ifdef DISABLE_DOUBLE_CONNECTS
	int	i;
#endif

	if ((bootopt & BOOT_STANDALONE))
		return 0;

	Debug((DEBUG_NOTICE,"Connection check at   : %s",
		myctime(currenttime)));
	for (aconf = conf; aconf; aconf = aconf->next )
	{
		/* not a C-line */
		if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
			continue;

		/* not a candidate for AC */
		if (aconf->port <= 0)
			continue;

		cltmp = Class(aconf);
		/* not a candidate for AC */
		if (MaxLinks(cltmp) == 0)
			continue;

		/* minimize next to lowest hold time of all AC-able C-lines */
		if (next > aconf->hold || next == 0)
			next = aconf->hold;

		/* skip conf if the use of it is on hold until future. */
		if (aconf->hold > currenttime)
			continue;

		/* at least one candidate not held for future, good */
		allheld = 0;

		/* see if another link in this conf is allowed */
		if (Links(cltmp) >= MaxLinks(cltmp))
			continue;
		
		/* next possible check after connfreq secs for this C-line */
		confrq = get_con_freq(cltmp);
		aconf->hold = currenttime + confrq;

		/* is this server already connected? */
		cptr = find_name(aconf->name, (aClient *)NULL);
		if (!cptr)
			cptr = find_mask(aconf->name, (aClient *)NULL);

		/* matching client already exists, no AC to it */
		if (cptr)
			continue;

		/* no such server, check D-lines */
		if (find_denied(aconf->name, Class(cltmp)))
			continue;

#ifdef DISABLE_DOUBLE_CONNECTS
		/* Much better would be traversing only unknown
		** connections, but this requires another global
		** variable, adding and removing from there in
		** proper places etc. Some day. --B. */
		for (i = highest_fd; i >= 0; i--)
		{
			if (!(cptr = local[i]) ||
				cptr->status > STAT_UNKNOWN)
			{
				continue;
			}
			/* an unknown traveller we have */
			if (
#ifndef INET6
				cptr->ip.s_addr == aconf->ipnum.s_addr
#else
				!memcmp(cptr->ip.s6_addr,
					aconf->ipnum.s6_addr, 16)
#endif
			)
			{
				/* IP the same. Coincidence? Maybe.
				** Do not cause havoc with double connect. */
				break;
			}
			cptr = NULL;
		}
		if (cptr)
		{
			sendto_flag(SCH_SERVER, "AC to %s postponed", aconf->name);
			continue;
		}
#endif
		/* we have a candidate! */

		/* choose the best. */
		if (!con_conf ||
		     (con_conf->pref > aconf->pref && aconf->pref >= 0) ||
		     (con_conf->pref == -1 &&
		      Class(cltmp) > ConfClass(con_conf)))
		{
			con_conf = aconf;
		}
		/* above is my doubt: if we always choose best connection
		** and it always fails connecting, we may never try another,
		** even "worse"; what shall we do? --Beeth */
	}
	if (con_conf)
	{
		if (con_conf->next)  /* are we already last? */
		{
			for (pconf = &conf; (aconf = *pconf);
			     pconf = &(aconf->next))
				/* put the current one at the end and
				 * make sure we try all connections
				 */
				if (aconf == con_conf)
					*pconf = aconf->next;
			(*pconf = con_conf)->next = 0;
		}

		/* "Penalty" for being the best, so in next call of
		 * try_connections() other servers have chance. --B. */
		con_conf->hold += get_con_freq(Class(con_conf));

		if (!iconf.aconnect)
		{
			sendto_flag(SCH_NOTICE,
				"Connection to %s deferred. Autoconnect "
				"administratively disabled", con_conf->name);
		}
		else if (connect_server(con_conf, (aClient *)NULL,
				   (struct hostent *)NULL) == 0)
		{
			sendto_flag(SCH_NOTICE,
				    "Connection to %s[%s] activated.",
				    con_conf->name, con_conf->host);
		}
	}
	else
	if (allheld == 0)	/* disable AC only when some C: got checked */
	{
		/* No suitable conf for AC was found, so why bother checking
		** again? If some server quits, it'd get reenabled --B. */
		next = 0;
	}
	Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
	return (next);
}
Beispiel #16
0
/*
** add_history
**	Add the currently defined name of the client to history.
**	usually called before changing to a new name (nick).
**	Client must be a fully registered user (specifically,
**	the user structure must have been allocated).
**	if nodelay is NULL, then the nickname will be subject to NickDelay
*/
void	add_history(aClient *cptr, aClient *nodelay)
{
	Reg	aName	*np;
	Reg	Link	*uwas;

	cptr->user->refcnt++;

	np = &was[ww_index];

	if ((np->ww_online && (np->ww_online != &me))
	    && !(np->ww_user && np->ww_user->uwas))
#ifdef DEBUGMODE
		dumpcore("whowas[%d] %#x %#x %#x", ww_index, np->ww_online,
			 np->ww_user, np->ww_user->uwas);
#else
		sendto_flag(SCH_ERROR, "whowas[%d] %#x %#x %#x", ww_index,
			    np->ww_online, np->ww_user, np->ww_user->uwas);
#endif
	/*
	** The entry to be overwritten in was[] is still online.
	** its uwas has to be updated
	*/
	if (np->ww_online && (np->ww_online != &me))
	    {
		Reg	Link	**old_uwas;

		old_uwas = &(np->ww_user->uwas);
		/* (*old_uwas) should NEVER happen to be NULL. -krys */
		while ((*old_uwas)->value.i != ww_index)
			old_uwas = &((*old_uwas)->next);
		uwas = *old_uwas;
		*old_uwas = uwas->next;
		free_link(uwas);
		free_user(np->ww_user);
		istat.is_wwuwas--;
	    }
	else if (np->ww_user)
	    {
		/*
		** Testing refcnt here is quite ugly, and unexact.
		** Nonetheless, the result is almost correct, and another
		** ugly thing in free_server() shoud make it exact.
		** The problem is that 1 anUser structure might be
		** referenced several times from whowas[] but is only counted
		** once. One knows when to add, not when to substract - krys
		*/
		if (np->ww_user->refcnt == 1)
		    {
			istat.is_wwusers--;
			if (np->ww_user->away)
			    {
				istat.is_wwaways--;
				istat.is_wwawaysmem -=strlen(np->ww_user->away)
							+ 1;
			    }
		    }
		free_user(np->ww_user);
	    }

	if (np->ww_logout != 0)
	    {
		int	elapsed = timeofday - np->ww_logout;

		/* some stats */
		ircstp->is_wwcnt++;
		ircstp->is_wwt += elapsed;
		if (elapsed < ircstp->is_wwmt)
			ircstp->is_wwmt = elapsed;
		if (elapsed > ircstp->is_wwMt)
			ircstp->is_wwMt = elapsed;

		if (np->ww_online == NULL)
		    {
			if (locked[lk_index].logout)
			    {
				elapsed = timeofday - locked[lk_index].logout;
				/* some stats first */
				ircstp->is_lkcnt++;
				ircstp->is_lkt += elapsed;
				if (elapsed < ircstp->is_lkmt)
					ircstp->is_lkmt = elapsed;
				if (elapsed > ircstp->is_lkMt)
					ircstp->is_lkMt = elapsed;
			    }

			/*
			 ** This nickname has to be locked, thus copy it to the
			 ** lock[] array.
			 */
			strcpy(locked[lk_index].nick, np->ww_nick);
			locked[lk_index++].logout = np->ww_logout;
			if ((lk_index == lk_size) && (lk_size != ww_size))
			{
				grow_locked();
			}
			if (lk_index >= lk_size)
				lk_index = 0;
		    }
	    }

	if (nodelay == cptr) /* &me is NOT a valid value, see off_history() */
	    {
		/*
		** The client is online, np->ww_online is going to point to
		** it. The client user struct has to point to this entry
		** as well for faster off_history()
		** this uwas, and the ww_online form a pair.
		*/
		uwas = make_link();
		istat.is_wwuwas++;
		/*
		** because of reallocs, one can not store a pointer inside
		** the array. store the index instead.
		*/
		uwas->value.i = ww_index;
		uwas->flags = timeofday;
		uwas->next = cptr->user->uwas;
		cptr->user->uwas = uwas;
	    }

	np->ww_logout = timeofday;
	np->ww_user = cptr->user;
	np->ww_online = (nodelay != NULL) ? nodelay : NULL;

	strncpyzt(np->ww_nick, cptr->name, NICKLEN+1);
	strncpyzt(np->ww_info, cptr->info, REALLEN+1);

	ww_index++;
	if ((ww_index == ww_size) && (numclients > ww_size))
		grow_whowas();
	if (ww_index >= ww_size)
		ww_index = 0;
	return;
}
Beispiel #17
0
/*
** exit_client
**	This is old "m_bye". Name  changed, because this is not a
**	protocol function, but a general server utility function.
**
**	This function exits a client of *any* type (user, server, etc)
**	from this server. Also, this generates all necessary prototol
**	messages that this exit may cause.
**
**   1) If the client is a local client, then this implicitly
**	exits all other clients depending on this connection (e.g.
**	remote clients having 'from'-field that points to this.
**
**   2) If the client is a remote client, then only this is exited.
**
** For convenience, this function returns a suitable value for
** m_funtion return value:
**
**	FLUSH_BUFFER	if (cptr == sptr)
**	0		if (cptr != sptr)
**
**	Parameters:
**
**	aClient *cptr
** 		The local client originating the exit or NULL, if this
** 		exit is generated by this server for internal reasons.
** 		This will not get any of the generated messages.
**	aClient *sptr
**		Client exiting
**	aClient *from
**		Client firing off this Exit, never NULL!
**	char	*comment
**		Reason for the exit
*/
int	exit_client(aClient *cptr, aClient *sptr, aClient *from,
		const char *comment)
{
	char	comment1[HOSTLEN + HOSTLEN + 2];

	if (MyConnect(sptr))
	{
		if (sptr->flags & FLAGS_KILLED)
		{
			sendto_flag(SCH_NOTICE, "Killed: %s.",
				    get_client_name(sptr, TRUE));
			sptr->exitc = EXITC_KILL;
		}

		sptr->flags |= FLAGS_CLOSING;
#if (defined(FNAME_USERLOG) || defined(FNAME_CONNLOG) \
     || defined(USE_SERVICES)) \
    || (defined(USE_SYSLOG) && (defined(SYSLOG_USERS) || defined(SYSLOG_CONN)))
		if (IsPerson(sptr))
		{
# if defined(FNAME_USERLOG) || defined(USE_SERVICES) || \
	(defined(USE_SYSLOG) && defined(SYSLOG_USERS))
			sendto_flog(sptr, EXITC_REG, sptr->user->username,
				    sptr->user->host);
# endif
# if defined(CLIENTS_CHANNEL) && (CLIENTS_CHANNEL_LEVEL & CCL_QUIT)
			sendto_flag(SCH_CLIENT, "%s %s %s %s QUIT %c"
#  if (CLIENTS_CHANNEL_LEVEL & CCL_QUITINFO)
				" :%s"
#  endif
				, sptr->user->uid, sptr->name,
				sptr->user->username, sptr->user->host,
				sptr->exitc
#  if (CLIENTS_CHANNEL_LEVEL & CCL_QUITINFO)
				, comment
#  endif
				);
# endif
		}
		else if (!IsService(sptr))
		{
# if defined(FNAME_CONNLOG) || defined(USE_SERVICES) || \
	(defined(USE_SYSLOG) && defined(SYSLOG_CONN))
			if (sptr->exitc == '\0' || sptr->exitc == EXITC_REG)
			{
				sptr->exitc = EXITC_UNDEF;
			}
			sendto_flog(sptr, sptr->exitc,
				    sptr->user && sptr->user->username ?
				    sptr->user->username : "",
#ifdef UNIXPORT
				    (IsUnixSocket(sptr)) ? me.sockhost :
#endif
				    ((sptr->hostp) ? sptr->hostp->h_name :
				     sptr->sockhost));
# endif
		}
#endif
		if (MyConnect(sptr))
		{
			if (IsPerson(sptr))
			{
				istat.is_myclnt--;
			}
			else if (IsServer(sptr))
			{
				istat.is_myserv--;
			}
			else if (IsService(sptr))
			{
				istat.is_myservice--;
			}
			else
			{
				istat.is_unknown--;
			}

			if (istat.is_myclnt % CLCHNO == 0 &&
				istat.is_myclnt != istat.is_l_myclnt)
			{
				sendto_flag(SCH_NOTICE,
					"Local %screase from %d to %d clients "
					"in %d seconds",
					istat.is_myclnt>istat.is_l_myclnt?"in":"de",
					istat.is_l_myclnt, istat.is_myclnt,
					timeofday - istat.is_l_myclnt_t);
				istat.is_l_myclnt_t = timeofday;
				istat.is_l_myclnt = istat.is_myclnt;
			}
			/* Send SQUIT message to 2.11 servers to tell them
			 * the squit reason for rebroadcast on the other side
			 * - jv
			 */
			if (IsServer(sptr))
			{
				sendto_one(sptr, ":%s SQUIT %s :%s",
					me.serv->sid, sptr->serv->sid,
					comment);
			}

			if (cptr != NULL && sptr != cptr)
			{
				sendto_one(sptr, "ERROR :Closing Link: "
					"%s %s (%s)",
					get_client_name(sptr,FALSE),
					cptr->name, comment);
			}
			else
			{
				sendto_one(sptr, "ERROR :Closing Link: %s (%s)",
					get_client_name(sptr,FALSE), comment);
			}

			if (sptr->auth != sptr->username)
			{
				istat.is_authmem -= strlen(sptr->auth) + 1;
				istat.is_auth -= 1;
				MyFree(sptr->auth);
				sptr->auth = sptr->username;
			}
		}
		/*
		** Currently only server connections can have
		** depending remote clients here, but it does no
		** harm to check for all local clients. In
		** future some other clients than servers might
		** have remotes too...
		** now, I think it harms big client servers... - krys
		**
		** Close the Client connection first and mark it
		** so that no messages are attempted to send to it.
		** (The following *must* make MyConnect(sptr) == FALSE!).
		** It also makes sptr->from == NULL, thus it's unnecessary
		** to test whether "sptr != acptr" in the following loops.
		*/
		close_connection(sptr);

	} /* if (MyConnect(sptr) */

 	if (IsServer(sptr))
 	{
		/* Remove all dependent servers and clients. */
		if (!IsMasked(sptr))
		{
			sprintf(comment1, "%s %s", sptr->serv->up->name,
				sptr->name);
		}
		else
		{
			/* It was a masked server, the squit reason should
			** give the right quit reason for clients. */
			strncpyzt(comment1, comment, sizeof(comment1));
		}
		/* cptr != sptr means non-local server */
		if (cptr != sptr && 
			nextconnect == 0 && find_conf_name(sptr->name,
			(CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER)))
		{
			/* try AC */
			nextconnect = timeofday + HANGONRETRYDELAY;
		}
		exit_server(sptr, sptr, from, comment, comment1);
		check_split();
		if ((cptr == sptr))
		{
			/* It serves no purpose. --B.
			sendto_flag(SCH_SERVER, "Sending SQUIT %s (%s)",
				cptr->name, comment);
			*/
			return FLUSH_BUFFER;
		}
		return 0;
 	}
	
	/*
	** Try to guess from comment if the client is exiting
	** normally (KILL or issued QUIT), or if it is splitting
	** It requires comment for splitting users to be
	** "server.some.where splitting.some.where"
	*/
	comment1[0] = '\0';
	if ((sptr->flags & FLAGS_KILLED) == 0)
	{
		if (comment[0] == '"')
		{
			/* definitely user quit, see m_quit */
			sptr->flags |= FLAGS_QUIT;
		}
		else
		{
		        const char *c = comment;
			int i = 0;
			while (*c && *c != ' ')
				if (*c++ == '.')
					i++;
			if (*c++ && i)
			{
			        i = 0;
				while (*c && *c != ' ')
					if (*c++ == '.')
						i++;
				if (!i || *c)
					sptr->flags |= FLAGS_QUIT;
			}
			else
			{
				sptr->flags |= FLAGS_QUIT;
			}
		}

		if (sptr == cptr && !(sptr->flags & FLAGS_QUIT))
		{
			/*
			** This will avoid nick delay to be abused by
			** letting local users put a comment looking
			** like a server split.
			*/
			strncpyzt(comment1, comment, HOSTLEN + HOSTLEN);
			strcat(comment1, " ");
			sptr->flags |= FLAGS_QUIT;
		}
	}
	
	exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : comment);
	/* XXX: we probably should not call it every client exit */
	/* checking every server quit should suffice --B. */
	/* check_split(); */
	return cptr == sptr ? FLUSH_BUFFER : 0;
    }
Beispiel #18
0
/*
** Exit one client, local or remote. Assuming all dependants have
** been already removed, and socket closed for local client.
*/
static	void	exit_one_client(aClient *cptr, aClient *sptr, aClient *from,
	const char *comment)
{
	Reg	aClient *acptr;
	Reg	int	i;
	Reg	Link	*lp;
	invLink		*ilp;

	/*
	**  For a server or user quitting, propagage the information to
	**  other servers (except to the one where is came from (cptr))
	*/
	if (IsMe(sptr))
	{
		sendto_flag(SCH_ERROR,
			    "ERROR: tried to exit me! : %s", comment);
		return;	/* ...must *never* exit self!! */
	}
	else if (IsServer(sptr))
	{
		/*
		** Old sendto_serv_but_one() call removed because we now
		** need to send different names to different servers
		** (domain name matching)
		*/
		if (!IsMasked(sptr))
		{
			istat.is_serv--;
		}
		if (!IsBursting(sptr))
		{
			istat.is_eobservers--;
		}
	 	for (i = fdas.highest; i >= 0; i--)
		{
			if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) ||
			    acptr == cptr || IsMe(acptr))
			{
				continue;
			}
			if (!(sptr->flags & FLAGS_SQUIT))
			{
				/* Make sure we only send the last SQUIT
				** to a 2.11. */
				continue;
			}
			if ((acptr->flags & FLAGS_HIDDEN) &&
				!IsMasked(sptr))
			{
				/* We need a special SQUIT reason, so
				** the remote server can send the
				** right quit message. */
				sendto_one(acptr, ":%s SQUIT %s :%s %s",
					sptr->serv->up->serv->sid,
					sptr->serv->sid,
					sptr->serv->up->name,
					sptr->name);
			}
			else
			{
				sendto_one(acptr, ":%s SQUIT %s :%s",
					sptr->serv->up->serv->sid,
					sptr->serv->sid, comment);
			}
		}
#ifdef	USE_SERVICES
		check_services_butone(SERVICE_WANT_SQUIT, sptr->serv, sptr,
				      ":%s SQUIT %s :%s", from->name,
				      sptr->name, comment);
#endif
		del_from_sid_hash_table(sptr->serv);
		remove_server_from_tree(sptr);
		/* remove server from svrtop */
		unregister_server(sptr);
	}
	else if (!IsPerson(sptr) && !IsService(sptr))
	{
				    /* ...this test is *dubious*, would need
				    ** some thougth.. but for now it plugs a
				    ** nasty hole in the server... --msa
				    */
		; /* Nothing */
	}
	else if (sptr->name[0] && !IsService(sptr)) /* clean with QUIT... */
	{
		/*
		** If this exit is generated from "m_kill", then there
		** is no sense in sending the QUIT--KILL's have been
		** sent instead.
		*/
		if ((sptr->flags & FLAGS_KILLED) == 0)
		{
			if ((sptr->flags & FLAGS_SPLIT) == 0)
			{
				sendto_serv_butone(cptr, ":%s QUIT :%s",
						   sptr->user->uid, comment);
#ifdef	USE_SERVICES
				check_services_butone(SERVICE_WANT_QUIT|
						      SERVICE_WANT_RQUIT, 
						      (sptr->user) ?
						      sptr->user->servp
						      : NULL, cptr,
						      ":%s QUIT :%s",
						      sptr->name, comment);
#endif
			}
			else
			{
				if (sptr->flags & FLAGS_HIDDEN)
					/* joys of hostmasking */
					for (i = fdas.highest; i >= 0; i--)
					{
						if (!(acptr =local[fdas.fd[i]])
						    || acptr == cptr
						    || IsMe(acptr))
							continue;
						if (acptr->flags & FLAGS_HIDDEN)
							sendto_one(acptr,
								":%s QUIT :%s",
								sptr->user->uid,
								comment);
					}
#ifdef	USE_SERVICES
				check_services_butone(SERVICE_WANT_QUIT, 
					      (sptr->user) ? sptr->user->servp
						      : NULL, cptr,
						      ":%s QUIT :%s",
						      sptr->name, comment);
#endif
			}
		}
#ifdef USE_SERVICES
		else
		{
			/* Send QUIT to services which desire such as well.
			** Services with both _QUIT and _KILL will get both
			** for now --jv
			*/
			check_services_butone(SERVICE_WANT_QUIT, 
					     (sptr->user) ? sptr->user->servp
						      : NULL, cptr,
						      ":%s QUIT :%s",
						      sptr->name, comment);

		}
#endif
		/*
		** If a person is on a channel, send a QUIT notice
		** to every client (person) on the same channel (so
		** that the client can show the "**signoff" message).
		** (Note: The notice is to the local clients *only*)
		*/
		if (sptr->user)
		{
			if (IsInvisible(sptr))
			{
				istat.is_user[1]--;
				sptr->user->servp->usercnt[1]--;
			}
			else
			{
				istat.is_user[0]--;
				sptr->user->servp->usercnt[0]--;
			}
			if (IsAnOper(sptr))
			{
				sptr->user->servp->usercnt[2]--;
				istat.is_oper--;
			}
			sendto_common_channels(sptr, ":%s QUIT :%s",
						sptr->name, comment);

			if (!(acptr = cptr ? cptr : sptr->from))
				acptr = sptr;
			while ((lp = sptr->user->channel))
			{
				/*
				** Mark channels from where remote chop left,
				** this will eventually lock the channel.
				** close_connection() has already been called,
				** it makes MyConnect == False - krys
				*/
				if (sptr != cptr)
				{
					if (*lp->value.chptr->chname == '!')
					{
						if (!(sptr->flags &FLAGS_QUIT))
							lp->value.chptr->history = timeofday + LDELAYCHASETIMELIMIT;
					}
					else if (
#ifndef BETTER_CDELAY
						 !(sptr->flags & FLAGS_QUIT) &&
#endif
						 is_chan_op(sptr, lp->value.chptr))
					{
						lp->value.chptr->history = timeofday + DELAYCHASETIMELIMIT;
					}
				}
				if (IsAnonymous(lp->value.chptr) &&
				    !IsQuiet(lp->value.chptr))
				{
					sendto_channel_butserv(lp->value.chptr, sptr, ":%s PART %s :None", sptr->name, lp->value.chptr->chname);
				}
				remove_user_from_channel(sptr,lp->value.chptr);
			}

			/* Clean up invitefield */
			while ((ilp = sptr->user->invited))
			{
				del_invite(sptr, ilp->chptr);
				/* again, this is all that is needed */
			}

			/* remove from uid hash table */
			if (sptr->user)
			{
				del_from_uid_hash_table(sptr->user->uid, sptr);
			}

			/* Add user to history */
#ifndef BETTER_NDELAY
			add_history(sptr, (sptr->flags & FLAGS_QUIT) ?
				    &me : NULL);
#else
			add_history(sptr, (sptr == cptr) ? &me : NULL);
#endif
			off_history(sptr);
#ifdef USE_HOSTHASH
			del_from_hostname_hash_table(sptr->user->host,
						     sptr->user);
#endif
#ifdef USE_IPHASH
			del_from_ip_hash_table(sptr->user->sip, sptr->user);
#endif
		    }
	    }
	else if (sptr->name[0] && IsService(sptr))
	    {
		/*
		** If this exit is generated from "m_kill", then there
		** is no sense in sending the QUIT--KILL's have been
		** sent instead.
		*/
		if ((sptr->flags & FLAGS_KILLED) == 0)
		{
			/*
			** A service quitting is annoying, It has to be sent
			** to connected servers depending on 
			** sptr->service->dist
			*/
			for (i = fdas.highest; i >= 0; i--)
			    {
				if (!(acptr = local[fdas.fd[i]])
				    || !IsServer(acptr) || acptr == cptr
				    || IsMe(acptr))
				{
					continue;
				}
				if (match(sptr->service->dist, acptr->name) && 
					match(sptr->service->dist, acptr->serv->sid))
				{
					continue;
				}
				sendto_one(acptr, ":%s QUIT :%s", sptr->name,
					   comment);
			}
		}
#ifdef	USE_SERVICES
		check_services_butone(SERVICE_WANT_SERVICE, NULL, NULL,
				      ":%s QUIT :%s", sptr->name, comment);
#endif
		/* MyConnect(sptr) is always FALSE here */
		if (cptr == sptr)
		{
			sendto_flag(SCH_NOTICE, "Service %s disconnected",
				    get_client_name(sptr, TRUE));
		}
		sendto_flag(SCH_SERVICE, "Received QUIT %s from %s (%s)",
			    sptr->name, from->name, comment);
		istat.is_service--;
	    }

	/* Remove sptr from the client list */
	if (del_from_client_hash_table(sptr->name, sptr) != 1)
	{
		Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
			sptr, sptr->name,
			sptr->from ? sptr->from->sockhost : "??host",
			sptr->from, sptr->next, sptr->prev, sptr->fd,
			sptr->status, sptr->user));
	}
	remove_client_from_list(sptr);
	return;
}
Beispiel #19
0
/*
** free_user
**	Decrease user reference count by one and release block,
**	if count reaches 0
*/
void	free_user(anUser *user)
{
	aServer *serv;
	aClient *cptr = user->bcptr;

	if (--user->refcnt <= 0)
	{
		/* Loop: This would be second deallocation of this structure.
		 * XXX: Remove loop detection before 2.11.0 - jv
		 */

		if (user->refcnt == -211001)
		{
			sendto_flag(SCH_ERROR,
				"* %p free_user loop (%s!%s@%s) %p *",
				(void *)cptr, cptr ? cptr->name : "<noname>",
				user->username, user->host, user);

			return;
		}
		
		/*
		 * sanity check
		 */
		if (user->joined || user->refcnt < 0 ||
		    user->invited || user->channel || user->uwas ||
		    user->bcptr)
		{
			char buf[512];
			/*too many arguments for dumpcore() and sendto_flag()*/
			sprintf(buf, "%p %p %p %p %d %d %p (%s)",
				(void *)user, (void *)user->invited,
				(void *)user->channel, (void *)user->uwas,
				user->joined, user->refcnt,
				(void *)user->bcptr,
				(user->bcptr) ? user->bcptr->name :"none");
#ifdef DEBUGMODE
			dumpcore("%p user (%s!%s@%s) %s",
				(void *)cptr, cptr ? cptr->name : "<noname>",
				user->username, user->host, buf);
#else
			sendto_flag(SCH_ERROR,
				"* %p user (%s!%s@%s) %s *",
				(void *)cptr, cptr ? cptr->name : "<noname>",
				user->username, user->host, buf);
#endif
		}

		if ((serv = user->servp))
		{
			user->servp = NULL; /* to avoid some impossible loop */
			user->refcnt = -211000; /* For loop detection */
			free_server(serv);
		}

		if (user->away)
		{
			istat.is_away--;
			istat.is_awaymem -= (strlen(user->away) + 1);
			MyFree(user->away);
		}
		MyFree(user);
#ifdef	DEBUGMODE
		users.inuse--;
#endif
	    }
}
Beispiel #20
0
Datei: send.c Projekt: ahf/irc
/*
** send_message
**	Internal utility which delivers one message buffer to the
**	socket. Takes care of the error handling and buffering, if
**	needed.
**	if ZIP_LINKS is defined, the message will eventually be compressed,
**	anything stored in the sendQ is compressed.
**
**	If msg is a null pointer, we are flushing connection
*/
int	send_message(aClient *to, char *msg, int len)
{
	int i;

	Debug((DEBUG_SEND,"Sending %s %d [%s] ", to->name, to->fd, msg));

	if (to->from)
		to = to->from;
	if (to->fd < 0)
	    {
		Debug((DEBUG_ERROR,
		       "Local socket %s with negative fd... AARGH!",
		      to->name));
	    }
	if (IsMe(to))
	    {
		sendto_flag(SCH_ERROR, "Trying to send to myself! [%s]", msg);
		return 0;
	    }
	if (IsDead(to))
		return 0; /* This socket has already been marked as dead */
	if (DBufLength(&to->sendQ) > (i=get_sendq(to, CBurst(to))))
	{
		to->exitc = EXITC_SENDQ;
		if (IsService(to) || IsServer(to))
		{
			return dead_link(to,
				"Max SendQ limit exceeded for %s: %d > %d",
				get_client_name(to, FALSE),
				DBufLength(&to->sendQ), i);
		}
		return dead_link(to, "Max Sendq exceeded");
	}
# ifdef	ZIP_LINKS
	/*
	** data is first stored in to->zip->outbuf until
	** it's big enough to be compressed and stored in the sendq.
	** send_queued is then responsible to never let the sendQ
	** be empty and to->zip->outbuf not empty.
	*/
	if (to->flags & FLAGS_ZIP)
		msg = zip_buffer(to, msg, &len, 0);

# endif	/* ZIP_LINKS */
tryagain:
	if (len && (i = dbuf_put(&to->sendQ, msg, len)) < 0)
	{
		if (i == -2	/* Poolsize was exceeded. */
#ifdef POOLSIZE_LIMITED
			/*
			** Defining this retains old ircd behaviour (will
			** allow client quit with buffer allocation error
			** as a result of poolsize starvation). As it may
			** happen to all clients on a big channel without
			** their fault, I think this is not right.
			** In the long run it should not matter (poolsize
			** or memory usage-wise), because if client lacks
			** the poolsize, the poolsize is too small anyway
			** and next netburst would probably make it grow.
			** IMO increasing poolsize with no limits is good
			** for clients -- hence this is not defined. --B.
			*/
			&& CBurst(to)
#endif
			)
		{
			/* Anyway, 10% increase. */
			poolsize *= 1.1;
			sendto_flag(SCH_NOTICE,
				    "New poolsize %u. (reached)",
				    poolsize);
			istat.is_dbufmore++;
			goto tryagain;
		}
		else
		{
			to->exitc = EXITC_MBUF;
			return dead_link(to,
				"Buffer allocation error for %s",
				get_client_name(to, FALSE));
		}
	}
	/*
	** Update statistics. The following is slightly incorrect
	** because it counts messages even if queued, but bytes
	** only really sent. Queued bytes get updated in SendQueued.
	*/
	to->sendM += 1;
	me.sendM += 1;
	if (to->acpt != &me)
		to->acpt->sendM += 1;
	/*
	** This little bit is to stop the sendQ from growing too large when
	** there is no need for it to. Thus we call send_queued() every time
	** 2k has been added to the queue since the last non-fatal write.
	** Also stops us from deliberately building a large sendQ and then
	** trying to flood that link with data (possible during the net
	** relinking done by servers with a large load).
	*/
	if (DBufLength(&to->sendQ)/1024 > to->lastsq)
		send_queued(to);
	return 0;
}
Beispiel #21
0
void	outofmemory()
{
	Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
	sendto_flag(SCH_NOTICE, "Ouch!!! Out of memory...");
	restart("Out of Memory");
}
Beispiel #22
0
/*
 * read_iauth
 *
 *	read and process data from the authentication slave process.
 */
void	read_iauth(void)
{
    static char obuf[READBUF_SIZE+1], last = '?';
    static int olen = 0, ia_dbg = 0;
    char buf[READBUF_SIZE+1], *start, *end, tbuf[BUFSIZ];
    aClient *cptr;
    int i;

    if (adfd == -1)
	{
	    olen = 0;
	    return;
	}
    while (1)
	{
	    if (olen)
		    bcopy(obuf, buf, olen);
	    if ((i = recv(adfd, buf+olen, READBUF_SIZE-olen, 0)) <= 0)
		{
		    if (errno != EAGAIN && errno != EWOULDBLOCK)
			{
			    sendto_flag(SCH_AUTH, "Aiiie! lost slave authentication process (errno = %d)", errno);
			    close(adfd);
			    adfd = -1;
			    olen = 0;
			    start_iauth(0);
			}
		    break;
		}
	    olen += i;
	    buf[olen] = '\0';
	    start = buf;
	    while ((end = index(start, '\n')))
		{
		    *end++ = '\0';
		    last = *start;
		    if (*start == '>')
			{
			    sendto_flag(SCH_AUTH, "%s", start+1);
			    start = end;
			    continue;
			}
		    if (*start == 'G')
			{
			    ia_dbg = atoi(start+2);
			    if (ia_dbg)
				    sendto_flag(SCH_AUTH,"ia_dbg = %d",ia_dbg);
			    start = end;
			    continue;
			}
		    if (*start == 'O') /* options */
			{
			    iauth_options = 0;
			    if (strchr(start+2, 'A'))
				    iauth_options |= XOPT_EARLYPARSE;
			    if (strchr(start+2, 'R'))
				    iauth_options |= XOPT_REQUIRED;
			    if (strchr(start+2, 'T'))
				    iauth_options |= XOPT_NOTIMEOUT;
			    if (strchr(start+2, 'W'))
				    iauth_options |= XOPT_EXTWAIT;
			    if (iauth_options)
				    sendto_flag(SCH_AUTH, "iauth options: %x",
						iauth_options);
			    start = end;
			    continue;
			}
		    if (*start == 'V') /* version */
			{
			    if (iauth_version)
				    MyFree(iauth_version);
			    iauth_version = mystrdup(start+2);
			    sendto_flag(SCH_AUTH, "iauth version %s running.",
					iauth_version);
			    start = end;
			    sendto_iauth("0 M %s", me.name);
			    continue;
			}
		    if (*start == 'a')
			{
			    aExtCf *ectmp;

			    while ((ectmp = iauth_conf))
				{
				    iauth_conf = iauth_conf->next;
				    MyFree(ectmp->line);
				    MyFree(ectmp);
				}
			    /* little lie.. ;) */
			    sendto_flag(SCH_AUTH, "New iauth configuration.");
			    start = end;
			    continue;
			}
		    if (*start == 'A')
			{
			    aExtCf **ectmp = &iauth_conf;

			    while (*ectmp)
				    ectmp = &((*ectmp)->next);
			    *ectmp = (aExtCf *) MyMalloc(sizeof(aExtCf));
			    (*ectmp)->line = mystrdup(start+2);
			    (*ectmp)->next = NULL;
			    start = end;
			    continue;
			}
		    if (*start == 's')
			{
			    aExtData *ectmp;

			    while ((ectmp = iauth_stats))
				{
				    iauth_stats = iauth_stats->next;
				    MyFree(ectmp->line);
				    MyFree(ectmp);
				}
			    iauth_stats = (aExtData *)
				    MyMalloc(sizeof(aExtData));
			    iauth_stats->line = MyMalloc(60);
			    sprintf(iauth_stats->line,
				    "iauth modules statistics (%s)",
				    myctime(timeofday));
			    iauth_stats->next = (aExtData *)
				    MyMalloc(sizeof(aExtData));
			    iauth_stats->next->line = MyMalloc(60);
			    sprintf(iauth_stats->next->line,
				    "spawned: %d, current options: %X (%.11s)",
				    iauth_spawn, iauth_options,
				    (iauth_version) ? iauth_version : "???");
			    iauth_stats->next->next = NULL;
			    start = end;
			    continue;
			}
		    if (*start == 'S')
			{
			    aExtData **ectmp = &iauth_stats;

			    while (*ectmp)
				    ectmp = &((*ectmp)->next);
			    *ectmp = (aExtData *) MyMalloc(sizeof(aExtData));
			    (*ectmp)->line = mystrdup(start+2);
			    (*ectmp)->next = NULL;
			    start = end;
			    continue;
			}
		    if (*start != 'U' && *start != 'u' && *start != 'o' &&
			*start != 'K' && *start != 'k' &&
			*start != 'D')
			{
			    sendto_flag(SCH_AUTH, "Garbage from iauth [%s]",
					start);
			    sendto_iauth("-1 E Garbage [%s]", start);
			    /*
			    ** The above should never happen, but i've seen it
			    ** occasionnally, so let's try to get more info
			    ** about it! -kalt
			    */
			    sendto_flag(SCH_AUTH,
				"last=%u start=%x end=%x buf=%x olen=%d i=%d",
					last, start, end, buf, olen, i);
			    sendto_iauth(
			 "-1 E last=%u start=%x end=%x buf=%x olen=%d i=%d",
			 		last, start, end, buf, olen, i);
			    start = end;
			    continue;
			}
		    if ((cptr = local[i = atoi(start+2)]) == NULL)
			{
			    /* this is fairly common and can be ignored */
			    if (ia_dbg)
				{
				    sendto_flag(SCH_AUTH, "Client %d is gone.",
						i);
				    sendto_iauth("%d E Gone [%s]", i, start);
				}
			    start = end;
			    continue;
			}
#ifndef	INET6
		    sprintf(tbuf, "%c %d %s %u ", start[0], i,
			    inetntoa((char *)&cptr->ip), cptr->port);
#else
		    sprintf(tbuf, "%c %d %s %u ", start[0], i,
			    inetntop(AF_INET6, (char *)&cptr->ip, 
			    ipv6string, sizeof(ipv6string)), cptr->port);
#endif
		    if (strncmp(tbuf, start, strlen(tbuf)))
			{
			    /* this is fairly common and can be ignored */
			    if (ia_dbg)
				{
				    sendto_flag(SCH_AUTH,
					"Client mismatch: %d [%s] != [%s]",
						i, start, tbuf);
				    sendto_iauth("%d E Mismatch [%s] != [%s]",
						 i, start, tbuf);
				}
			    start = end;
			    continue;
			}
		    if (start[0] == 'U')
			{
			    if (*(start+strlen(tbuf)) == '\0')
				{
				    sendto_flag(SCH_AUTH,
						"Null U message! %d [%s]",
						i, start);
				    sendto_iauth("%d E Null U [%s]", i, start);
				    start = end;
				    continue;
				}
			    if (cptr->auth != cptr->username)
				{   
				    istat.is_authmem -= strlen(cptr->auth) + 1;
				    istat.is_auth -= 1;
				    MyFree(cptr->auth);
				}
			    cptr->auth = mystrdup(start+strlen(tbuf));
			    set_clean_username(cptr);
			    cptr->flags |= FLAGS_GOTID;
			}
		    else if (start[0] == 'u')
			{
			    if (*(start+strlen(tbuf)) == '\0')
				{
				    sendto_flag(SCH_AUTH,
						"Null u message! %d [%s]",
						i, start);
				    sendto_iauth("%d E Null u [%s]", i, start);
				    start = end;
				    continue;
				}
			    if (cptr->auth != cptr->username)
				{
				    istat.is_authmem -= strlen(cptr->auth) + 1;
				    istat.is_auth -= 1;
				    MyFree(cptr->auth);
				}
			    cptr->auth = MyMalloc(strlen(start+strlen(tbuf))
						  + 2);
			    *cptr->auth = '-';
			    strcpy(cptr->auth+1, start+strlen(tbuf));
			    set_clean_username(cptr);
			    cptr->flags |= FLAGS_GOTID;
			}
		    else if (start[0] == 'o')
			{
			    if (!WaitingXAuth(cptr))
				{
				    sendto_flag(SCH_AUTH,
						"Early o message discarded!");
				    sendto_iauth("%d E Early o [%s]", i,start);
				    start = end;
				    continue;
				}
			    if (cptr->user == NULL)
				{
				    /* just to be safe */
				    sendto_flag(SCH_AUTH,
						"Ack! cptr->user is NULL");
				    start = end;
				    continue;
				}
			    strncpyzt(cptr->user->username, tbuf, USERLEN+1);
			}
		    else if (start[0] == 'D')
		      {
			    /*authentication finished*/
			    ClearXAuth(cptr);
			    SetDoneXAuth(cptr);
			    if (WaitingXAuth(cptr))
				{
				    ClearWXAuth(cptr);
				    register_user(cptr, cptr, cptr->name,
						  cptr->user->username);
				}
			    else
				    ClearWXAuth(cptr);
		      }
		    else
			{
			    char *reason;

			    /* Copy kill reason received from iauth */
			    reason = strstr(start, " :");
			    if (reason && (reason + 2 != '\0'))
			    {
				    if (cptr->reason)
				    {
					    MyFree(cptr->reason);
				    }
				    cptr->reason = mystrdup(reason + 2);
			    }
			    /*
			    ** mark for kill, because it cannot be killed
			    ** yet: we don't even know if this is a server
			    ** or a user connection!
			    */
			    if (start[0] == 'K')
				    cptr->exitc = EXITC_AREF;
			    else
				    cptr->exitc = EXITC_AREFQ;
			    /* should also check to make sure it's still
			       an unregistered client.. */

			    /* Finally, working after registration. --B. */
			    if (IsRegisteredUser(cptr))
			    {
                        	if (cptr->exitc == EXITC_AREF)
				{
					sendto_flag(SCH_LOCAL,
                                		"Denied after connection "
						"from %s.",
						get_client_host(cptr));
				}
                        	(void) exit_client(cptr, cptr, &me,
					cptr->reason ? cptr->reason :
					"Denied access");
			    }
			}
		    start = end;
		}
	    olen -= start - buf;
	    if (olen)
		    memcpy(obuf, start, olen);
	}
}