1439 lines
35 KiB
C
1439 lines
35 KiB
C
/************************************************************************
|
|
* IRC - Internet Relay Chat, ircd/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 1, 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.
|
|
*/
|
|
|
|
/* -- avalon -- 20 Feb 1992
|
|
* Reversed the order of the params for attach_conf().
|
|
* detach_conf() and attach_conf() are now the same:
|
|
* function_conf(aClient *, aConfItem *)
|
|
*/
|
|
|
|
/* -- Jto -- 20 Jun 1990
|
|
* Added gruner's overnight fix..
|
|
*/
|
|
|
|
/* -- Jto -- 16 Jun 1990
|
|
* Moved matches to ../common/match.c
|
|
*/
|
|
|
|
/* -- Jto -- 03 Jun 1990
|
|
* Added Kill fixes from gruner@lan.informatik.tu-muenchen.de
|
|
* Added jarlek's msgbase fix (I still don't understand it... -- Jto)
|
|
*/
|
|
|
|
/* -- Jto -- 13 May 1990
|
|
* Added fixes from msa:
|
|
* Comments and return value to init_conf()
|
|
*/
|
|
|
|
/*
|
|
* -- Jto -- 12 May 1990
|
|
* Added close() into configuration file (was forgotten...)
|
|
*/
|
|
|
|
#ifndef lint
|
|
static char sccsid[] = "@(#)s_conf.c 2.56 02 Apr 1994 (C) 1988 University of Oulu, \
|
|
Computing Center and Jarkko Oikarinen";
|
|
#endif
|
|
|
|
#include "struct.h"
|
|
#include "common.h"
|
|
#include "sys.h"
|
|
#include "numeric.h"
|
|
#include <sys/socket.h>
|
|
#include <fcntl.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#ifdef __hpux
|
|
#include "inet.h"
|
|
#endif
|
|
#if defined(PCS) || defined(AIX) || defined(DYNIXPTX) || defined(SVR3)
|
|
#include <time.h>
|
|
#endif
|
|
#ifdef R_LINES
|
|
#include <signal.h>
|
|
#endif
|
|
|
|
#include "h.h"
|
|
|
|
static int check_time_interval PROTO((char *, char *));
|
|
static int lookup_confhost PROTO((aConfItem *));
|
|
static int is_comment PROTO((char *));
|
|
|
|
aConfItem *conf = NULL;
|
|
aGline *gline = NULL;
|
|
|
|
/*
|
|
* remove all conf entries from the client except those which match
|
|
* the status field mask.
|
|
*/
|
|
void det_confs_butmask(cptr, mask)
|
|
aClient *cptr;
|
|
int mask;
|
|
{
|
|
Reg1 Link *tmp, *tmp2;
|
|
|
|
for (tmp = cptr->confs; tmp; tmp = tmp2)
|
|
{
|
|
tmp2 = tmp->next;
|
|
if ((tmp->value.aconf->status & mask) == 0)
|
|
(void)detach_conf(cptr, tmp->value.aconf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* find the first (best) I line to attach.
|
|
*/
|
|
int attach_Iline(cptr, hp, sockhost)
|
|
aClient *cptr;
|
|
Reg2 struct hostent *hp;
|
|
char *sockhost;
|
|
{
|
|
Reg1 aConfItem *aconf;
|
|
Reg3 const char *hname;
|
|
Reg4 int i;
|
|
static char uhost[HOSTLEN+USERLEN+3];
|
|
static char fullname[HOSTLEN+1];
|
|
|
|
for (aconf = conf; aconf; aconf = aconf->next)
|
|
{
|
|
if (aconf->status != CONF_CLIENT)
|
|
continue;
|
|
if (aconf->port && aconf->port != cptr->acpt->port)
|
|
continue;
|
|
if (!aconf->host || !aconf->name)
|
|
goto attach_iline;
|
|
if (hp)
|
|
for (i = 0, hname = hp->h_name; hname;
|
|
hname = hp->h_aliases[i++])
|
|
{
|
|
(void)strncpy(fullname, hname,
|
|
sizeof(fullname)-1);
|
|
add_local_domain(fullname,
|
|
HOSTLEN - strlen(fullname));
|
|
Debug((DEBUG_DNS, "a_il: %s->%s",
|
|
sockhost, fullname));
|
|
if (index(aconf->name, '@'))
|
|
{
|
|
(void)strcpy(uhost, cptr->username);
|
|
(void)strcat(uhost, "@");
|
|
}
|
|
else
|
|
*uhost = '\0';
|
|
(void)strncat(uhost, fullname,
|
|
sizeof(uhost) - strlen(uhost));
|
|
if (!match(aconf->name, uhost))
|
|
goto attach_iline;
|
|
}
|
|
|
|
if (index(aconf->host, '@'))
|
|
{
|
|
strncpyzt(uhost, cptr->username, sizeof(uhost));
|
|
(void)strcat(uhost, "@");
|
|
}
|
|
else
|
|
*uhost = '\0';
|
|
(void)strncat(uhost, sockhost, sizeof(uhost) - strlen(uhost));
|
|
if (!match(aconf->host, uhost))
|
|
goto attach_iline;
|
|
continue;
|
|
attach_iline:
|
|
if (index(uhost, '@'))
|
|
cptr->flags |= FLAGS_DOID;
|
|
get_sockhost(cptr, uhost);
|
|
|
|
if (aconf->passwd && !strcmp(aconf->passwd, "ONE"))
|
|
{
|
|
for (i = highest_fd; i >= 0; i--)
|
|
if (local[i] && MyClient(local[i]) &&
|
|
local[i]->ip.s_addr == cptr->ip.s_addr)
|
|
return -1; /* Already got one with that ip# */
|
|
}
|
|
return attach_conf(cptr, aconf);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Find the single N line and return pointer to it (from list).
|
|
* If more than one then return NULL pointer.
|
|
*/
|
|
aConfItem *count_cnlines(lp)
|
|
Reg1 Link *lp;
|
|
{
|
|
Reg1 aConfItem *aconf, *cline = NULL, *nline = NULL;
|
|
|
|
for (; lp; lp = lp->next)
|
|
{
|
|
aconf = lp->value.aconf;
|
|
if (!(aconf->status & CONF_SERVER_MASK))
|
|
continue;
|
|
if (aconf->status == CONF_CONNECT_SERVER && !cline)
|
|
cline = aconf;
|
|
else if (aconf->status == CONF_NOCONNECT_SERVER && !nline)
|
|
nline = aconf;
|
|
}
|
|
return nline;
|
|
}
|
|
|
|
/*
|
|
** detach_conf
|
|
** Disassociate configuration from the client.
|
|
** Also removes a class from the list if marked for deleting.
|
|
*/
|
|
int detach_conf(cptr, aconf)
|
|
aClient *cptr;
|
|
aConfItem *aconf;
|
|
{
|
|
Reg1 Link **lp, *tmp;
|
|
|
|
lp = &(cptr->confs);
|
|
|
|
while (*lp)
|
|
{
|
|
if ((*lp)->value.aconf == aconf)
|
|
{
|
|
if ((aconf) && (Class(aconf)))
|
|
{
|
|
if (aconf->status & CONF_CLIENT_MASK)
|
|
if (ConfLinks(aconf) > 0)
|
|
--ConfLinks(aconf);
|
|
if (ConfMaxLinks(aconf) == -1 &&
|
|
ConfLinks(aconf) == 0)
|
|
{
|
|
free_class(Class(aconf));
|
|
Class(aconf) = NULL;
|
|
}
|
|
}
|
|
if (aconf && !--aconf->clients && IsIllegal(aconf))
|
|
free_conf(aconf);
|
|
tmp = *lp;
|
|
*lp = tmp->next;
|
|
free_link(tmp);
|
|
return 0;
|
|
}
|
|
else
|
|
lp = &((*lp)->next);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int is_attached(aconf, cptr)
|
|
aConfItem *aconf;
|
|
aClient *cptr;
|
|
{
|
|
Reg1 Link *lp;
|
|
|
|
for (lp = cptr->confs; lp; lp = lp->next)
|
|
if (lp->value.aconf == aconf)
|
|
break;
|
|
|
|
return (lp) ? 1 : 0;
|
|
}
|
|
|
|
/*
|
|
** attach_conf
|
|
** Associate a specific configuration entry to a *local*
|
|
** client (this is the one which used in accepting the
|
|
** connection). Note, that this automaticly changes the
|
|
** attachment if there was an old one...
|
|
*/
|
|
int attach_conf(cptr, aconf)
|
|
aConfItem *aconf;
|
|
aClient *cptr;
|
|
{
|
|
Reg1 Link *lp;
|
|
|
|
if (is_attached(aconf, cptr))
|
|
return 1;
|
|
if (IsIllegal(aconf))
|
|
return -1;
|
|
if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT)) &&
|
|
ConfLinks(aconf) >= ConfMaxLinks(aconf) && ConfMaxLinks(aconf) > 0)
|
|
return -3; /* Use this for printing error message */
|
|
lp = make_link();
|
|
lp->next = cptr->confs;
|
|
lp->value.aconf = aconf;
|
|
cptr->confs = lp;
|
|
aconf->clients++;
|
|
if (aconf->status & CONF_CLIENT_MASK)
|
|
ConfLinks(aconf)++;
|
|
return 0;
|
|
}
|
|
|
|
|
|
aConfItem *find_admin()
|
|
{
|
|
Reg1 aConfItem *aconf;
|
|
|
|
for (aconf = conf; aconf; aconf = aconf->next)
|
|
if (aconf->status & CONF_ADMIN)
|
|
break;
|
|
|
|
return (aconf);
|
|
}
|
|
|
|
aConfItem *find_me()
|
|
{
|
|
Reg1 aConfItem *aconf;
|
|
for (aconf = conf; aconf; aconf = aconf->next)
|
|
if (aconf->status & CONF_ME)
|
|
break;
|
|
|
|
return (aconf);
|
|
}
|
|
|
|
/*
|
|
* attach_confs
|
|
* Attach a CONF line to a client if the name passed matches that for
|
|
* the conf file (for non-C/N lines) or is an exact match (C/N lines
|
|
* only). The difference in behaviour is to stop C:*::* and N:*::*.
|
|
*/
|
|
aConfItem *attach_confs(cptr, name, statmask)
|
|
aClient *cptr;
|
|
const char *name;
|
|
int statmask;
|
|
{
|
|
Reg1 aConfItem *tmp;
|
|
aConfItem *first = NULL;
|
|
int len = strlen(name);
|
|
|
|
if (!name || len > HOSTLEN)
|
|
return NULL;
|
|
for (tmp = conf; tmp; tmp = tmp->next)
|
|
{
|
|
if ((tmp->status & statmask) && !IsIllegal(tmp) &&
|
|
((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0) &&
|
|
tmp->name && !match(tmp->name, name))
|
|
{
|
|
if (!attach_conf(cptr, tmp) && !first)
|
|
first = tmp;
|
|
}
|
|
else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
|
|
(tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
|
|
tmp->name && !mycmp(tmp->name, name))
|
|
{
|
|
if (!attach_conf(cptr, tmp) && !first)
|
|
first = tmp;
|
|
}
|
|
}
|
|
return (first);
|
|
}
|
|
|
|
/*
|
|
* Added for new access check meLazy
|
|
*/
|
|
aConfItem *attach_confs_host(cptr, host, statmask)
|
|
aClient *cptr;
|
|
char *host;
|
|
int statmask;
|
|
{
|
|
Reg1 aConfItem *tmp;
|
|
aConfItem *first = NULL;
|
|
int len = strlen(host);
|
|
|
|
if (!host || len > HOSTLEN)
|
|
return NULL;
|
|
|
|
for (tmp = conf; tmp; tmp = tmp->next)
|
|
{
|
|
if ((tmp->status & statmask) && !IsIllegal(tmp) &&
|
|
(tmp->status & CONF_SERVER_MASK) == 0 &&
|
|
(!tmp->host || match(tmp->host, host) == 0))
|
|
{
|
|
if (!attach_conf(cptr, tmp) && !first)
|
|
first = tmp;
|
|
}
|
|
else if ((tmp->status & statmask) && !IsIllegal(tmp) &&
|
|
(tmp->status & CONF_SERVER_MASK) &&
|
|
(tmp->host && mycmp(tmp->host, host) == 0))
|
|
{
|
|
if (!attach_conf(cptr, tmp) && !first)
|
|
first = tmp;
|
|
}
|
|
}
|
|
return (first);
|
|
}
|
|
|
|
/*
|
|
* find a conf entry which matches the hostname and has the same name.
|
|
*/
|
|
aConfItem *find_conf_exact(name, user, host, statmask)
|
|
char *name, *host, *user;
|
|
int statmask;
|
|
{
|
|
Reg1 aConfItem *tmp;
|
|
char userhost[USERLEN+HOSTLEN+3];
|
|
|
|
(void)sprintf(userhost, "%s@%s", user, host);
|
|
|
|
for (tmp = conf; tmp; tmp = tmp->next)
|
|
{
|
|
if (!(tmp->status & statmask) || !tmp->name || !tmp->host ||
|
|
mycmp(tmp->name, name))
|
|
continue;
|
|
/*
|
|
** Accept if the *real* hostname (usually sockecthost)
|
|
** socket host) matches *either* host or name field
|
|
** of the configuration.
|
|
*/
|
|
if (match(tmp->host, userhost))
|
|
continue;
|
|
if (tmp->status & (CONF_OPERATOR|CONF_LOCOP))
|
|
{
|
|
if (tmp->clients < MaxLinks(Class(tmp)))
|
|
return tmp;
|
|
else
|
|
continue;
|
|
}
|
|
else
|
|
return tmp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
aConfItem *find_conf_name(name, statmask)
|
|
char *name;
|
|
int statmask;
|
|
{
|
|
Reg1 aConfItem *tmp;
|
|
|
|
for (tmp = conf; tmp; tmp = tmp->next)
|
|
{
|
|
/*
|
|
** Accept if the *real* hostname (usually sockecthost)
|
|
** matches *either* host or name field of the configuration.
|
|
*/
|
|
if ((tmp->status & statmask) &&
|
|
(!tmp->name || match(tmp->name, name) == 0))
|
|
return tmp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
aConfItem *find_conf(lp, name, statmask)
|
|
char *name;
|
|
Link *lp;
|
|
int statmask;
|
|
{
|
|
Reg1 aConfItem *tmp;
|
|
int namelen = name ? strlen(name) : 0;
|
|
|
|
if (namelen > HOSTLEN)
|
|
return (aConfItem *) 0;
|
|
|
|
for (; lp; lp = lp->next)
|
|
{
|
|
tmp = lp->value.aconf;
|
|
if ((tmp->status & statmask) &&
|
|
(((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) &&
|
|
tmp->name && !mycmp(tmp->name, name)) ||
|
|
((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0 &&
|
|
tmp->name && !match(tmp->name, name))))
|
|
return tmp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Added for new access check meLazy
|
|
*/
|
|
aConfItem *find_conf_host(lp, host, statmask)
|
|
Reg2 Link *lp;
|
|
char *host;
|
|
Reg3 int statmask;
|
|
{
|
|
Reg1 aConfItem *tmp;
|
|
int hostlen = host ? strlen(host) : 0;
|
|
|
|
if (hostlen > HOSTLEN || BadPtr(host))
|
|
return (aConfItem *)NULL;
|
|
for (; lp; lp = lp->next)
|
|
{
|
|
tmp = lp->value.aconf;
|
|
if (tmp->status & statmask &&
|
|
(!(tmp->status & CONF_SERVER_MASK || tmp->host) ||
|
|
(tmp->host && !match(tmp->host, host))))
|
|
return tmp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* find_conf_ip
|
|
*
|
|
* Find a conf line using the IP# stored in it to search upon.
|
|
* Added 1/8/92 by Avalon.
|
|
*/
|
|
aConfItem *find_conf_ip(lp, ip, user, statmask)
|
|
char *ip, *user;
|
|
Link *lp;
|
|
int statmask;
|
|
{
|
|
Reg1 aConfItem *tmp;
|
|
Reg2 char *s;
|
|
|
|
for (; lp; lp = lp->next)
|
|
{
|
|
tmp = lp->value.aconf;
|
|
if (!(tmp->status & statmask))
|
|
continue;
|
|
s = index(tmp->host, '@');
|
|
*s = '\0';
|
|
if (match(tmp->host, user))
|
|
{
|
|
*s = '@';
|
|
continue;
|
|
}
|
|
*s = '@';
|
|
if (!bcmp((char *)&tmp->ipnum, ip, sizeof(struct in_addr)))
|
|
return tmp;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* find_conf_entry
|
|
*
|
|
* - looks for a match on all given fields.
|
|
*/
|
|
aConfItem *find_conf_entry(aconf, mask)
|
|
aConfItem *aconf;
|
|
u_int mask;
|
|
{
|
|
Reg1 aConfItem *bconf;
|
|
|
|
for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next)
|
|
{
|
|
if (!(bconf->status & mask) || (bconf->port != aconf->port))
|
|
continue;
|
|
|
|
if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) ||
|
|
(BadPtr(aconf->host) && !BadPtr(bconf->host)))
|
|
continue;
|
|
if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host))
|
|
continue;
|
|
|
|
if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) ||
|
|
(BadPtr(aconf->passwd) && !BadPtr(bconf->passwd)))
|
|
continue;
|
|
if (!BadPtr(bconf->passwd) && mycmp(bconf->passwd, "ONE") &&
|
|
mycmp(bconf->passwd, aconf->passwd))
|
|
continue;
|
|
|
|
if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) ||
|
|
(BadPtr(aconf->name) && !BadPtr(bconf->name)))
|
|
continue;
|
|
if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name))
|
|
continue;
|
|
break;
|
|
}
|
|
return bconf;
|
|
}
|
|
|
|
/*
|
|
* rehash
|
|
*
|
|
* Actual REHASH service routine. Called with sig == 0 if it has been called
|
|
* as a result of an operator issuing this command, else assume it has been
|
|
* called as a result of the server receiving a HUP signal.
|
|
*/
|
|
int rehash(cptr, sptr, sig)
|
|
aClient *cptr, *sptr;
|
|
int sig;
|
|
{
|
|
Reg1 aConfItem **tmp = &conf, *tmp2;
|
|
Reg2 aClass *cltmp;
|
|
Reg1 aClient *acptr;
|
|
Reg2 int i;
|
|
int ret = 0, found_g;
|
|
|
|
if (sig == 1)
|
|
{
|
|
sendto_ops("Got signal SIGHUP, reloading ircd conf. file");
|
|
#ifdef notdef /* fucking crap --dog3 */
|
|
if (fork() > 0)
|
|
exit(0);
|
|
write_pidfile();
|
|
#endif
|
|
}
|
|
|
|
for (i = 0; i <= highest_fd; i++)
|
|
if ((acptr = local[i]) && !IsMe(acptr))
|
|
{
|
|
/*
|
|
* Nullify any references from client structures to
|
|
* this host structure which is about to be freed.
|
|
* Could always keep reference counts instead of
|
|
* this....-avalon
|
|
*/
|
|
acptr->hostp = NULL;
|
|
}
|
|
|
|
while ((tmp2 = *tmp))
|
|
if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT)
|
|
{
|
|
/*
|
|
** Configuration entry is still in use by some
|
|
** local clients, cannot delete it--mark it so
|
|
** that it will be deleted when the last client
|
|
** exits...
|
|
*/
|
|
if (!(tmp2->status & (CONF_LISTEN_PORT|CONF_CLIENT)))
|
|
{
|
|
*tmp = tmp2->next;
|
|
tmp2->next = NULL;
|
|
}
|
|
else
|
|
tmp = &tmp2->next;
|
|
tmp2->status |= CONF_ILLEGAL;
|
|
}
|
|
else
|
|
{
|
|
*tmp = tmp2->next;
|
|
/* free expression trees of connect rules */
|
|
if ((tmp2->status & (CONF_CRULEALL|CONF_CRULEAUTO))
|
|
&& (tmp2->passwd != NULL))
|
|
crule_free (&(tmp2->passwd));
|
|
free_conf(tmp2);
|
|
}
|
|
|
|
/*
|
|
* We don't delete the class table, rather mark all entries
|
|
* for deletion. The table is cleaned up by check_class. - avalon
|
|
*/
|
|
for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp))
|
|
MaxLinks(cltmp) = -1;
|
|
|
|
if (sig != 2)
|
|
flush_cache();
|
|
(void) initconf(0);
|
|
close_listeners();
|
|
|
|
/*
|
|
* flush out deleted I and P lines although still in use.
|
|
*/
|
|
for (tmp = &conf; (tmp2 = *tmp); )
|
|
if (!(tmp2->status & CONF_ILLEGAL))
|
|
tmp = &tmp2->next;
|
|
else
|
|
{
|
|
*tmp = tmp2->next;
|
|
tmp2->next = NULL;
|
|
if (!tmp2->clients)
|
|
free_conf(tmp2);
|
|
}
|
|
|
|
for (i = 0; i <= highest_fd; i++)
|
|
if ((acptr = local[i]) && !IsMe(acptr))
|
|
{
|
|
if (IsServer(acptr))
|
|
{
|
|
det_confs_butmask(acptr,
|
|
~(CONF_HUB|CONF_LEAF|CONF_UWORLD|CONF_ILLEGAL));
|
|
(void)attach_confs(acptr, acptr->name,
|
|
CONF_HUB|CONF_LEAF|CONF_UWORLD);
|
|
}
|
|
if (found_g = find_kill(acptr))
|
|
{
|
|
sendto_ops(found_g == -2 ? "G-line active for %s" :
|
|
"K-line active for %s",
|
|
get_client_name(acptr,FALSE));
|
|
if (exit_client(cptr, acptr, &me, found_g == -2 ? "G-lined" :
|
|
"K-lined") == CPTR_KILLED)
|
|
ret = CPTR_KILLED;
|
|
}
|
|
#if defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN)
|
|
if (find_restrict(acptr))
|
|
{
|
|
sendto_ops("Restricting %s, closing lp",
|
|
get_client_name(acptr,FALSE));
|
|
if (exit_client(cptr, acptr,&me,"R-lined") == CPTR_KILLED)
|
|
ret = CPTR_KILLED;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* openconf
|
|
*
|
|
* returns -1 on any error or else the fd opened from which to read the
|
|
* configuration file from. This may either be th4 file direct or one end
|
|
* of a pipe from m4.
|
|
*/
|
|
int openconf()
|
|
{
|
|
#ifdef M4_PREPROC
|
|
int pi[2], i;
|
|
|
|
if (pipe(pi) == -1)
|
|
return -1;
|
|
switch(fork())
|
|
{
|
|
case -1 :
|
|
return -1;
|
|
case 0 :
|
|
(void)close(pi[0]);
|
|
if (pi[1] != 1)
|
|
{
|
|
(void)dup2(pi[1], 1);
|
|
(void)close(pi[1]);
|
|
}
|
|
(void)dup2(1,2);
|
|
for (i = 3; i < MAXCONNECTIONS; i++)
|
|
if (local[i])
|
|
(void) close(i);
|
|
/*
|
|
* m4 maybe anywhere, use execvp to find it. Any error
|
|
* goes out with report_error. Could be dangerous,
|
|
* two servers running with the same fd's >:-) -avalon
|
|
*/
|
|
(void)execlp("m4", "m4", "ircd.m4", configfile, 0);
|
|
report_error("Error executing m4 %s:%s", &me);
|
|
exit(-1);
|
|
default :
|
|
(void)close(pi[1]);
|
|
return pi[0];
|
|
}
|
|
#else
|
|
return open(configfile, O_RDONLY);
|
|
#endif
|
|
}
|
|
extern char *getfield();
|
|
|
|
/*
|
|
** initconf()
|
|
** Read configuration file.
|
|
**
|
|
** returns -1, if file cannot be opened
|
|
** 0, if file opened
|
|
*/
|
|
|
|
#define MAXCONFLINKS 150
|
|
|
|
int initconf(opt)
|
|
int opt;
|
|
{
|
|
static char quotes[9][2] = {{'b', '\b'}, {'f', '\f'}, {'n', '\n'},
|
|
{'r', '\r'}, {'t', '\t'}, {'v', '\v'},
|
|
{'\\', '\\'}, { 0, 0}};
|
|
Reg1 char *tmp, *s;
|
|
int fd, i;
|
|
char line[512], c[80];
|
|
int ccount = 0, ncount = 0;
|
|
aConfItem *aconf = NULL;
|
|
static Dlink *d1 = NULL, *d2 = NULL;
|
|
|
|
Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile));
|
|
if ((fd = openconf()) == -1)
|
|
{
|
|
#ifdef M4_PREPROC
|
|
(void)wait(0);
|
|
#endif
|
|
return -1;
|
|
}
|
|
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
|
|
while ((i = dgets(fd, line, sizeof(line) - 1)) > 0)
|
|
{
|
|
line[i] = '\0';
|
|
if ((tmp = (char *)index(line, '\n')))
|
|
*tmp = 0;
|
|
else while(dgets(fd, c, sizeof(c) - 1) > 0)
|
|
if ((tmp = (char *)index(c, '\n')))
|
|
{
|
|
*tmp = 0;
|
|
break;
|
|
}
|
|
/*
|
|
* Do quoting of characters and # detection.
|
|
*/
|
|
for (tmp = line; *tmp; tmp++)
|
|
{
|
|
if (*tmp == '\\')
|
|
{
|
|
for (i = 0; quotes[i][0]; i++)
|
|
if (quotes[i][0] == *(tmp+1))
|
|
{
|
|
*tmp = quotes[i][1];
|
|
break;
|
|
}
|
|
if (!quotes[i][0])
|
|
*tmp = *(tmp+1);
|
|
if (!*(tmp+1))
|
|
break;
|
|
else
|
|
for (s = tmp; *s = *(s+1); s++)
|
|
;
|
|
}
|
|
else if (*tmp == '#')
|
|
*tmp = '\0';
|
|
}
|
|
if (!*line || line[0] == '#' || line[0] == '\n' ||
|
|
line[0] == ' ' || line[0] == '\t')
|
|
continue;
|
|
/* Could we test if it's conf line at all? -Vesa */
|
|
if (line[1] != ':')
|
|
{
|
|
Debug((DEBUG_ERROR, "Bad config line: %s", line));
|
|
continue;
|
|
}
|
|
if (aconf)
|
|
free_conf(aconf);
|
|
aconf = make_conf();
|
|
|
|
tmp = getfield(line);
|
|
if (!tmp)
|
|
continue;
|
|
switch (*tmp)
|
|
{
|
|
case 'A': /* Name, e-mail address of administrator */
|
|
case 'a': /* of this server. */
|
|
aconf->status = CONF_ADMIN;
|
|
break;
|
|
case 'C': /* Server where I should try to connect */
|
|
case 'c': /* in case of lp failures */
|
|
ccount++;
|
|
aconf->status = CONF_CONNECT_SERVER;
|
|
break;
|
|
/* Connect rule */
|
|
case 'D':
|
|
aconf->status = CONF_CRULEALL;
|
|
break;
|
|
/* Connect rule - autos only */
|
|
case 'd':
|
|
aconf->status = CONF_CRULEAUTO;
|
|
break;
|
|
case 'H': /* Hub server line */
|
|
case 'h':
|
|
aconf->status = CONF_HUB;
|
|
break;
|
|
case 'I': /* Just plain normal irc client trying */
|
|
case 'i': /* to connect me */
|
|
aconf->status = CONF_CLIENT;
|
|
break;
|
|
case 'K': /* Kill user line on irc.conf */
|
|
case 'k':
|
|
aconf->status = CONF_KILL;
|
|
break;
|
|
/* Operator. Line should contain at least */
|
|
/* password and host where connection is */
|
|
case 'L': /* guaranteed leaf server */
|
|
case 'l':
|
|
aconf->status = CONF_LEAF;
|
|
break;
|
|
/* Me. Host field is name used for this host */
|
|
/* and port number is the number of the port */
|
|
case 'M':
|
|
case 'm':
|
|
aconf->status = CONF_ME;
|
|
break;
|
|
case 'N': /* Server where I should NOT try to */
|
|
case 'n': /* connect in case of lp failures */
|
|
/* but which tries to connect ME */
|
|
++ncount;
|
|
aconf->status = CONF_NOCONNECT_SERVER;
|
|
break;
|
|
case 'O':
|
|
aconf->status = CONF_OPERATOR;
|
|
break;
|
|
/* Local Operator, (limited privs --SRB) */
|
|
case 'o':
|
|
aconf->status = CONF_LOCOP;
|
|
break;
|
|
case 'P': /* listen port line */
|
|
case 'p':
|
|
aconf->status = CONF_LISTEN_PORT;
|
|
break;
|
|
case 'Q': /* a server that you don't want in your */
|
|
case 'q': /* network. USE WITH CAUTION! */
|
|
aconf->status = CONF_QUARANTINED_SERVER;
|
|
break;
|
|
#ifdef R_LINES
|
|
case 'R': /* extended K line */
|
|
case 'r': /* Offers more options of how to restrict */
|
|
aconf->status = CONF_RESTRICT;
|
|
break;
|
|
#endif
|
|
case 'S': /* Service. Same semantics as */
|
|
case 's': /* CONF_OPERATOR */
|
|
aconf->status = CONF_SERVICE;
|
|
break;
|
|
case 'T': /* print out different motd's */
|
|
case 't': /* based on hostmask */
|
|
aconf->status = CONF_TLINES;
|
|
break;
|
|
case 'U': /* Underworld server, allowed to hack modes */
|
|
case 'u': /* *Every* server on the net must define the same !!! */
|
|
aconf->status = CONF_UWORLD;
|
|
break;
|
|
case 'Y':
|
|
case 'y':
|
|
aconf->status = CONF_CLASS;
|
|
break;
|
|
default:
|
|
Debug((DEBUG_ERROR, "Error in config file: %s", line));
|
|
break;
|
|
}
|
|
if (IsIllegal(aconf))
|
|
continue;
|
|
|
|
for (;;) /* Fake loop, that I can use break here --msa */
|
|
{
|
|
if ((tmp = getfield(NULL)) == NULL)
|
|
break;
|
|
DupString(aconf->host, tmp);
|
|
if ((tmp = getfield(NULL)) == NULL)
|
|
break;
|
|
DupString(aconf->passwd, tmp);
|
|
if ((tmp = getfield(NULL)) == NULL)
|
|
break;
|
|
DupString(aconf->name, tmp);
|
|
if ((tmp = getfield(NULL)) == NULL)
|
|
break;
|
|
aconf->port = atoi(tmp);
|
|
if ((tmp = getfield(NULL)) == NULL)
|
|
break;
|
|
Class(aconf) = find_class(atoi(tmp));
|
|
break;
|
|
}
|
|
/*
|
|
** If conf line is a class definition, create a class entry
|
|
** for it and make the conf_line illegal and delete it.
|
|
*/
|
|
if (aconf->status & CONF_CLASS)
|
|
{
|
|
add_class(atoi(aconf->host), atoi(aconf->passwd),
|
|
atoi(aconf->name), aconf->port,
|
|
tmp ? atoi(tmp) : 0);
|
|
continue;
|
|
}
|
|
/*
|
|
** associate each conf line with a class by using a pointer
|
|
** to the correct class record. -avalon
|
|
*/
|
|
if (aconf->status & (CONF_CLIENT_MASK|CONF_LISTEN_PORT))
|
|
{
|
|
if (Class(aconf) == 0)
|
|
Class(aconf) = find_class(0);
|
|
if (MaxLinks(Class(aconf)) < 0)
|
|
Class(aconf) = find_class(0);
|
|
}
|
|
if (aconf->status & (CONF_LISTEN_PORT|CONF_CLIENT))
|
|
{
|
|
aConfItem *bconf;
|
|
|
|
if (bconf = find_conf_entry(aconf, aconf->status))
|
|
{
|
|
delist_conf(bconf);
|
|
bconf->status &= ~CONF_ILLEGAL;
|
|
if (aconf->status == CONF_CLIENT)
|
|
{
|
|
bconf->class->links -= bconf->clients;
|
|
bconf->class = aconf->class;
|
|
if (bconf->class)
|
|
bconf->class->links += bconf->clients;
|
|
}
|
|
free_conf(aconf);
|
|
aconf = bconf;
|
|
}
|
|
else if (aconf->host &&
|
|
aconf->status == CONF_LISTEN_PORT)
|
|
(void)add_listener(aconf);
|
|
}
|
|
if (aconf->status & CONF_SERVER_MASK)
|
|
if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS ||
|
|
!aconf->host || index(aconf->host, '*') ||
|
|
index(aconf->host,'?') || !aconf->name)
|
|
continue;
|
|
|
|
if (aconf->status &
|
|
(CONF_SERVER_MASK|CONF_LOCOP|CONF_OPERATOR))
|
|
if (!index(aconf->host, '@') && *aconf->host != '/')
|
|
{
|
|
char *newhost;
|
|
int len = 3; /* *@\0 = 3 */
|
|
|
|
len += strlen(aconf->host);
|
|
newhost = (char *)MyMalloc(len);
|
|
(void)sprintf(newhost, "*@%s", aconf->host);
|
|
MyFree(aconf->host);
|
|
aconf->host = newhost;
|
|
}
|
|
if (aconf->status & CONF_SERVER_MASK)
|
|
{
|
|
if (BadPtr(aconf->passwd))
|
|
continue;
|
|
else if (!(opt & BOOT_QUICK))
|
|
(void)lookup_confhost(aconf);
|
|
}
|
|
|
|
/* Create expression tree from connect rule...
|
|
** If there's a parsing error, nuke the conf structure */
|
|
if (aconf->status & (CONF_CRULEALL | CONF_CRULEAUTO))
|
|
{
|
|
MyFree (aconf->passwd);
|
|
if ((aconf->passwd =
|
|
(char *) crule_parse (aconf->name)) == NULL)
|
|
{
|
|
free_conf (aconf);
|
|
aconf = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Own port and name cannot be changed after the startup.
|
|
** (or could be allowed, but only if all links are closed
|
|
** first).
|
|
** Configuration info does not override the name and port
|
|
** if previously defined. Note, that "info"-field can be
|
|
** changed by "/rehash".
|
|
*/
|
|
if (aconf->status == CONF_ME)
|
|
{
|
|
strncpyzt(me.info, aconf->name, sizeof(me.info));
|
|
if (me.name[0] == '\0' && aconf->host[0])
|
|
strncpyzt(me.name, aconf->host,
|
|
sizeof(me.name));
|
|
if (portnum < 0 && aconf->port >= 0)
|
|
portnum = aconf->port;
|
|
}
|
|
(void)collapse(aconf->host);
|
|
(void)collapse(aconf->name);
|
|
Debug((DEBUG_NOTICE,
|
|
"Read Init: (%d) (%s) (%s) (%s) (%d) (%d)",
|
|
aconf->status, aconf->host, aconf->passwd,
|
|
aconf->name, aconf->port, Class(aconf)));
|
|
aconf->next = conf;
|
|
conf = aconf;
|
|
aconf = NULL;
|
|
}
|
|
if (aconf)
|
|
free_conf(aconf);
|
|
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
|
|
(void)close(fd);
|
|
#ifdef M4_PREPROC
|
|
(void)wait(0);
|
|
#endif
|
|
check_class();
|
|
nextping = nextconnect = now;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* lookup_confhost
|
|
* Do (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.
|
|
*/
|
|
static int lookup_confhost(aconf)
|
|
Reg1 aConfItem *aconf;
|
|
{
|
|
Reg2 char *s;
|
|
Reg3 struct hostent *hp;
|
|
Link ln;
|
|
|
|
if (BadPtr(aconf->host) || BadPtr(aconf->name))
|
|
goto badlookup;
|
|
if ((s = index(aconf->host, '@')))
|
|
s++;
|
|
else
|
|
s = aconf->host;
|
|
/*
|
|
** Do name lookup now on hostnames given and store the
|
|
** ip numbers in conf structure.
|
|
*/
|
|
if (!isalpha(*s) && !isdigit(*s))
|
|
goto badlookup;
|
|
|
|
/*
|
|
** Prepare structure in case we have to wait for a
|
|
** reply which we get later and store away.
|
|
*/
|
|
ln.value.aconf = aconf;
|
|
ln.flags = ASYNC_CONF;
|
|
|
|
if (isdigit(*s))
|
|
aconf->ipnum.s_addr = inet_addr(s);
|
|
else if ((hp = gethost_byname(s, &ln)))
|
|
bcopy(hp->h_addr, (char *)&(aconf->ipnum),
|
|
sizeof(struct in_addr));
|
|
|
|
if (aconf->ipnum.s_addr == -1)
|
|
goto badlookup;
|
|
return 0;
|
|
badlookup:
|
|
if (aconf->ipnum.s_addr == -1)
|
|
bzero((char *)&aconf->ipnum, sizeof(struct in_addr));
|
|
Debug((DEBUG_ERROR,"Host/server name error: (%s) (%s)",
|
|
aconf->host, aconf->name));
|
|
return -1;
|
|
}
|
|
|
|
/* find_tline
|
|
* 30 mar 1995 flux (cmlambertus@ucdavis.edu)
|
|
* associate a conf struct with a client
|
|
*
|
|
* cptr - client in question
|
|
*/
|
|
aConfItem *find_tline(cptr)
|
|
aClient *cptr;
|
|
{
|
|
char *host, *name;
|
|
aConfItem *tmp;
|
|
|
|
if (!cptr->user)
|
|
return NULL;
|
|
|
|
host = cptr->sockhost;
|
|
name = cptr->user->username;
|
|
|
|
if (strlen(host) > (size_t)HOSTLEN ||
|
|
(name ? strlen(name) : 0) > (size_t)HOSTLEN)
|
|
return NULL;
|
|
|
|
/*
|
|
* if the status is a T line, host and passwd exist
|
|
* and the client host is a match for the hostmask in
|
|
* the tline, return the confitem struct pointer -flux
|
|
*/
|
|
for (tmp = conf; tmp; tmp = tmp->next)
|
|
if (tmp->status == CONF_TLINES && tmp->host &&
|
|
tmp->passwd && match(tmp->host, host) == 0)
|
|
return tmp;
|
|
|
|
return NULL; /* no tline found */
|
|
}
|
|
|
|
int find_kill(cptr)
|
|
aClient *cptr;
|
|
{
|
|
char reply[256], *host, *name;
|
|
aConfItem *tmp;
|
|
aGline *agline = NULL;
|
|
|
|
if (!cptr->user)
|
|
return 0;
|
|
|
|
host = cptr->sockhost;
|
|
name = cptr->user->username;
|
|
|
|
if (strlen(host) > (size_t) HOSTLEN ||
|
|
(name ? strlen(name) : 0) > (size_t) HOSTLEN)
|
|
return (0);
|
|
|
|
reply[0] = '\0';
|
|
|
|
for (tmp = conf; tmp; tmp = tmp->next)
|
|
if ((tmp->status == CONF_KILL) && tmp->host && tmp->name &&
|
|
(match(tmp->host, host) == 0) &&
|
|
(!name || match(tmp->name, name) == 0) &&
|
|
(!tmp->port || (tmp->port == cptr->acpt->port)))
|
|
/* can short-circuit evaluation - not taking chances
|
|
cos check_time_interval destroys tmp->passwd
|
|
- Mmmm
|
|
*/
|
|
if (BadPtr(tmp->passwd))
|
|
break;
|
|
else if (is_comment(tmp->passwd))
|
|
break;
|
|
else if (check_time_interval(tmp->passwd, reply))
|
|
break;
|
|
|
|
|
|
if (reply[0])
|
|
sendto_one(cptr, reply,
|
|
me.name, ERR_YOUREBANNEDCREEP, cptr->name);
|
|
else if (tmp)
|
|
if (BadPtr(tmp->passwd))
|
|
sendto_one(cptr,
|
|
":%s %d %s :*** You are not welcome to this server.",
|
|
me.name, ERR_YOUREBANNEDCREEP, cptr->name);
|
|
else
|
|
#ifdef COMMENT_IS_FILE
|
|
m_killcomment(cptr,cptr->name, tmp->passwd);
|
|
#else
|
|
sendto_one(cptr,
|
|
":%s %d %s :*** %s.",
|
|
me.name, ERR_YOUREBANNEDCREEP, cptr->name,
|
|
tmp->passwd);
|
|
#endif /* COMMENT_IS_FILE */
|
|
|
|
/* find active glines */
|
|
else if ((agline = find_gline(host, name, NULL)) &&
|
|
agline->active == GLINE_ACTIVE)
|
|
sendto_one(cptr, ":%s %d %s :*** %s.", me.name,
|
|
ERR_YOUREBANNEDCREEP, cptr->name, agline->reason);
|
|
else agline = NULL; /* if a gline was found, it was inactive */
|
|
|
|
return (tmp ? -1 : (agline ? -2 : 0));
|
|
}
|
|
|
|
#ifdef R_LINES
|
|
/* find_restrict works against host/name and calls an outside program
|
|
* to determine whether a client is allowed to connect. This allows
|
|
* more freedom to determine who is legal and who isn't, for example
|
|
* machine load considerations. The outside program is expected to
|
|
* return a reply line where the first word is either 'Y' or 'N' meaning
|
|
* "Yes Let them in" or "No don't let them in." If the first word
|
|
* begins with neither 'Y' or 'N' the default is to let the person on.
|
|
* It returns a value of 0 if the user is to be let through -Hoppie
|
|
*/
|
|
int find_restrict(cptr)
|
|
aClient *cptr;
|
|
{
|
|
aConfItem *tmp;
|
|
char reply[80], temprpl[80];
|
|
char *rplhold = reply, *host, *name, *s;
|
|
char rplchar = 'Y';
|
|
int pi[2], rc = 0, n;
|
|
|
|
if (!cptr->user)
|
|
return 0;
|
|
name = cptr->user->username;
|
|
host = cptr->sockhost;
|
|
Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host));
|
|
|
|
for (tmp = conf; tmp; tmp = tmp->next)
|
|
{
|
|
if (tmp->status != CONF_RESTRICT ||
|
|
(tmp->host && host && match(tmp->host, host)) ||
|
|
(tmp->name && name && match(tmp->name, name)))
|
|
continue;
|
|
|
|
if (BadPtr(tmp->passwd))
|
|
{
|
|
sendto_ops("Program missing on R-line %s/%s, ignoring",
|
|
name, host);
|
|
continue;
|
|
}
|
|
|
|
if (pipe(pi) == -1)
|
|
{
|
|
report_error("Error creating pipe for R-line %s:%s",
|
|
&me);
|
|
return 0;
|
|
}
|
|
switch (rc = fork())
|
|
{
|
|
case -1 :
|
|
report_error("Error forking for R-line %s:%s", &me);
|
|
return 0;
|
|
case 0 :
|
|
{
|
|
Reg1 int i;
|
|
|
|
(void)close(pi[0]);
|
|
for (i = 2; i < MAXCONNECTIONS; i++)
|
|
if (i != pi[1])
|
|
(void)close(i);
|
|
if (pi[1] != 2)
|
|
(void)dup2(pi[1], 2);
|
|
(void)dup2(2, 1);
|
|
if (pi[1] != 2 && pi[1] != 1)
|
|
(void)close(pi[1]);
|
|
(void)execlp(tmp->passwd, tmp->passwd, name, host, 0);
|
|
exit(-1);
|
|
}
|
|
default :
|
|
(void)close(pi[1]);
|
|
break;
|
|
}
|
|
*reply = '\0';
|
|
(void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
|
|
while ((n = dgets(pi[0], temprpl, sizeof(temprpl)-1)) > 0)
|
|
{
|
|
temprpl[n] = '\0';
|
|
if ((s = (char *)index(temprpl, '\n')))
|
|
*s = '\0';
|
|
if (strlen(temprpl) + strlen(reply) < sizeof(reply)-2)
|
|
(void)sprintf(rplhold, "%s %s", rplhold,
|
|
temprpl);
|
|
else
|
|
{
|
|
sendto_ops("R-line %s/%s: reply too long!",
|
|
name, host);
|
|
break;
|
|
}
|
|
}
|
|
(void)dgets(-1, NULL, 0); /* make sure buffer marked empty */
|
|
(void)close(pi[0]);
|
|
(void)kill(rc, SIGKILL); /* cleanup time */
|
|
(void)wait(0);
|
|
|
|
rc = 0;
|
|
while (*rplhold == ' ')
|
|
rplhold++;
|
|
rplchar = *rplhold; /* Pull out the yes or no */
|
|
while (*rplhold != ' ')
|
|
rplhold++;
|
|
while (*rplhold == ' ')
|
|
rplhold++;
|
|
(void)strcpy(reply,rplhold);
|
|
rplhold = reply;
|
|
|
|
if ((rc = (rplchar == 'n' || rplchar == 'N')))
|
|
break;
|
|
}
|
|
if (rc)
|
|
{
|
|
sendto_one(cptr, ":%s %d %s :Restriction: %s",
|
|
me.name, ERR_YOUREBANNEDCREEP, cptr->name,
|
|
reply);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
** output the reason for being k lined from a file - Mmmm
|
|
** sptr is server
|
|
** parv is the sender prefix
|
|
** filename is the file that is to be output to the K lined client
|
|
*/
|
|
int m_killcomment(sptr, parv, filename)
|
|
aClient *sptr;
|
|
char *parv, *filename;
|
|
{
|
|
int fd;
|
|
char line[80];
|
|
Reg1 char *tmp;
|
|
struct stat sb;
|
|
struct tm *tm;
|
|
|
|
/*
|
|
* stop NFS hangs...most systems should be able to open a file in
|
|
* 3 seconds. -avalon (curtesy of wumpus)
|
|
*/
|
|
(void)alarm(3);
|
|
fd = open(filename, O_RDONLY);
|
|
(void)alarm(0);
|
|
if (fd == -1)
|
|
{
|
|
sendto_one(sptr, err_str(ERR_NOMOTD), me.name, parv);
|
|
sendto_one(sptr,
|
|
":%s %d %s :*** You are not welcome to this server.",
|
|
me.name, ERR_YOUREBANNEDCREEP, parv);
|
|
return 0;
|
|
}
|
|
(void)fstat(fd, &sb);
|
|
tm = localtime((time_t *)&sb.st_mtime); /* NetBSD needs cast */
|
|
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
|
|
while (dgets(fd, line, sizeof(line)-1) > 0)
|
|
{
|
|
if ((tmp = (char *)index(line,'\n')))
|
|
*tmp = '\0';
|
|
if ((tmp = (char *)index(line,'\r')))
|
|
*tmp = '\0';
|
|
/* sendto_one(sptr,
|
|
":%s %d %s : %s.",
|
|
me.name, ERR_YOUREBANNEDCREEP, parv,line); */
|
|
sendto_one(sptr, rpl_str(RPL_MOTD), me.name, parv, line);
|
|
}
|
|
sendto_one(sptr,
|
|
":%s %d %s :*** You are not welcome to this server.",
|
|
me.name, ERR_YOUREBANNEDCREEP, parv);
|
|
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
|
|
(void)close(fd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
** is the K line field an interval or a comment? - Mmmm
|
|
*/
|
|
|
|
static int is_comment(comment)
|
|
char *comment;
|
|
{
|
|
int i;
|
|
for (i=0; i<strlen(comment); i++)
|
|
if ( (comment[i] != ' ') && (comment[i] != '-')
|
|
&& (comment[i] != ',')
|
|
&& ( (comment[i] < '0') || (comment[i] > '9') ) )
|
|
return(1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
** check against a set of time intervals
|
|
*/
|
|
|
|
static int check_time_interval(interval, reply)
|
|
char *interval, *reply;
|
|
{
|
|
struct tm *tptr;
|
|
char *p;
|
|
int perm_min_hours, perm_min_minutes,
|
|
perm_max_hours, perm_max_minutes;
|
|
int nowm, perm_min, perm_max;
|
|
|
|
tptr = localtime(&now);
|
|
nowm = tptr->tm_hour * 60 + tptr->tm_min;
|
|
|
|
while (interval)
|
|
{
|
|
p = (char *)index(interval, ',');
|
|
if (p)
|
|
*p = '\0';
|
|
if (sscanf(interval, "%2d%2d-%2d%2d",
|
|
&perm_min_hours, &perm_min_minutes,
|
|
&perm_max_hours, &perm_max_minutes) != 4)
|
|
{
|
|
if (p)
|
|
*p = ',';
|
|
return(0);
|
|
}
|
|
if (p)
|
|
*(p++) = ',';
|
|
perm_min = 60 * perm_min_hours + perm_min_minutes;
|
|
perm_max = 60 * perm_max_hours + perm_max_minutes;
|
|
/*
|
|
** The following check allows intervals over midnight ...
|
|
*/
|
|
if ((perm_min < perm_max)
|
|
? (perm_min <= nowm && nowm <= perm_max)
|
|
: (perm_min <= nowm || nowm <= perm_max))
|
|
{
|
|
(void)sprintf(reply,
|
|
":%%s %%d %%s :%s %d:%02d to %d:%02d.",
|
|
"You are not allowed to connect from",
|
|
perm_min_hours, perm_min_minutes,
|
|
perm_max_hours, perm_max_minutes);
|
|
return(ERR_YOUREBANNEDCREEP);
|
|
}
|
|
if ((perm_min < perm_max)
|
|
? (perm_min <= nowm + 5 && nowm + 5 <= perm_max)
|
|
: (perm_min <= nowm + 5 || nowm + 5 <= perm_max))
|
|
{
|
|
(void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s",
|
|
perm_min-nowm,(perm_min-nowm)>1?"s ":" ",
|
|
"and you will be denied for further access");
|
|
return(ERR_YOUWILLBEBANNED);
|
|
}
|
|
interval = p;
|
|
}
|
|
return(0);
|
|
}
|