/************************************************************************
* IRC - Internet Relay Chat, server/s_conf.c
* Copyright (C) 1990 Jarkko Oikarinen and
* University of Oulu, Computing Center
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* (C) 1988 University of Oulu,Computing Center and Jarkko Oikarinen"
*
*/
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "tools.h"
#include "channel.h"
#include "class.h"
#include "event.h"
#include "listener.h"
#include "modules.h"
#include "numeric.h"
#include "fd.h"
#include "s_bsd.h"
#include "s_conf.h"
#include "throttle.h"
#include "fileio.h"
#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned int) 0xffffffff)
#endif
/* internally defined functions */
char conf_line_in[256];
static int attach_iline(struct Client *, struct ConfItem *);
int attach_Iline(struct Client *client_p, char *username);
/*
* conf_dns_callback - called when resolver query finishes
* if the query resulted in a successful search, hp will contain
* a non-null pointer, otherwise hp will be null.
* if successful save hp in the conf item it was called with
*/
static void conf_dns_callback(void *vptr, adns_answer * reply)
{
struct ConfItem *aconf = (struct ConfItem *) vptr;
if (reply && reply->status == adns_s_ok) {
#ifdef IPV6
copy_s_addr(IN_ADDR(aconf->ipnum), reply->rrs.addr->addr.inet6.sin6_addr.s6_addr);
#else
copy_s_addr(IN_ADDR(aconf->ipnum), reply->rrs.addr->addr.inet.sin_addr.s_addr);
#endif
MyFree(reply);
}
MyFree(aconf->dns_query);
aconf->dns_query = NULL;
}
/*
* conf_dns_lookup - do a nameserver lookup of the conf host
* if the conf entry is currently doing a ns lookup do nothing, otherwise
* set the conf_dns_pending flag
*/
static void conf_dns_lookup(struct ConfItem *aconf)
{
if (aconf->dns_query == NULL) {
aconf->dns_query = MyMalloc(sizeof(struct DNSQuery));
aconf->dns_query->ptr = aconf;
aconf->dns_query->callback = conf_dns_callback;
adns_gethost(aconf->host, aconf->aftype, aconf->dns_query);
}
}
/*
* check_client
*
* inputs - pointer to client
* output - 0 = Success
* NOT_AUTHORIZED (-1) = Access denied (no I line match)
* SOCKET_ERROR (-2) = Bad socket.
* I_LINE_FULL (-3) = I-line is full
* TOO_MANY (-4) = Too many connections from hostname
* BANNED_CLIENT (-5) = K-lined
* side effects - Ordinary client access check.
* Look for conf lines which have the same
* status as the flags passed.
*/
int check_client(struct Client *client_p, struct Client *source_p, char *username)
{
int i;
ClearAccess(source_p);
i = attach_Iline(source_p, username);
switch (i) {
case SOCKET_ERROR:
exit_client(source_p, &me, "Socket Error");
break;
case TOO_MANY:
sendto_lev(SNOTICE_LEV, "Too many connections on IP from %s (%s).",
get_client_name(source_p, FALSE), source_p->sockhost);
ircstp->is_ref++;
exit_client(source_p, &me, "No more connections allowed on that IP");
break;
case I_LINE_FULL:
sendto_lev(SNOTICE_LEV,
"I-line is full for %s (%s).",
get_client_name(source_p, FALSE), source_p->sockhost);
ircstp->is_ref++;
exit_client(source_p, &me,
"No more connections allowed in your connection class");
break;
case INVALID_CONNECTION:
sendto_lev(REJ_LEV, "Unauthorized client connection from %~C on non-client port", source_p);
exit_client(source_p, &me, "You are not authorized to use this port");
break;
case NOT_AUTHORIZED:
{
static char ipaddr[HOSTIPLEN];
ircstp->is_ref++;
/* jdc - lists server name & port connections are on */
/* a purely cosmetical change */
inetntop(source_p->aftype, &IN_ADDR(source_p->ip), ipaddr, HOSTIPLEN);
sendto_lev(REJ_LEV,
"Unauthorised client connection from %s [%s] on [%s/%u].",
get_client_name(source_p, FALSE), ipaddr,
source_p->listener->name, source_p->listener->port);
exit_client(source_p, &me,
"You are not authorized to use this server");
break;
}
case BANNED_CLIENT:
exit_client(client_p, &me, "*** Banned ");
ircstp->is_ref++;
break;
case 0:
default:
break;
}
return (i);
}
/*
* attach_Iline
*
* inputs -
* output -
* side effect - find the first (best) I line to attach.
*/
int attach_Iline(struct Client *client_p, char *username)
{
struct ConfItem *aconf;
aconf = find_conf_for_client(client_p, CONF_CLIENT, 1);
if (aconf == NULL)
aconf = find_conf_for_client(client_p, CONF_CLIENT, 0);
if (aconf != NULL) {
if (aconf->status & CONF_CLIENT) {
if (aconf->flags & CONF_FLAGS_REDIR) {
send_me_numeric(client_p, RPL_REDIR, aconf->name ? aconf->name : "", aconf->port);
return NOT_AUTHORIZED;
}
if (find_connection_kill_level(client_p, username) != 0)
return BANNED_CLIENT;
return (attach_iline(client_p, aconf));
}
}
return NOT_AUTHORIZED;
}
/*
* attach_iline
*
* inputs - client pointer
* - conf pointer
* output -
* side effects -
*/
static int attach_iline(struct Client *client_p, struct ConfItem *aconf)
{
int f = aconf->class->links;
f++;
/* only check it if its non zero */
if (f > aconf->class->max_connections) {
if (!IsConfExemptLimits(aconf))
return TOO_MANY; /* Already at maximum allowed ip#'s */
else {
send_me_notice(client_p, ":*** :I: line is full, but you have an >I: line!");
}
}
if (!IsListenerClient(client_p->listener))
return INVALID_CONNECTION;
return (attach_conf(client_p, aconf));
}
/*
* attach_cn_lines
*
* inputs - pointer to server to attach c/ns to
* - name of server
* - hostname of server
* output - true (1) if both are found, otherwise return false (0)
* side effects -
* attach_cn_lines - find C/N lines and attach them to connecting client
* NOTE: this requires an exact match between the name on the C:line and
* the name on the N:line
* C/N lines are completely gone now, the name exists only for historical
* reasons - A1kmm.
*/
int attach_cn_lines(struct Client *client_p, char *name, char *host)
{
struct ConfItem *ptr;
int tmp = 0;
assert(0 != client_p);
assert(0 != host);
for (ptr = GlobalConfItemList; ptr; ptr = ptr->next) {
if (IsIllegal(ptr))
continue;
if (!(ptr->status & CONF_SERVER))
continue;
if (match(ptr->name, name) || match(ptr->host, host))
continue;
attach_conf(client_p, ptr);
tmp = 1;
}
return tmp;
}
/*
* SplitUserHost
*
* inputs - struct ConfItem pointer
* output - return 1/0 true false or -1 for error
* side effects - splits user@host found in a name field of conf given
* stuff the user into ->user and the host into ->host
*/
static int SplitUserHost(struct ConfItem *aconf)
{
char *p;
char *new_user;
char *new_host;
if ((p = strchr(aconf->host, '@'))) {
*p = '\0';
DupString(new_user, aconf->host);
MyFree(aconf->user);
aconf->user = new_user;
p++;
DupString(new_host, p);
MyFree(aconf->host);
aconf->host = new_host;
} else {
DupString(aconf->user, "*");
}
return (1);
}
/*
* lookup_confhost - start DNS lookups of all hostnames in the conf
* line and convert an IP addresses in a.b.c.d number for to IP#s.
*
*/
void lookup_confhost(struct ConfItem *aconf)
{
if (BadPtr(aconf->host) || BadPtr(aconf->name)) {
sendto_lev(DEBUG_LEV, "Host/server name error: (%s) (%s)", aconf->host, aconf->name);
return;
}
if (strchr(aconf->host, '*') || strchr(aconf->host, '?'))
return;
/*
* ** Do name lookup now on hostnames given and store the
* ** ip numbers in conf structure.
*/
if (inetpton(DEF_FAM, aconf->host, &IN_ADDR(aconf->ipnum)) <= 0)
conf_dns_lookup(aconf);
}
/*
* flush_deleted_I_P
*
* inputs - none
* output - none
* side effects - This function removes I/P conf items
*/
void flush_deleted_I_P(void)
{
struct ConfItem **tmp = &GlobalConfItemList;
struct ConfItem *tmp2;
/*
* flush out deleted I and P lines although still in use.
*/
for (tmp = &GlobalConfItemList; (tmp2 = *tmp);) {
if (!(tmp2->status & CONF_ILLEGAL))
tmp = &tmp2->next;
else {
*tmp = tmp2->next;
tmp2->next = NULL;
if (!tmp2->clients)
free_conf(tmp2);
}
}
}
#define MAXCONFLINKS 150
/*
* conf_add_conf
* Inputs - ConfItem
* Output - none
* Side effects - add given conf to link list
*/
void conf_add_conf(struct ConfItem *aconf)
{
(void) collapse(aconf->host);
(void) collapse(aconf->user);
logevent_call(LogSys.add_confline,
aconf->status,
aconf->host ? aconf->host : "<NULL>",
aconf->passwd ? aconf->passwd : "<NULL>",
aconf->user ? aconf->user : "<NULL>", aconf->port);
aconf->next = GlobalConfItemList;
GlobalConfItemList = aconf;
}
/*
* conf_add_class_to_conf
* inputs - pointer to config item
* output - NONE
* side effects - Add a class pointer to a conf
*/
void conf_add_class_to_conf(struct ConfItem *aconf)
{
if (aconf->class == 0) {
aconf->class = find_class(0);
return;
}
if (aconf->class->max_connections < 0) {
aconf->class = find_class(0);
return;
}
}
/*
* conf_add_server
*
* inputs - pointer to config item
* - pointer to link count already on this conf
* output - NONE
* side effects - Add a connect block
*/
int conf_add_server(struct ConfItem *aconf, int lcount)
{
conf_add_class_to_conf(aconf);
if (lcount > MAXCONFLINKS || !aconf->host || !aconf->name) {
logevent_call(LogSys.bad_connect, "No-NAME");
return -1;
}
if (SplitUserHost(aconf) < 0) {
logevent_call(LogSys.bad_connect, aconf->name);
return -1;
}
lookup_confhost(aconf);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1