Esempio n. 1
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;
}
Esempio n. 2
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);
}
Esempio n. 3
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);
	}
}