This commit is contained in:
2023-12-26 16:40:53 -05:00
commit ab64084f63
93 changed files with 40857 additions and 0 deletions

291
ircd/Makefile Normal file
View File

@@ -0,0 +1,291 @@
#************************************************************************
#* IRC - Internet Relay Chat, ircd/Makefile
#* Copyright (C) 1990 Jarkko Oikarinen
#*
#* 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.
#*/
CC=cc
RM=/bin/rm
CP=/bin/cp
TOUCH=touch
SHELL=/bin/sh
INSTALL=/usr/bin/install
# IRCDMODE given in top level Makefile, but added here to make sure
# compilation works if started in ircd subdirectory
IRCDMODE=711
INCLUDEDIR=../include
# CFLAGS/IRCDLIBS used in ../Makefile should also be used here. The list
# given below is less than complete.
# For MIPS, use the following:
#CFLAGS= -g -systype bsd43 -DSYSTYPE_BSD43 -I${INCLUDEDIR}
# For Irix 4.x (SGI), use the following:
#CFLAGS= -g -cckr -I$(INCLUDEDIR)
# else just this
CFLAGS= -g -I${INCLUDEDIR}
#
# use the following on SUN OS without nameserver libraries inside libc
# NOTE: most dont have the resolver libraries inside libc
#IRCDLIBS=-lresolv
#
#on NeXT other than 2.0:
#IRCDLIBS=-lsys_s
#
# HPUX:
#IRCDLIBS=-lBSD
#
# Solaris 2
#IRCDLIBS=-lsocket -lnsl
#
# ESIX
#CFLAGS=-O -I${INCLUDEDIR} -I/usr/ucbinclude
#IRCDLIBS=-L/usr/ucblib -L/usr/lib -lsocket -lucb -lns -lnsl
#
#When profiling:
#IRCDLIBS=-lc_p
LINTFLAGS=-hba
#
# LDFLAGS - flags to send the loader (ld). SunOS users may want to add
# -Bstatic here.
#
#LDFLAGS=-Bstatic
#LDFLAGS=-Wl,-a,archive
#
# RES - if you are missing the resolv library (man 5 resolv.conf), or you
# experience probems with ip# to hostname lookups for local machines or
# the server wont compile because _res is missing, uncomment RES.
# For those who know what these are, if you normally use the resolv+
# libraries and have setup /etc/resolv.conf, these are fromm resolv+ if they
# are not part of your system libraries. In all cases you should try your
# system libraries before these.
#
#RES=res_init.o res_comp.o res_mkquery.o
COMMONOBJS=../common/bsd.o ../common/dbuf.o ../common/packet.o \
../common/send.o ../common/match.o ../common/parse.o \
../common/support.o
OBJS=channel.o class.o hash.o ircd.o list.o res.o s_auth.o s_bsd.o s_conf.o \
s_debug.o s_err.o s_misc.o s_numeric.o s_serv.o s_user.o whowas.o \
note.o userload.o crule.o s_ping.o map.o random.o $(RES) $(COMMONOBJS)
SRC=$(OBJS:%.o=%.c)
COMMONSRC=$(COMMONOBJS:%.o=%.c)
MAKE = make 'CFLAGS=${CFLAGS}' 'CC=${CC}' 'IRCDLIBS=${IRCDLIBS}' \
'LDFLAGS=${LDFLAGS}' 'IRCDMODE=${IRCDMODE}'
all: build
build: ircd chkconf
ircd: $(OBJS) ../include/patchlevel.h
$(SHELL) version.c.SH
$(CC) $(CFLAGS) -c version.c
$(CC) $(CFLAGS) $(OBJS) version.o $(LDFLAGS) $(IRCDLIBS) -o ircd
chmod $(IRCDMODE) ircd
chkconf: ../include/struct.h ../include/config.h ../include/sys.h \
../include/common.h crule.c chkconf.c
$(CC) $(CFLAGS) -DCR_CHKCONF -o chkcrule.o -c crule.c
$(CC) $(CFLAGS) chkconf.c ../common/match.o chkcrule.o \
$(LDFLAGS) $(IRCDLIBS) -o chkconf
saber: $(SRC)
#load -I../include $(SRC) $(COMMONSRC) version.c $(IRCDLIBS)
lint:
lint $(LINTFLAGS) -I../include $(SRC) | egrep -v 'sendto_|debug'
../common/parse.o: ../common/parse.c ../include/msg.h ../include/config.h\
../include/struct.h ../include/sys.h ../include/numeric.h
(cd ../common; $(MAKE) build);
../common/bsd.o: ../common/bsd.c ../include/config.h ../include/common.h\
../include/struct.h ../include/sys.h
(cd ../common; $(MAKE) build);
../common/dbuf.o: ../common/dbuf.c ../include/config.h ../include/common.h\
../include/struct.h ../include/dbuf.h
(cd ../common; $(MAKE) build);
../common/packet.o: ../common/packet.c ../include/config.h ../include/common.h\
../include/struct.h ../include/msg.h
(cd ../common; $(MAKE) build);
../common/send.o: ../common/send.c ../include/config.h ../include/common.h\
../include/struct.h ../include/sys.h
(cd ../common; $(MAKE) build);
../common/match.o: ../common/match.c ../include/config.h ../include/common.h\
../include/sys.h
(cd ../common; $(MAKE) build);
../common/support.o: ../common/support.c ../include/config.h ../include/sys.h\
../include/common.h
(cd ../common; $(MAKE) build);
install: all
-if [ ! -d ${IRCDDIR} -a ! -f ${IRCDDIR} ] ; then \
mkdir ${IRCDDIR}; \
fi
../bsdinstall -c -s -m ${IRCDMODE} ircd ${BINDIR}
../bsdinstall -c -s -m 700 chkconf ${BINDIR}
$(CP) ../doc/example.conf ${IRCDDIR}
$(TOUCH) ${IRCDDIR}/ircd.motd
$(RM) -f ${IRCDDIR}/ircd.m4
$(TOUCH) ${IRCDDIR}/ircd.m4
chmod +x buildm4
./buildm4 ${IRCDDIR}
clean:
$(RM) -f *.o *~ core ircd version.c \#* *.bak chkconf *.orig
depend:
makedepend -I${INCLUDEDIR} ${SRC}
channel.o: ../include/struct.h ../include/config.h ../include/dbuf.h \
../include/numeric.h ../include/channel.h ../include/sys.h \
../include/common.h
$(CC) $(CFLAGS) -c channel.c
class.o: ../include/struct.h ../include/class.h ../include/numeric.h \
../include/common.h ../include/config.h ../include/sys.h
$(CC) $(CFLAGS) -c class.c
ircd.o: ircd.c ../include/struct.h ../include/config.h ../include/sys.h \
../include/dbuf.h ../include/numeric.h ../include/common.h
$(CC) $(CFLAGS) -c ircd.c
list.o: list.c ../include/struct.h ../include/config.h ../include/dbuf.h \
../include/sys.h ../include/common.h
$(CC) $(CFLAGS) -c list.c
res.o: res.c ../include/struct.h ../include/config.h ../include/res.h \
../include/sys.h ../include/common.h
$(CC) $(CFLAGS) -c res.c
s_bsd.o: s_bsd.c ../include/struct.h ../include/config.h ../include/dbuf.h \
../include/sys.h ../include/common.h
$(CC) $(CFLAGS) -c s_bsd.c
s_auth.o: s_auth.c ../include/struct.h ../include/config.h ../include/dbuf.h \
../include/sys.h ../include/common.h
$(CC) $(CFLAGS) -c s_auth.c
s_conf.o: s_conf.c ../include/struct.h ../include/config.h ../include/sys.h \
../include/common.h ../include/numeric.h ../include/dbuf.h
$(CC) $(CFLAGS) -c s_conf.c
s_debug.o: ../include/config.h ../include/struct.h ../include/common.h \
../include/sys.h s_debug.c
$(CC) $(CFLAGS) -c s_debug.c
s_err.o: ../include/config.h ../include/struct.h ../include/common.h \
../include/sys.h ../include/numeric.h ../include/msg.h s_err.c
$(CC) $(CFLAGS) -c s_err.c
s_misc.o: s_misc.c ../include/struct.h ../include/config.h ../include/dbuf.h \
../include/common.h ../include/sys.h ../include/numeric.h
$(CC) $(CFLAGS) -c s_misc.c
s_user.o: s_user.c ../include/struct.h ../include/config.h ../include/sys.h \
../include/common.h ../include/dbuf.h ../include/channel.h \
../include/msg.h ../include/numeric.h ../include/whowas.h
$(CC) $(CFLAGS) -c s_user.c
s_serv.o: s_serv.c ../include/struct.h ../include/config.h ../include/sys.h \
../include/common.h ../include/dbuf.h ../include/channel.h \
../include/msg.h ../include/numeric.h ../include/whowas.h
$(CC) $(CFLAGS) -c s_serv.c
s_numeric.o: s_numeric.c ../include/config.h ../include/sys.h \
../include/common.h ../include/struct.h ../include/dbuf.h \
../include/numeric.h
$(CC) $(CFLAGS) -c s_numeric.c
whowas.o: ../include/struct.h ../include/config.h ../include/sys.h \
../include/common.h ../include/dbuf.h ../include/numeric.h \
../include/whowas.h whowas.c
$(CC) $(CFLAGS) -c whowas.c
hash.o: ../include/struct.h ../include/sys.h ../include/hash.h hash.c \
../include/common.h ../include/config.h s_bsd.c s_serv.c s_user.c \
channel.c s_misc.c
@crypt/sums
$(CC) $(CFLAGS) -c hash.c
@/bin/rm -f hash.c
@/bin/mv -f hash.c.old hash.c
@touch hash.o
note.o: ../include/struct.h ../include/sys.h ../include/common.h \
../include/config.h note.c
$(CC) $(CFLAGS) -c note.c
crule.o: ../include/struct.h ../include/sys.h ../include/common.h \
../include/config.h crule.c
$(CC) $(CFLAGS) -c crule.c
s_ping.o: ../include/struct.h ../include/sys.h ../include/common.h \
../include/config.h s_ping.c
$(CC) $(CFLAGS) -c s_ping.c
random.o: ../include/struct.h ../include/sys.h random.c
$(CC) $(CFLAGS) -c random.c
map.o: ../include/struct.h ../include/sys.h map.c
$(CC) $(CFLAGS) -c map.c
# DO NOT DELETE THIS LINE -- make depend depends on it.
channel.o: ../include/struct.h ../include/config.h ../include/dbuf.h
channel.o: ../include/numeric.h ../include/channel.h channel.c
s_misc.o: ../include/struct.h ../include/config.h ../include/dbuf.h s_misc.c
ircd.o: ../include/struct.h ../include/config.h
ircd.o: ../include/dbuf.h ../include/numeric.h ircd.c
list.o: ../include/struct.h ../include/config.h ../include/dbuf.h
list.o: ../include/sys.h list.c
note.o: ../include/config.h note.c
res.o: ../include/struct.h ../include/config.h ../include/res.h res.c
s_bsd.o: ../include/struct.h ../include/config.h ../include/dbuf.h
s_bsd.o: ../include/sys.h s_bsd.c
s_auth.o: ../include/struct.h ../include/config.h ../include/dbuf.h
s_auth.o: ../include/sys.h s_auth.c
s_debug.o: ../include/config.h ../include/struct.h ../include/common.h
s_debug.o: ../include/sys.h s_debug.c
s_debug.o: ../include/struct.h ../include/common.h ../include/sys.h
s_err.o: ../include/struct.h ../include/config.h ../include/numeric.h
s_err.o: ../include/dbuf.h ../include/sys.h s_err.c
s_conf.o: ../include/struct.h ../include/config.h ../include/numeric.h
s_conf.o: ../include/dbuf.h ../include/sys.h s_conf.c
s_user.o: ../include/struct.h ../include/config.h
s_user.o: ../include/dbuf.h ../include/sys.h ../include/channel.h
s_user.o: ../include/msg.h ../include/numeric.h ../include/whowas.h s_user.c
s_serv.o: ../include/struct.h ../include/config.h
s_serv.o: ../include/dbuf.h ../include/sys.h ../include/channel.h
userload.o: ../include/common.h ../include/config.h ../include/userload.h
s_serv.o: ../include/msg.h ../include/numeric.h ../include/whowas.h s_serv.c
s_numeric.o: ../include/config.h ../include/sys.h ../include/struct.h
s_numeric.o: ../include/dbuf.h ../include/numeric.h s_numeric.c
whowas.o: ../include/struct.h ../include/config.h ../include/dbuf.h
whowas.o: ../include/numeric.h ../include/whowas.h ../include/sys.h whowas.c
class.o: ../include/struct.h ../include/class.h ../include/numeric.h
class.o: ../include/common.h ../include/config.h class.c
hash.o: ../include/config.h ../include/sys.h ../include/hash.h
hash.o: ../include/struct.h ../include/common.h s_serv.c s_user.c
hash.o: channel.c s_misc.c s_bsd.c ircd.c hash.c version.c.SH
version.o: version.c.SH version.c
crule.o: ../include/config.h ../include/sys.h ../include/struct.h
crule.o: ../include/common.h

84
ircd/buildm4 Executable file
View File

@@ -0,0 +1,84 @@
#!/bin/sh
# IRC - Internet Relay Chat, ircd/buildm4
# Copyright (C) 1993 Darren Reed
#
# 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.
#
# If only this was a perl script...*sigh*
#
IRCDDIR=$1
M4=$IRCDDIR/ircd.m4
/bin/rm -f $M4
egrep "^#def[^P]*PATCHLEVEL" ../include/patchlevel.h | \
sed -e 's/[^\"]*\"\([^\"]*\)\"/define(VERSION,\1)/' >>$M4
DEBUG=`egrep "^#define[ ]*DEBUGMODE" ../include/config.h`
if [ -n "$DEBUG" ] ; then
echo "define(DEBUGMODE,1)" >>$M4
else
echo "undefine(DEBUGMODE)" >>$M4
fi
echo -n "define(HOSTNAME," >> $M4
echo "`hostname`" | sed -e 's/\([a-zA-Z0-9\-]*\).*/\1)/' >> $M4
echo "define(USER,$USER)" >>$M4
echo -n 'define(PORT,' >>$M4
PORT=`egrep '^#define[ ]*PORT[ ]*[0-9]*' ../include/config.h`
echo "$PORT" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
echo -n 'define(PFREQ,' >>$M4
PING=`egrep '^#define[ ]*PINGFREQUENCY[ ]*[0-9]*' ../include/config.h`
echo "$PING" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
echo -n 'define(CFREQ,' >>$M4
CONT=`egrep '^#define[ ]*CONNECTFREQUENCY[ ]*[0-9]*' ../include/config.h`
echo "$CONT" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
echo -n "define(MAXSENDQ," >>$M4
MAXQ=`egrep '^#define[ ]*MAXSENDQLENGTH[ ]*[0-9]*' ../include/config.h`
echo "$MAXQ" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
echo -n "define(MAXLINKS," >>$M4
MAXL=`egrep '^#define[ ]*MAXIMUM_LINKS[ ]*[0-9]* | head -1' \
../include/config.h`
echo "$MAXL" | sed -e 's/[^0-9]*\([0-9]*\).*/\1)/' >> $M4
DOM=`egrep '^domain' /etc/resolv.conf | \
sed -e 's/^domain[ ]*\([a-zA-Z\-\.0-9]*\).*/\1/'`
echo "define(DOMAIN,$DOM)" >> $M4
cat >>$M4 <<_EOF_
define(CL,\`ifelse(len(\$1),0,0,\$1)')
define(HOST,\$1)
define(HOSTM,\$1)
define(ID,*@\$1)
define(PASS,\$1)
define(PING,\`ifelse(len(\$1),0,PFREQ,\$1)')
define(APORT,\`ifelse(len(\$1),0,PORT,\$1)')
define(FREQ,\`ifelse(len(\$1),0,CFREQ,\$1)')
define(SENDQ,\`ifelse(len(\$1),0,MAXSENDQ,\$1)')
define(MAX,\`ifelse(len(\$1),0,MAXLINKS,\$1)')
define(CPORT,\$1)
define(SERV,\$1)
define(ADMIN,A:\$1:\$2:\$3:\$4:\$5)
define(ALLOW,N:\`HOST(\$1)':\`PASS(\$2)':\`SERV(\$3)':\`HOSTM(\$4)':\`CL(\$5)')
define(BAN,K:\$1:\$2:\$3)
define(CLASS,Y:\$1:\`PING(\$2)':\$3:\`MAX(\$4)':\`SENDQ(\$5)')
define(CLIENT,I:\`HOST(\$1)':\`PASS(\$2)':\`ifelse(len(HOST(\$3)),0,\$1,\$3)':\
\`APORT(\$4)':\`CL(\$5)')
define(CONNECT,C:\`HOST(\$1)':\`PASS(\$2)':\`SERV(\$3)':\
\`CPORT(\$4)':\`CL(\$5)')
define(ME,M:\$1:\$2:\$3:\$4:\$5)
define(HUB,H:\`ifelse(len(\$2),0,*,\$2)':*:\$1)
define(LEAF,L:\`ifelse(len(\$2),0,*,\$2)':*:\$1:1)
define(SERVER,\`
CONNECT(\$1,\$2,\$3,\$5,\$6)
ALLOW(\$1,\$2,\$3,\$4,\$6)
')
_EOF_

2676
ircd/channel.c Normal file

File diff suppressed because it is too large Load Diff

755
ircd/chkconf.c Normal file
View File

@@ -0,0 +1,755 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/chkconf.c
* Copyright (C) 1993 Darren Reed
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)chkconf.c 1.9 1/30/94 (C) 1993 Darren Reed";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef __hpux
#include "inet.h"
#endif
#ifdef PCS
#include <time.h>
#endif
#ifdef R_LINES
#include <signal.h>
#endif
#ifdef DYNIXPTX
#include <sys/types.h>
#include <time.h>
#endif
/* for the connect rule patch.. these really should be in a header,
** but i see h.h isn't included for some reason.. so they're here */
char *crule_parse PROTO((char *rule));
void crule_free PROTO((char **elem));
#undef free
#define MyMalloc(x) malloc(x)
static void new_class();
static char *getfield(), confchar ();
static int openconf(), validate();
static aClass *get_class();
static aConfItem *initconf();
static int numclasses = 0, *classarr = (int *)NULL, debugflag = 0;
static char *configfile = CONFIGFILE;
static char nullfield[] = "";
static char maxsendq[12];
main(argc, argv)
int argc;
char *argv[];
{
new_class(0);
if (chdir(DPATH))
{
perror("chdir");
exit(-1);
}
if (argc > 1 && !strncmp(argv[1], "-d", 2))
{
debugflag = 1;
if (argv[1][2])
debugflag = atoi(argv[1]+2);
argc--, argv++;
}
if (argc > 1)
configfile = argv[1];
return validate(initconf());
}
/*
* 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.
*/
static int openconf()
{
#ifdef M4_PREPROC
int pi[2];
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);
/*
* 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);
perror("m4");
exit(-1);
default :
(void)close(pi[1]);
return pi[0];
}
#else
return open(configfile, O_RDONLY);
#endif
}
/*
** initconf()
** Read configuration file.
**
** returns -1, if file cannot be opened
** 0, if file opened
*/
static aConfItem *initconf(opt)
int opt;
{
int fd;
char line[512], *tmp, c[80], *s, *crule;
int ccount = 0, ncount = 0, dh, flags = 0;
aConfItem *aconf = NULL, *ctop = NULL;
(void)fprintf(stderr, "initconf(): ircd.conf = %s\n", configfile);
if ((fd = openconf()) == -1)
{
#ifdef M4_PREPROC
(void)wait(0);
#endif
return NULL;
}
(void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */
while ((dh = dgets(fd, line, sizeof(line) - 1)) > 0)
{
if (aconf)
{
if (aconf->host)
(void)free(aconf->host);
if (aconf->passwd)
(void)free(aconf->passwd);
if (aconf->name)
(void)free(aconf->name);
}
else
aconf = (aConfItem *)malloc(sizeof(*aconf));
aconf->host = (char *)NULL;
aconf->passwd = (char *)NULL;
aconf->name = (char *)NULL;
aconf->class = (aClass *)NULL;
if (tmp = (char *)index(line, '\n'))
*tmp = 0;
else while(dgets(fd, c, sizeof(c) - 1))
if (tmp = (char *)index(c, '\n'))
{
*tmp = 0;
break;
}
/*
* Do quoting of characters and # detection.
*/
for (tmp = line; *tmp; tmp++)
{
if (*tmp == '\\')
{
switch (*(tmp+1))
{
case 'n' :
*tmp = '\n';
break;
case 'r' :
*tmp = '\r';
break;
case 't' :
*tmp = '\t';
break;
case '0' :
*tmp = '\0';
break;
default :
*tmp = *(tmp+1);
break;
}
if (!*(tmp+1))
break;
else
for (s = tmp; *s = *++s; )
;
tmp++;
}
else if (*tmp == '#')
*tmp = '\0';
}
if (!*line || *line == '#' || *line == '\n' ||
*line == ' ' || *line == '\t')
continue;
if (line[1] != ':')
{
(void)fprintf(stderr, "ERROR: Bad config line (%s)\n",
line);
continue;
}
if (debugflag)
(void)printf("\n%s\n",line);
(void)fflush(stdout);
tmp = getfield(line);
if (!tmp)
{
(void)fprintf(stderr, "\tERROR: no fields found\n");
continue;
}
aconf->status = CONF_ILLEGAL;
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':
case 't':
aconf->status = CONF_TLINES;
break;
case 'U':
case 'u':
aconf->status = CONF_UWORLD;
break;
case 'Y':
case 'y':
aconf->status = CONF_CLASS;
break;
default:
(void)fprintf(stderr,
"\tERROR: unknown conf line letter (%c)\n",
*tmp);
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;
if (!(aconf->status & CONF_CLASS))
aconf->class = get_class(atoi(tmp));
break;
}
if (!aconf->class && (aconf->status & (CONF_CONNECT_SERVER|
CONF_NOCONNECT_SERVER|CONF_OPS|CONF_CLIENT)))
{
(void)fprintf(stderr,
"\tWARNING: No class. Default 0\n");
aconf->class = get_class(0);
}
/*
** 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)
{
int class = 0;
if (!aconf->host)
{
(void)fprintf(stderr,"\tERROR: no class #\n");
continue;
}
if (!tmp)
{
(void)fprintf(stderr,
"\tWARNING: missing sendq field\n");
(void)fprintf(stderr, "\t\t default: %d\n",
MAXSENDQLENGTH);
(void)sprintf(maxsendq, "%d", MAXSENDQLENGTH);
}
else
(void)sprintf(maxsendq, "%d", atoi(tmp));
new_class(atoi(aconf->host));
aconf->class = get_class(atoi(aconf->host));
goto print_confline;
}
if (aconf->status & CONF_LISTEN_PORT)
{
#ifdef UNIXPORT
struct stat sb;
if (!aconf->host)
(void)fprintf(stderr, "\tERROR: %s\n",
"null host field in P-line");
else if (index(aconf->host, '/'))
{
if (stat(aconf->host, &sb) == -1)
{
(void)fprintf(stderr, "\tERROR: (%s) ",
aconf->host);
perror("stat");
}
else if ((sb.st_mode & S_IFMT) != S_IFDIR)
(void)fprintf(stderr,
"\tERROR: %s not directory\n",
aconf->host);
}
#else
if (!aconf->host)
(void)fprintf(stderr, "\tERROR: %s\n",
"null host field in P-line");
else if (index(aconf->host, '/'))
(void)fprintf(stderr, "\t%s %s\n",
"WARNING: / present in P-line",
"for non-UNIXPORT configuration");
#endif
aconf->class = get_class(0);
goto print_confline;
}
if (aconf->status & CONF_SERVER_MASK &&
(!aconf->host || index(aconf->host, '*') ||
index(aconf->host, '?')))
{
(void)fprintf(stderr, "\tERROR: bad host field\n");
continue;
}
if (aconf->status & CONF_SERVER_MASK && BadPtr(aconf->passwd))
{
(void)fprintf(stderr,
"\tERROR: empty/no password field\n");
continue;
}
if (aconf->status & CONF_SERVER_MASK && !aconf->name)
{
(void)fprintf(stderr, "\tERROR: bad name field\n");
continue;
}
if (aconf->status & (CONF_SERVER_MASK|CONF_OPS))
if (!index(aconf->host, '@'))
{
char *newhost;
int len = 3; /* *@\0 = 3 */
len += strlen(aconf->host);
newhost = (char *)MyMalloc(len);
(void)sprintf(newhost, "*@%s", aconf->host);
(void)free(aconf->host);
aconf->host = newhost;
}
/* parse the connect rules to detect errors, but free
** any allocated storage immediately -- we're just looking
** for errors.. */
if (aconf->status & CONF_CRULE)
if ((crule =
(char *) crule_parse (aconf->name)) != NULL)
crule_free (&crule);
if (!aconf->class)
aconf->class = get_class(0);
(void)sprintf(maxsendq, "%d", aconf->class->class);
if (!aconf->name)
aconf->name = nullfield;
if (!aconf->passwd)
aconf->passwd = nullfield;
if (!aconf->host)
aconf->host = nullfield;
if (aconf->status & (CONF_ME|CONF_ADMIN))
{
if (flags & aconf->status)
(void)fprintf(stderr,
"ERROR: multiple %c-lines\n",
toupper(confchar(aconf->status)));
else
flags |= aconf->status;
}
print_confline:
if (debugflag > 8)
(void)printf("(%d) (%s) (%s) (%s) (%d) (%s)\n",
aconf->status, aconf->host, aconf->passwd,
aconf->name, aconf->port, maxsendq);
(void)fflush(stdout);
if (aconf->status & (CONF_SERVER_MASK|CONF_HUB|CONF_LEAF))
{
aconf->next = ctop;
ctop = aconf;
aconf = NULL;
}
}
(void)close(fd);
#ifdef M4_PREPROC
(void)wait(0);
#endif
return ctop;
}
static aClass *get_class(cn)
int cn;
{
static aClass cls;
int i = numclasses - 1;
cls.class = -1;
for (; i >= 0; i--)
if (classarr[i] == cn)
{
cls.class = cn;
break;
}
if (i == -1)
(void)fprintf(stderr,"\tWARNING: class %d not found\n", cn);
return &cls;
}
static void new_class(cn)
int cn;
{
numclasses++;
if (classarr)
classarr = (int *)realloc(classarr, sizeof(int) * numclasses);
else
classarr = (int *)malloc(sizeof(int));
classarr[numclasses-1] = cn;
}
/*
* field breakup for ircd.conf file.
*/
static char *getfield(newline)
char *newline;
{
static char *line = NULL;
char *end, *field;
if (newline)
line = newline;
if (line == NULL)
return(NULL);
field = line;
if ((end = (char *)index(line,':')) == NULL)
{
line = NULL;
if ((end = (char *)index(field,'\n')) == NULL)
end = field + strlen(field);
}
else
line = end + 1;
*end = '\0';
return(field);
}
/*
** read a string terminated by \r or \n in from a fd
**
** Created: Sat Dec 12 06:29:58 EST 1992 by avalon
** Returns:
** 0 - EOF
** -1 - error on read
** >0 - number of bytes returned (<=num)
** After opening a fd, it is necessary to init dgets() by calling it as
** dgets(x,y,0);
** to mark the buffer as being empty.
*/
int dgets(fd, buf, num)
int fd, num;
char *buf;
{
static char dgbuf[8192];
static char *head = dgbuf, *tail = dgbuf;
register char *s, *t;
register int n, nr;
/*
** Sanity checks.
*/
if (head == tail)
*head = '\0';
if (!num)
{
head = tail = dgbuf;
*head = '\0';
return 0;
}
if (num > sizeof(dgbuf) - 1)
num = sizeof(dgbuf) - 1;
dgetsagain:
if (head > dgbuf)
{
for (nr = tail - head, s = head, t = dgbuf; nr > 0; nr--)
*t++ = *s++;
tail = t;
head = dgbuf;
}
/*
** check input buffer for EOL and if present return string.
*/
if (head < tail &&
((s = index(head, '\n')) || (s = index(head, '\r'))) && s < tail)
{
n = MIN(s - head + 1, num); /* at least 1 byte */
dgetsreturnbuf:
bcopy(head, buf, n);
head += n;
if (head == tail)
head = tail = dgbuf;
return n;
}
if (tail - head >= num) /* dgets buf is big enough */
{
n = num;
goto dgetsreturnbuf;
}
n = sizeof(dgbuf) - (tail - dgbuf) - 1;
nr = read(fd, tail, n);
if (nr == -1)
{
head = tail = dgbuf;
return -1;
}
if (!nr)
{
if (head < tail)
{
n = MIN(head - tail, num);
goto dgetsreturnbuf;
}
head = tail = dgbuf;
return 0;
}
tail += nr;
*tail = '\0';
for (t = head; (s = index(t, '\n')); )
{
if ((s > head) && (s > dgbuf))
{
t = s-1;
for (nr = 0; *t == '\\'; nr++)
t--;
if (nr & 1)
{
t = s+1;
s--;
nr = tail - t;
while (nr--)
*s++ = *t++;
tail -= 2;
*tail = '\0';
}
else
s++;
}
else
s++;
t = s;
}
*tail = '\0';
goto dgetsagain;
}
static int validate(top)
aConfItem *top;
{
Reg1 aConfItem *aconf, *bconf;
u_int otype, valid = 0;
if (!top)
return 0;
for (aconf = top; aconf; aconf = aconf->next)
{
if (aconf->status & CONF_MATCH)
continue;
if (aconf->status & CONF_SERVER_MASK)
{
if (aconf->status & CONF_CONNECT_SERVER)
otype = CONF_NOCONNECT_SERVER;
else if (aconf->status & CONF_NOCONNECT_SERVER)
otype = CONF_CONNECT_SERVER;
for (bconf = top; bconf; bconf = bconf->next)
{
if (bconf == aconf || !(bconf->status & otype))
continue;
if (bconf->class == aconf->class &&
!mycmp(bconf->name, aconf->name) &&
!mycmp(bconf->host, aconf->host))
{
aconf->status |= CONF_MATCH;
bconf->status |= CONF_MATCH;
break;
}
}
}
else
for (bconf = top; bconf; bconf = bconf->next)
{
if ((bconf == aconf) ||
!(bconf->status & CONF_SERVER_MASK))
continue;
if (!mycmp(bconf->name, aconf->name))
{
aconf->status |= CONF_MATCH;
break;
}
}
}
(void) fprintf(stderr, "\n");
for (aconf = top; aconf; aconf = aconf->next)
if (aconf->status & CONF_MATCH)
valid++;
else
(void)fprintf(stderr, "Unmatched %c:%s:%s:%s\n",
confchar(aconf->status), aconf->host,
aconf->passwd, aconf->name);
return valid ? 0 : -1;
}
static char confchar(status)
u_int status;
{
static char letrs[] = "QICNoOMKARYSLPH";
char *s = letrs;
status &= ~(CONF_MATCH|CONF_ILLEGAL);
for (; *s; s++, status >>= 1)
if (status & 1)
return *s;
return '-';
}
outofmemory()
{
(void)write(2, "Out of memory\n", 14);
exit(-1);
}

236
ircd/class.c Normal file
View File

@@ -0,0 +1,236 @@
/*
* IRC - Internet Relay Chat, ircd/class.c
* Copyright (C) 1990 Darren Reed
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)class.c 1.4 6/28/93 (C) 1990 Darren Reed";
#endif
#include "struct.h"
#include "common.h"
#include "numeric.h"
#include "h.h"
#define BAD_CONF_CLASS -1
#define BAD_PING -2
#define BAD_CLIENT_CLASS -3
aClass *classes;
int get_conf_class(aconf)
aConfItem *aconf;
{
if ((aconf) && Class(aconf))
return (ConfClass(aconf));
Debug((DEBUG_DEBUG,"No Class For %s",
(aconf) ? aconf->name : "*No Conf*"));
return (BAD_CONF_CLASS);
}
static int get_conf_ping(aconf)
aConfItem *aconf;
{
if ((aconf) && Class(aconf))
return (ConfPingFreq(aconf));
Debug((DEBUG_DEBUG,"No Ping For %s",
(aconf) ? aconf->name : "*No Conf*"));
return (BAD_PING);
}
int get_client_class(acptr)
aClient *acptr;
{
Reg1 Link *tmp;
Reg2 aClass *cl;
int i = 0, retc = BAD_CLIENT_CLASS;
if (acptr && !IsMe(acptr) && !IsPing(acptr) && (acptr->confs))
for (tmp = acptr->confs; tmp; tmp = tmp->next)
{
if (!tmp->value.aconf ||
!(cl = tmp->value.aconf->class))
continue;
if (Class(cl) > retc)
retc = Class(cl);
}
Debug((DEBUG_DEBUG,"Returning Class %d For %s",retc,acptr->name));
return (retc);
}
int get_client_ping(acptr)
aClient *acptr;
{
int ping = 0, ping2;
aConfItem *aconf;
Link *link;
link = acptr->confs;
if (link)
while (link)
{
aconf = link->value.aconf;
if (aconf->status & (CONF_CLIENT|CONF_CONNECT_SERVER|
CONF_NOCONNECT_SERVER))
{
ping2 = get_conf_ping(aconf);
if ((ping2 != BAD_PING) && ((ping > ping2) ||
!ping))
ping = ping2;
}
link = link->next;
}
else
{
ping = PINGFREQUENCY;
Debug((DEBUG_DEBUG,"No Attached Confs"));
}
if (ping <= 0)
ping = PINGFREQUENCY;
Debug((DEBUG_DEBUG,"Client %s Ping %d", acptr->name, ping));
return (ping);
}
int get_con_freq(clptr)
aClass *clptr;
{
if (clptr)
return (ConFreq(clptr));
else
return (CONNECTFREQUENCY);
}
/*
* When adding a class, check to see if it is already present first.
* if so, then update the information for that class, rather than create
* a new entry for it and later delete the old entry.
* if no present entry is found, then create a new one and add it in
* immeadiately after the first one (class 0).
*/
void add_class(class, ping, confreq, maxli, sendq)
int class, ping, confreq, maxli;
long sendq;
{
aClass *t, *p;
t = find_class(class);
if ((t == classes) && (class != 0))
{
p = (aClass *)make_class();
NextClass(p) = NextClass(t);
NextClass(t) = p;
}
else
p = t;
Debug((DEBUG_DEBUG,
"Add Class %d: p %x t %x - cf: %d pf: %d ml: %d sq: %l",
class, p, t, confreq, ping, maxli, sendq));
Class(p) = class;
ConFreq(p) = confreq;
PingFreq(p) = ping;
MaxLinks(p) = maxli;
MaxSendq(p) = (sendq > 0) ? sendq : MAXSENDQLENGTH;
if (p != t)
Links(p) = 0;
}
aClass *find_class(cclass)
int cclass;
{
aClass *cltmp;
for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
if (Class(cltmp) == cclass)
return cltmp;
return classes;
}
void check_class()
{
Reg1 aClass *cltmp, *cltmp2;
Debug((DEBUG_DEBUG, "Class check:"));
for (cltmp2 = cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp2))
{
Debug((DEBUG_DEBUG,
"Class %d : CF: %d PF: %d ML: %d LI: %d SQ: %ld",
Class(cltmp), ConFreq(cltmp), PingFreq(cltmp),
MaxLinks(cltmp), Links(cltmp), MaxSendq(cltmp)));
if (MaxLinks(cltmp) < 0)
{
NextClass(cltmp2) = NextClass(cltmp);
if (Links(cltmp) <= 0)
free_class(cltmp);
}
else
cltmp2 = cltmp;
}
}
void initclass()
{
classes = (aClass *)make_class();
Class(FirstClass()) = 0;
ConFreq(FirstClass()) = CONNECTFREQUENCY;
PingFreq(FirstClass()) = PINGFREQUENCY;
MaxLinks(FirstClass()) = MAXIMUM_LINKS;
MaxSendq(FirstClass()) = MAXSENDQLENGTH;
Links(FirstClass()) = 0;
NextClass(FirstClass()) = NULL;
}
void report_classes(sptr)
aClient *sptr;
{
Reg1 aClass *cltmp;
for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp))
sendto_one(sptr, rpl_str(RPL_STATSYLINE), me.name, sptr->name,
'Y', Class(cltmp), PingFreq(cltmp), ConFreq(cltmp),
MaxLinks(cltmp), MaxSendq(cltmp));
}
long get_sendq(cptr)
aClient *cptr;
{
Reg1 int sendq = MAXSENDQLENGTH, retc = BAD_CLIENT_CLASS;
Reg2 Link *tmp;
Reg2 aClass *cl;
if (cptr && !IsMe(cptr) && (cptr->confs))
for (tmp = cptr->confs; tmp; tmp = tmp->next)
{
if (!tmp->value.aconf ||
!(cl = tmp->value.aconf->class))
continue;
if (Class(cl) > retc)
sendq = MaxSendq(cl);
}
return sendq;
}

775
ircd/crule.c Normal file
View File

@@ -0,0 +1,775 @@
/*
* SmartRoute phase 1
* connection rule patch
* by Tony Vencill (Tonto on IRC) <vencill@bga.com>
*
* The majority of this file is a recusive descent parser used to convert
* connection rules into expression trees when the conf file is read.
* All parsing structures and types are hidden in the interest of good
* programming style and to make possible future data structure changes
* without affecting the interface between this patch and the rest of the
* server. The only functions accessible externally are crule_parse,
* crule_free, and crule_eval. Prototypes for these functions can be
* found in h.h.
*
* Please direct any connection rule or SmartRoute questions to Tonto on
* IRC or by email to vencill@bga.com.
*
* For parser testing, defining CR_DEBUG generates a stand-alone parser
* that takes rules from stdin and prints out memory allocation
* information and the parsed rule. This stand alone parser is ignorant
* of the irc server and thus cannot do rule evaluation. Do not define
* this flag when compiling the server! If you wish to generate the
* test parser, compile from the ircd directory with a line similar to
* cc -o parser -DCR_DEBUG crule.c
*
* The define CR_CHKCONF is provided to generate routines needed in
* chkconf. These consist of the parser, a different crule_parse that
* prints errors to stderr, and crule_free (just for good style and to
* more closely simulate the actual ircd environment). crule_eval and
* the rule functions are made empty functions as in the stand-alone
* test parser.
*/
#ifndef CR_DEBUG
/* ircd functions and types we need */
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
char *collapse PROTO((char *pattern));
extern aClient *client, *local[];
#else
/* includes and defines to make the stand-alone test parser */
#include <stdio.h>
#include <string.h>
#define BadPtr(x) (!(x) || (*(x) == '\0'))
#define DupString(x,y) do{x=(char *)MyMalloc(strlen(y)+1);(void)strcpy(x,y);}while(0)
#define mycmp strcasecmp
#endif
#ifndef PROTO
#if __STDC__
# define PROTO(x) x
#else
# define PROTO(x) ()
#endif
#endif
#if defined(CR_DEBUG) || defined(CR_CHKCONF)
#define MyMalloc malloc
#undef MyFree
#undef free
#define MyFree free
#endif
/* some constants and shared data types */
#define CR_MAXARGLEN 80 /* why 80? why not? it's > hostname lengths */
#define CR_MAXARGS 3 /* there's a better way to do this, but not now */
/* some symbols for easy reading */
enum crule_token
{CR_UNKNOWN, CR_END, CR_AND, CR_OR, CR_NOT, CR_OPENPAREN, CR_CLOSEPAREN,
CR_COMMA, CR_WORD};
enum crule_errcode
{CR_NOERR, CR_UNEXPCTTOK, CR_UNKNWTOK, CR_EXPCTAND, CR_EXPCTOR,
CR_EXPCTPRIM, CR_EXPCTOPEN, CR_EXPCTCLOSE, CR_UNKNWFUNC, CR_ARGMISMAT};
/* expression tree structure, function pointer, and tree pointer */
/* local! */
typedef int (*crule_funcptr) PROTO((int, void **));
struct crule_treestruct
{
crule_funcptr funcptr;
int numargs;
void *arg[CR_MAXARGS]; /* for operators arg points to a tree element;
for functions arg points to a char string */
};
typedef struct crule_treestruct crule_treeelem;
typedef crule_treeelem *crule_treeptr;
/* rule function prototypes - local! */
int crule_connected PROTO((int, void **));
int crule_directcon PROTO((int, void **));
int crule_via PROTO((int, void **));
int crule_directop PROTO((int, void **));
int crule__andor PROTO((int, void **));
int crule__not PROTO((int, void **));
/* parsing function prototypes - local! */
int crule_gettoken PROTO((int *, char **));
void crule_getword PROTO((char *, int *, int, char **));
int crule_parseandexpr PROTO((crule_treeptr *, int *, char **));
int crule_parseorexpr PROTO((crule_treeptr *, int *, char **));
int crule_parseprimary PROTO((crule_treeptr *, int *, char **));
int crule_parsefunction PROTO((crule_treeptr *, int *, char **));
int crule_parsearglist PROTO((crule_treeptr, int *, char **));
#if defined(CR_DEBUG) || defined(CR_CHKCONF)
/* prototypes for the test parser; if not debugging, these are
* defined in h.h */
char *crule_parse PROTO((char *));
void crule_free PROTO((char **));
#ifdef CR_DEBUG
void print_tree PROTO((crule_treeptr));
#endif
#endif
/* error messages */
char *crule_errstr[] =
{
"Unknown error", /* NOERR? - for completeness */
"Unexpected token", /* UNEXPCTTOK */
"Unknown token", /* UNKNWTOK */
"And expr expected", /* EXPCTAND */
"Or expr expected", /* EXPCTOR */
"Primary expected", /* EXPCTPRIM */
"( expected", /* EXPCTOPEN */
") expected", /* EXPCTCLOSE */
"Unknown function", /* UNKNWFUNC */
"Argument mismatch" /* ARGMISMAT */
};
/* function table - null terminated */
struct crule_funclistent
{
char name[15]; /* MAXIMUM FUNCTION NAME LENGTH IS 14 CHARS!! */
int reqnumargs;
crule_funcptr funcptr;
};
struct crule_funclistent crule_funclist[] =
{
/* maximum function name length is 14 chars */
{"connected", 1, crule_connected},
{"directcon", 1, crule_directcon},
{"via", 2, crule_via},
{"directop", 0, crule_directop},
{"", 0, NULL} /* this must be here to mark end of list */
};
int crule_connected (numargs, crulearg)
int numargs;
void *crulearg[];
{
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
aClient *acptr;
/* taken from m_links */
for (acptr = client; acptr; acptr = acptr->next)
{
if (!IsServer(acptr) && !IsMe(acptr))
continue;
if (match((char *) crulearg[0], acptr->name))
continue;
return (1);
}
return (0);
#endif
}
int crule_directcon (numargs, crulearg)
int numargs;
void *crulearg[];
{
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
int i;
aClient *acptr;
/* adapted from m_trace and exit_one_client */
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]) || !IsServer(acptr))
continue;
if (match((char *) crulearg[0], acptr->name))
continue;
return (1);
}
return (0);
#endif
}
int crule_via (numargs, crulearg)
int numargs;
void *crulearg[];
{
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
aClient *acptr;
/* adapted from m_links */
for (acptr = client; acptr; acptr = acptr->next)
{
if (!IsServer(acptr) && !IsMe(acptr))
continue;
if (match((char *) crulearg[1], acptr->name))
continue;
if (match((char *) crulearg[0], (local[acptr->from->fd])->name))
continue;
return (1);
}
return (0);
#endif
}
int crule_directop (numargs, crulearg)
int numargs;
void *crulearg[];
{
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
int i;
aClient *acptr;
/* adapted from m_trace */
for (i = 0; i <= highest_fd; i++)
{
if (!(acptr = local[i]) || !IsAnOper(acptr))
continue;
return (1);
}
return (0);
#endif
}
int crule__andor (numargs, crulearg)
int numargs;
void *crulearg[];
{
int result1;
result1 = ((crule_treeptr) crulearg[0])->funcptr
(((crule_treeptr) crulearg[0])->numargs,
(void *) ((crule_treeptr) crulearg[0])->arg);
if (crulearg[2]) /* or */
return (result1 ||
((crule_treeptr) crulearg[1])->funcptr
(((crule_treeptr) crulearg[1])->numargs,
(void *) ((crule_treeptr) crulearg[1])->arg));
else
return (result1 &&
((crule_treeptr) crulearg[1])->funcptr
(((crule_treeptr) crulearg[1])->numargs,
(void *) ((crule_treeptr) crulearg[1])->arg));
}
int crule__not (numargs, crulearg)
int numargs;
void *crulearg[];
{
return (!((crule_treeptr) crulearg[0])->funcptr
(((crule_treeptr) crulearg[0])->numargs,
(void *) ((crule_treeptr) crulearg[0])->arg));
}
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
int crule_eval (rule)
char *rule;
{
return (((crule_treeptr) rule)->funcptr
(((crule_treeptr) rule)->numargs,
((crule_treeptr) rule)->arg));
}
#endif
int crule_gettoken (next_tokp, ruleptr)
int *next_tokp;
char **ruleptr;
{
char pending = '\0';
*next_tokp = CR_UNKNOWN;
while (*next_tokp == CR_UNKNOWN)
switch (*(*ruleptr)++)
{
case ' ': case '\t':
break;
case '&':
if (pending == '\0')
pending = '&';
else if (pending == '&')
*next_tokp = CR_AND;
else
return (CR_UNKNWTOK);
break;
case '|':
if (pending == '\0')
pending = '|';
else if (pending == '|')
*next_tokp = CR_OR;
else
return (CR_UNKNWTOK);
break;
case '!':
*next_tokp = CR_NOT;
break;
case '(':
*next_tokp = CR_OPENPAREN;
break;
case ')':
*next_tokp = CR_CLOSEPAREN;
break;
case ',':
*next_tokp = CR_COMMA;
break;
case '\0':
(*ruleptr)--;
*next_tokp = CR_END;
break;
case ':':
*next_tokp = CR_END;
break;
default:
if ((isalpha (*(--(*ruleptr)))) || (**ruleptr == '*') ||
(**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-'))
*next_tokp = CR_WORD;
else
return (CR_UNKNWTOK);
break;
}
return CR_NOERR;
}
void crule_getword (word, wordlenp, maxlen, ruleptr)
char *word;
int *wordlenp;
int maxlen;
char **ruleptr;
{
char *word_ptr;
word_ptr = word;
while ((isalnum (**ruleptr)) || (**ruleptr == '*') ||
(**ruleptr == '?') || (**ruleptr == '.') || (**ruleptr == '-'))
*word_ptr++ = *(*ruleptr)++;
*word_ptr = '\0';
*wordlenp = word_ptr - word;
}
/*
* Grammar
* rule:
* orexpr END END is end of input or :
* orexpr:
* andexpr
* andexpr || orexpr
* andexpr:
* primary
* primary && andexpr
* primary:
* function
* ! primary
* ( orexpr )
* function:
* word ( ) word is alphanumeric string, first character
* word ( arglist ) must be a letter
* arglist:
* word
* word , arglist
*/
char *crule_parse (rule)
char *rule;
{
char *ruleptr = rule;
int next_tok;
crule_treeptr ruleroot = NULL;
int errcode = CR_NOERR;
if ((errcode = crule_gettoken (&next_tok, &ruleptr)) == CR_NOERR)
if ((errcode = crule_parseorexpr (&ruleroot, &next_tok,
&ruleptr)) == CR_NOERR)
if (ruleroot != NULL)
if (next_tok == CR_END)
return ((char *) ruleroot);
else
errcode = CR_UNEXPCTTOK;
else
errcode = CR_EXPCTOR;
if (ruleroot != NULL)
crule_free ((char **) &ruleroot);
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
Debug ((DEBUG_ERROR, "%s in rule: %s", crule_errstr[errcode], rule));
#else
(void) fprintf (stderr, "%s in rule: %s\n", crule_errstr[errcode], rule);
#endif
return NULL;
}
int crule_parseorexpr (orrootp, next_tokp, ruleptr)
crule_treeptr *orrootp;
int *next_tokp;
char **ruleptr;
{
int errcode = CR_NOERR;
crule_treeptr andexpr;
crule_treeptr orptr;
*orrootp = NULL;
while (errcode == CR_NOERR)
{
errcode = crule_parseandexpr (&andexpr, next_tokp, ruleptr);
if ((errcode == CR_NOERR) && (*next_tokp == CR_OR))
{
orptr = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
#ifdef CR_DEBUG
(void) fprintf (stderr, "allocating or element at %ld\n", orptr);
#endif
orptr->funcptr = crule__andor;
orptr->numargs = 3;
orptr->arg[2] = (void *) 1;
if (*orrootp != NULL)
{
(*orrootp)->arg[1] = andexpr;
orptr->arg[0] = *orrootp;
}
else
orptr->arg[0] = andexpr;
*orrootp = orptr;
}
else
{
if (*orrootp != NULL)
if (andexpr != NULL)
{
(*orrootp)->arg[1] = andexpr;
return (errcode);
}
else
{
(*orrootp)->arg[1] = NULL; /* so free doesn't seg fault */
return (CR_EXPCTAND);
}
else
{
*orrootp = andexpr;
return (errcode);
}
}
if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
return (errcode);
}
return (errcode);
}
int crule_parseandexpr (androotp, next_tokp, ruleptr)
crule_treeptr *androotp;
int *next_tokp;
char **ruleptr;
{
int errcode = CR_NOERR;
crule_treeptr primary;
crule_treeptr andptr;
*androotp = NULL;
while (errcode == CR_NOERR)
{
errcode = crule_parseprimary (&primary, next_tokp, ruleptr);
if ((errcode == CR_NOERR) && (*next_tokp == CR_AND))
{
andptr = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
#ifdef CR_DEBUG
(void) fprintf (stderr, "allocating and element at %ld\n", andptr);
#endif
andptr->funcptr = crule__andor;
andptr->numargs = 3;
andptr->arg[2] = (void *) 0;
if (*androotp != NULL)
{
(*androotp)->arg[1] = primary;
andptr->arg[0] = *androotp;
}
else
andptr->arg[0] = primary;
*androotp = andptr;
}
else
{
if (*androotp != NULL)
if (primary != NULL)
{
(*androotp)->arg[1] = primary;
return (errcode);
}
else
{
(*androotp)->arg[1] = NULL; /* so free doesn't seg fault */
return (CR_EXPCTPRIM);
}
else
{
*androotp = primary;
return (errcode);
}
}
if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
return (errcode);
}
return (errcode);
}
int crule_parseprimary (primrootp, next_tokp, ruleptr)
crule_treeptr *primrootp;
int *next_tokp;
char **ruleptr;
{
crule_treeptr *insertionp;
int errcode = CR_NOERR;
*primrootp = NULL;
insertionp = primrootp;
while (errcode == CR_NOERR)
{
switch (*next_tokp)
{
case CR_OPENPAREN:
if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
break;
if ((errcode = crule_parseorexpr (insertionp, next_tokp,
ruleptr)) != CR_NOERR)
break;
if (*insertionp == NULL)
{
errcode = CR_EXPCTAND;
break;
}
if (*next_tokp != CR_CLOSEPAREN)
{
errcode = CR_EXPCTCLOSE;
break;
}
errcode = crule_gettoken (next_tokp, ruleptr);
break;
case CR_NOT:
*insertionp = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
#ifdef CR_DEBUG
(void) fprintf (stderr,
"allocating primary element at %ld\n", *insertionp);
#endif
(*insertionp)->funcptr = crule__not;
(*insertionp)->numargs = 1;
(*insertionp)->arg[0] = NULL;
insertionp = (crule_treeptr *) &((*insertionp)->arg[0]);
if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
break;
continue;
case CR_WORD:
errcode = crule_parsefunction (insertionp, next_tokp, ruleptr);
break;
default:
if (*primrootp == NULL)
errcode = CR_NOERR;
else
errcode = CR_EXPCTPRIM;
break;
}
return (errcode);
}
return (errcode);
}
int crule_parsefunction (funcrootp, next_tokp, ruleptr)
crule_treeptr *funcrootp;
int *next_tokp;
char **ruleptr;
{
int errcode = CR_NOERR;
char funcname[CR_MAXARGLEN];
int namelen;
int funcnum;
*funcrootp = NULL;
crule_getword (funcname, &namelen, CR_MAXARGLEN, ruleptr);
if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
return (errcode);
if (*next_tokp == CR_OPENPAREN)
{
for (funcnum = 0; ; funcnum++)
{
if (mycmp (crule_funclist[funcnum].name, funcname) == 0)
break;
if (crule_funclist[funcnum].name[0] == '\0')
return (CR_UNKNWFUNC);
}
if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
return (errcode);
*funcrootp = (crule_treeptr) MyMalloc (sizeof (crule_treeelem));
#ifdef CR_DEBUG
(void) fprintf (stderr, "allocating function element at %ld\n",
*funcrootp);
#endif
(*funcrootp)->funcptr = NULL; /* for freeing aborted trees */
if ((errcode = crule_parsearglist (*funcrootp, next_tokp,
ruleptr)) != CR_NOERR)
return (errcode);
if (*next_tokp != CR_CLOSEPAREN)
return (CR_EXPCTCLOSE);
if ((crule_funclist[funcnum].reqnumargs != (*funcrootp)->numargs) &&
(crule_funclist[funcnum].reqnumargs != -1))
return (CR_ARGMISMAT);
if ((errcode = crule_gettoken (next_tokp, ruleptr)) != CR_NOERR)
return (errcode);
(*funcrootp)->funcptr = crule_funclist[funcnum].funcptr;
return (CR_NOERR);
}
else
return (CR_EXPCTOPEN);
}
int crule_parsearglist (argrootp, next_tokp, ruleptr)
crule_treeptr argrootp;
int *next_tokp;
char **ruleptr;
{
int errcode = CR_NOERR;
char *argelemp = NULL;
char currarg[CR_MAXARGLEN];
int arglen = 0;
char word[CR_MAXARGLEN];
int wordlen = 0;
argrootp->numargs = 0;
currarg[0] = '\0';
while (errcode == CR_NOERR)
{
switch (*next_tokp)
{
case CR_WORD:
crule_getword (word, &wordlen, CR_MAXARGLEN, ruleptr);
if (currarg[0] != '\0')
{
if ((arglen + wordlen) < (CR_MAXARGLEN - 1))
{
strcat (currarg, " ");
strcat (currarg, word);
arglen += wordlen + 1;
}
}
else
{
strcpy (currarg, word);
arglen = wordlen;
}
errcode = crule_gettoken (next_tokp, ruleptr);
break;
default:
#if !defined(CR_DEBUG) && !defined(CR_CHKCONF)
(void) collapse (currarg);
#endif
if (!BadPtr (currarg))
{
DupString (argelemp, currarg);
argrootp->arg[argrootp->numargs++] = (void *) argelemp;
}
if (*next_tokp != CR_COMMA)
return (CR_NOERR);
currarg[0] = '\0';
errcode = crule_gettoken (next_tokp, ruleptr);
break;
}
}
return (errcode);
}
/*
* this function is recursive.. i wish i knew a nonrecursive way but
* i dont. anyway, recursion is fun.. :)
* DO NOT CALL THIS FUNTION WITH A POINTER TO A NULL POINTER
* (ie: if *elem is NULL, you're doing it wrong - seg fault)
*/
void crule_free (elem)
char **elem;
{
int arg, numargs;
if ((*((crule_treeptr *) elem))->funcptr == crule__not)
{
/* type conversions and ()'s are fun! ;) here have an asprin.. */
if ((*((crule_treeptr *)elem))->arg[0] != NULL)
crule_free ((char **) &((*((crule_treeptr *) elem))->arg[0]));
}
else if ((*((crule_treeptr *)elem))->funcptr == crule__andor)
{
crule_free ((char **) &((*((crule_treeptr *) elem))->arg[0]));
if ((*((crule_treeptr *)elem))->arg[1] != NULL)
crule_free ((char **) &((*((crule_treeptr *) elem))->arg[1]));
}
else
{
numargs = (*((crule_treeptr *) elem))->numargs;
for (arg = 0; arg < numargs; arg++)
MyFree ((char *) (*((crule_treeptr *) elem))->arg[arg]);
}
#ifdef CR_DEBUG
(void) fprintf (stderr, "freeing element at %ld\n", *elem);
#endif
MyFree (*elem);
*elem = NULL;
}
#ifdef CR_DEBUG
void print_tree (printelem)
crule_treeptr printelem;
{
int funcnum, arg;
if (printelem->funcptr == crule__not)
{
printf ("!( ");
print_tree ((crule_treeptr) printelem->arg[0]);
printf (") ");
}
else if (printelem->funcptr == crule__andor)
{
printf ("( ");
print_tree ((crule_treeptr) printelem->arg[0]);
if (printelem->arg[2])
printf ("|| ");
else
printf ("&& ");
print_tree ((crule_treeptr) printelem->arg[1]);
printf (") ");
}
else
{
for (funcnum = 0; ;funcnum++)
{
if (printelem->funcptr == crule_funclist[funcnum].funcptr)
break;
if (crule_funclist[funcnum].funcptr == NULL)
{
printf ("\nACK! *koff* *sputter*\n");
exit (1);
}
}
printf ("%s(", crule_funclist[funcnum].name);
for (arg = 0; arg < printelem->numargs; arg++)
{
if (arg != 0)
printf (",");
printf ("%s", (char *) printelem->arg[arg]);
}
printf (") ");
}
}
#endif
#ifdef CR_DEBUG
void main ()
{
char indata[256];
char *rule;
printf ("rule: ");
while (fgets (indata, 256, stdin) != NULL)
{
indata[strlen (indata) - 1] = '\0'; /* lose the newline */
if ((rule = crule_parse (indata)) != NULL)
{
printf ("equivalent rule: ");
print_tree ((crule_treeptr) rule);
printf ("\n");
crule_free (&rule);
}
printf ("\nrule: ");
}
printf ("\n");
}
#endif

35
ircd/crypt/Makefile Normal file
View File

@@ -0,0 +1,35 @@
#************************************************************************
#* IRC - Internet Relay Chat, ircd/crypt/Makefile
#* Copyright (C) 1991 Darren Reed
#*
#* 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.
#*/
#
# Change this to the path of your local ircd.conf file
#
IRCDCONF = /home/407/avalon/ircd.conf
all: mkpasswd
crypt: install
mkpasswd: mkpasswd.c
cc -O mkpasswd.c -o mkpasswd
install:
crypter ${IRCDCONF}
@echo 'done.'
clean:
/bin/rm -f mkpasswd

61
ircd/crypt/README Normal file
View File

@@ -0,0 +1,61 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/crypt/README
* Copyright (C) 1991 Nelson Minar
*
* 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.
*/
The change implemented here is that the operator password in irc.conf
is no longer stored in plaintext form, but is encrypted the same way
that user passwords are encrypted on normal UNIX systems. Ie, instead
of having
O:*:goodboy:Nelson
in your ircd.conf file, you have
O:*:sCnvYRmbFJ7oI:Nelson
You still type "/oper Nelson goodboy" to become operator. However, if
someone gets ahold of your irc.conf file, they can no longer figure
out what the password is from reading it. There are still other
security holes, namely server-server passwords, but this closes one
obvious problem.
So how do you generate these icky looking strings for passwords?
There's a simple program called mkpasswd to do that for you. Just run
mkpasswd, and at the prompt type in your plaintext password. It will
spit out the encrypted password, which you should then just copy into
the irc.conf file. This should be done only when adding new passwords
to your irc.conf file. To change over your irc.conf file to use
encrypted passwords, define CRYPT_OPER_PASSWORD in config.h. You will
need to recompile your server if you already compiled it with this
feature disabled. Once compiled, edit the Makefile in this directory
and chang "IRCDCONF" to your irc.conf file. Then "make install" in this
directory to replace all the operator passwords in your irc.conf file
with the encrypted format.
Choose your passwords carefully. Do not choose something in a
dictionary, make sure its at least 5 characters. Anything past 8
characters is ignored.
One thing to note about crypt() passwords - for every plaintext, there
are 4096 different passwords. Some valid encryptions of "goodboy"
include t1Ub2RhRQHd4g sCnvYRmbFJ7oI and Xr4Z.Kg5tcdy6. The first
two characters (the "salt") determine which of the 4096 passwords
you will get. mkpasswd chooses the salt randomly, or alternately
will let you specify one on the command line.
see also - crypt(3)

52
ircd/crypt/crypter Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/local/bin/perl
#************************************************************************
#* IRC - Internet Relay Chat, ircd/crypt/crypter
#* Copyright (C) 1991 Sean Batt
#*
#* 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.
#*/
#From Sean Batt sean@coombs.anu.edu.au
#
#Temporary output file
#
$tmpfile = "/tmp/ircd.conf.tmp";
#
#Original ircd.conf file
#
$ircdconf = @ARGV[0];
print "crypting ",$ircdconf,"\n";
@saltset = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '.', '/');
umask(0077);
open ($ircdout, ">/tmp/ircd.conf.tmp") || die "open $!";
while ($text = <>) {
#if its not an "O" line we can ignore it
$text =~ /^o/i || print ($ircdout $text) && next;
chop($text);
@oline = split(':', $text);
$salt = $saltset[rand(time)%64].$saltset[(rand(time)>>6)%64];
$oline[2] = crypt(@oline[2], $salt);
print ($ircdout join(':',@oline)."\n");
}
close ($ircdout);
close ($ircdin);
print "/bin/cp ",$tmpfile," ",$ircdconf,"\n";
(fork()==0) ? exec("/bin/cp", $tmpfile, $ircdconf) : wait;
#unlink($tmpfile);

40
ircd/crypt/mkpasswd.c Normal file
View File

@@ -0,0 +1,40 @@
/* simple password generator by Nelson Minar (minar@reed.edu)
* copyright 1991, all rights reserved.
* You can use this code as long as my name stays with it.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *getpass();
int main(argc, argv)
int argc;
char *argv[];
{
static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
char salt[3];
char * plaintext;
int i;
if (argc < 2) {
srandom(time(0)); /* may not be the BEST salt, but its close */
salt[0] = saltChars[random() % 64];
salt[1] = saltChars[random() % 64];
salt[2] = 0;
}
else {
salt[0] = argv[1][0];
salt[1] = argv[1][1];
salt[2] = '\0';
if ((strchr(saltChars, salt[0]) == NULL) || (strchr(saltChars, salt[1]) == NULL))
fprintf(stderr, "illegal salt %s\n", salt), exit(1);
}
plaintext = getpass("plaintext: ");
printf("%s\n", crypt(plaintext, salt));
return 0;
}

38
ircd/crypt/sums Executable file
View File

@@ -0,0 +1,38 @@
#!/bin/sh
# trap "" 1 2 3 13 14 15 21 22
trap "" 1 2 3 13 14 15
/bin/cp hash.c hash.c.old 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum s_bsd.c 2>/dev/null`
sed -e "s/SUSER/[${csum}]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum s_user.c 2>/dev/null`
sed -e "s/SSERV/[${csum}]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum s_serv.c 2>/dev/null`
sed -e "s/SBSDC/[${csum}]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum channel.c 2>/dev/null`
sed -e "s/CHANC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum ircd.c 2>/dev/null`
sed -e "s/IRCDC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum s_misc.c 2>/dev/null`
sed -e "s/SMISC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum hash.c.old 2>/dev/null`
sed -e "s/HASHC/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum version.c.SH 2>/dev/null`
sed -e "s/VERSH/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`sum s_bsd.c 2>/dev/null`
sed -e "s/MAKEF/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
if [ -f /bin/hostid ] ; then
/bin/mv -f hash.c hash.c.temp 1>/dev/null 2>&1
csum=`hostid 2>/dev/null`
sed -e "s/HOSTID/[$csum]/g" hash.c.temp > hash.c 2>/dev/null
fi
/bin/rm -f hash.c.temp 1>/dev/null 2>&1

755
ircd/hash.c Normal file
View File

@@ -0,0 +1,755 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/hash.c
* Copyright (C) 1991 Darren Reed
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)hash.c 2.10 7/3/93 (C) 1991 Darren Reed";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "hash.h"
#include "h.h"
#ifdef DEBUGMODE
static aHashEntry *clientTable = NULL;
static aHashEntry *channelTable = NULL;
static int clhits, clmiss;
static int chhits, chmiss;
int HASHSIZE = 2003;
int CHANNELHASHSIZE = 607;
#else
static aHashEntry clientTable[HASHSIZE];
static aHashEntry channelTable[CHANNELHASHSIZE];
#endif
static int hash_mult[] = { 173, 179, 181, 191, 193, 197,
199, 211, 223, 227, 229, 233,
239, 241, 251, 257, 263, 269,
271, 277, 281, 293, 307, 311,
401, 409, 419, 421, 431, 433,
439, 443, 449, 457, 461, 463
};
/*
* Hashing.
*
* The server uses a chained hash table to provide quick and efficient
* hash table mantainence (providing the hash function works evenly over
* the input range). The hash table is thus not susceptible to problems
* of filling all the buckets or the need to rehash.
* It is expected that the hash table would look somehting like this
* during use:
* +-----+ +-----+ +-----+ +-----+
* ---| 224 |----| 225 |----| 226 |---| 227 |---
* +-----+ +-----+ +-----+ +-----+
* | | |
* +-----+ +-----+ +-----+
* | A | | C | | D |
* +-----+ +-----+ +-----+
* |
* +-----+
* | B |
* +-----+
*
* A - GOPbot, B - chang, C - hanuaway, D - *.mu.OZ.AU
*
* The order shown above is just one instant of the server. Each time a
* lookup is made on an entry in the hash table and it is found, the entry
* is moved to the top of the chain.
*/
/*
* hash_nick_name
*
* this function must be *quick*. Thus there should be no multiplication
* or division or modulus in the inner loop. subtraction and other bit
* operations allowed.
*/
int hash_nick_name(nname)
char *nname;
{
Reg1 u_char *name = (u_char *)nname;
Reg2 u_char ch;
Reg4 int hash = 1, *tab;
for (tab = hash_mult; (ch = *name); name++, tab++)
hash += tolower(ch) + *tab + hash;
if (hash < 0)
hash = -hash;
hash %= HASHSIZE;
return (hash);
}
/*
* hash_channel_name
*
* calculate a hash value on at most the first 30 characters of the channel
* name. Most names are short than this or dissimilar in this range. There
* is little or no point hashing on a full channel name which maybe 255 chars
* long.
*/
int hash_channel_name(hname)
char *hname;
{
Reg1 u_char *name = (u_char *)hname;
Reg2 u_char ch;
Reg3 int i = 30;
Reg4 int hash = 5, *tab;
for (tab = hash_mult; (ch = *name) && --i; name++, tab++)
hash += tolower(ch) + *tab + hash + i + i;
if (hash < 0)
hash = -hash;
hash %= CHANNELHASHSIZE;
return (hash);
}
/*
* clear_*_hash_table
*
* Nullify the hashtable and its contents so it is completely empty.
*/
void clear_client_hash_table()
{
#ifdef DEBUGMODE
clhits = 0;
clmiss = 0;
if (!clientTable)
clientTable = (aHashEntry *)MyMalloc(HASHSIZE *
sizeof(aHashEntry));
#endif
bzero((char *)clientTable, sizeof(aHashEntry) * HASHSIZE);
}
void clear_channel_hash_table()
{
#ifdef DEBUGMODE
chmiss = 0;
chhits = 0;
if (!channelTable)
channelTable = (aHashEntry *)MyMalloc(CHANNELHASHSIZE *
sizeof(aHashEntry));
#endif
bzero((char *)channelTable, sizeof(aHashEntry) * CHANNELHASHSIZE);
}
/*
* add_to_client_hash_table
*/
int add_to_client_hash_table(name, cptr)
char *name;
aClient *cptr;
{
Reg1 int hashv;
hashv = hash_nick_name(name);
cptr->hnext = (aClient *)clientTable[hashv].list;
clientTable[hashv].list = (void *)cptr;
clientTable[hashv].links++;
clientTable[hashv].hits++;
return 0;
}
/*
* add_to_channel_hash_table
*/
int add_to_channel_hash_table(name, chptr)
char *name;
aChannel *chptr;
{
Reg1 int hashv;
hashv = hash_channel_name(name);
chptr->hnextch = (aChannel *)channelTable[hashv].list;
channelTable[hashv].list = (void *)chptr;
channelTable[hashv].links++;
channelTable[hashv].hits++;
return 0;
}
/*
* del_from_client_hash_table
*/
int del_from_client_hash_table(name, cptr)
char *name;
aClient *cptr;
{
Reg1 aClient *tmp, *prev = NULL;
Reg2 int hashv;
hashv = hash_nick_name(name);
for (tmp = (aClient *)clientTable[hashv].list; tmp; tmp = tmp->hnext)
{
if (tmp == cptr)
{
if (prev)
prev->hnext = tmp->hnext;
else
clientTable[hashv].list = (void *)tmp->hnext;
tmp->hnext = NULL;
if (clientTable[hashv].links > 0)
{
clientTable[hashv].links--;
return 1;
}
else
/*
* Should never actually return from here and
* if we do it is an error/inconsistency in the
* hash table.
*/
return -1;
}
prev = tmp;
}
return 0;
}
/*
* del_from_channel_hash_table
*/
int del_from_channel_hash_table(name, chptr)
char *name;
aChannel *chptr;
{
Reg1 aChannel *tmp, *prev = NULL;
Reg2 int hashv;
hashv = hash_channel_name(name);
for (tmp = (aChannel *)channelTable[hashv].list; tmp;
tmp = tmp->hnextch)
{
if (tmp == chptr)
{
if (prev)
prev->hnextch = tmp->hnextch;
else
channelTable[hashv].list=(void *)tmp->hnextch;
tmp->hnextch = NULL;
if (channelTable[hashv].links > 0)
{
channelTable[hashv].links--;
return 1;
}
else
return -1;
}
prev = tmp;
}
return 0;
}
/*
* hash_find_client
*/
aClient *hash_find_client(name, cptr)
char *name;
aClient *cptr;
{
Reg1 aClient *tmp;
Reg2 aClient *prv = NULL;
Reg3 aHashEntry *tmp3;
int hashv;
#ifdef TESTNET
Reg4 aClient *tmp_fnd = NULL, *prv_fnd = NULL;
#endif
hashv = hash_nick_name(name);
tmp3 = &clientTable[hashv];
/*
* Got the bucket, now search the chain.
*/
for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
{
if (IsPing(tmp))
continue;
#ifdef TESTNET
if (mycmp(name, tmp->name) == 0)
{
if (tmp_fnd)
sendto_ops("*** DEBUG ERROR *** : Found %s TWICE !",
tmp->name);
else
{
tmp_fnd=tmp;
prv_fnd=prv;
}
}
#else
if (mycmp(name, tmp->name) == 0)
goto c_move_to_top;
#endif
}
#ifdef TESTNET
if (tmp_fnd)
{
tmp=tmp_fnd;
prv=prv_fnd;
goto c_move_to_top;
}
#endif
#ifdef DEBUGMODE
clmiss++;
#endif
return (cptr);
c_move_to_top:
#ifdef DEBUGMODE
clhits++;
#endif
/*
* If the member of the hashtable we found isnt at the top of its
* chain, put it there. This builds a most-frequently used order into
* the chains of the hash table, giving speadier lookups on those nicks
* which are being used currently. This same block of code is also
* used for channels and servers for the same performance reasons.
*/
if (prv)
{
aClient *tmp2;
tmp2 = (aClient *)tmp3->list;
tmp3->list = (void *)tmp;
prv->hnext = tmp->hnext;
tmp->hnext = tmp2;
}
return (tmp);
}
/*
* hash_find_nickserver
*/
aClient *hash_find_nickserver(name, cptr)
char *name;
aClient *cptr;
{
Reg1 aClient *tmp;
Reg2 aClient *prv = NULL;
Reg3 aHashEntry *tmp3;
int hashv;
char *serv;
serv = index(name, '@');
*serv++ = '\0';
hashv = hash_nick_name(name);
tmp3 = &clientTable[hashv];
/*
* Got the bucket, now search the chain.
*/
for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
if (mycmp(name, tmp->name) == 0 && tmp->user &&
mycmp(serv, tmp->user->server->name) == 0)
goto c_move_to_top;
#ifdef DEBUGMODE
clmiss++;
#endif
*--serv = '\0';
return (cptr);
c_move_to_top:
#ifdef DEBUGMODE
clhits++;
#endif
/*
* If the member of the hashtable we found isnt at the top of its
* chain, put it there. This builds a most-frequently used order into
* the chains of the hash table, giving speadier lookups on those nicks
* which are being used currently. This same block of code is also
* used for channels and servers for the same performance reasons.
*/
if (prv)
{
aClient *tmp2;
tmp2 = (aClient *)tmp3->list;
tmp3->list = (void *)tmp;
prv->hnext = tmp->hnext;
tmp->hnext = tmp2;
}
*--serv = '\0';
return (tmp);
}
/*
* hash_find_server
*/
aClient *hash_find_server(server, cptr)
char *server;
aClient *cptr;
{
Reg1 aClient *tmp, *prv = NULL;
Reg2 char *t;
Reg3 char ch;
aHashEntry *tmp3;
int hashv;
hashv = hash_nick_name(server);
tmp3 = &clientTable[hashv];
for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext)
{
if (!IsServer(tmp) && !IsMe(tmp))
continue;
if (mycmp(server, tmp->name) == 0)
goto s_move_to_top;
}
t = ((char *)server + strlen(server));
/*
* Whats happening in this next loop ? Well, it takes a name like
* foo.bar.edu and proceeds to search for *.edu and then *.bar.edu.
* This is for checking full server names against masks although
* it isnt often done this way in lieu of using matches().
*/
for (;;)
{
t--;
for (; t > server; t--)
if (*(t+1) == '.')
break;
if (t <= server || *t == '*')
break;
ch = *t;
*t = '*';
/*
* Dont need to check IsServer() here since nicknames cant
*have *'s in them anyway.
*/
if (((tmp = hash_find_client(t, cptr))) != cptr)
{
*t = ch;
return (tmp);
}
*t = ch;
}
#ifdef DEBUGMODE
clmiss++;
#endif
return (cptr);
s_move_to_top:
#ifdef DEBUGMODE
clhits++;
#endif
if (prv)
{
aClient *tmp2;
tmp2 = (aClient *)tmp3->list;
tmp3->list = (void *)tmp;
prv->hnext = tmp->hnext;
tmp->hnext = tmp2;
}
return (tmp);
}
/*
* hash_find_channel
*/
aChannel *hash_find_channel(name, chptr)
char *name;
aChannel *chptr;
{
int hashv;
Reg1 aChannel *tmp, *prv = NULL;
aHashEntry *tmp3;
hashv = hash_channel_name(name);
tmp3 = &channelTable[hashv];
for (tmp = (aChannel *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnextch)
if (mycmp(name, tmp->chname) == 0)
goto c_move_to_top;
#ifdef DEBUGMODE
chmiss++;
#endif
return chptr;
c_move_to_top:
#ifdef DEBUGMODE
chhits++;
#endif
if (prv)
{
register aChannel *tmp2;
tmp2 = (aChannel *)tmp3->list;
tmp3->list = (void *)tmp;
prv->hnextch = tmp->hnextch;
tmp->hnextch = tmp2;
}
return (tmp);
}
/*
* NOTE: this command is not supposed to be an offical part of the ircd
* protocol. It is simply here to help debug and to monitor the
* performance of the hash functions and table, enabling a better
* algorithm to be sought if this one becomes troublesome.
* -avalon
*/
int m_hash(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
#ifdef DEBUGMODE
register int l, i;
register aHashEntry *tab;
int deepest = 0, deeplink = 0, showlist = 0, tothits = 0;
int mosthit = 0, mosthits = 0, used = 0, used_now = 0, totlink = 0;
int link_pop[10], size = HASHSIZE;
char ch;
aHashEntry *table;
if (parc > 1) {
ch = *parv[1];
if (islower(ch))
table = clientTable;
else {
table = channelTable;
size = CHANNELHASHSIZE;
}
if (ch == 'L' || ch == 'l')
showlist = 1;
} else {
ch = '\0';
table = clientTable;
}
for (i = 0; i < 10; i++)
link_pop[i] = 0;
for (i = 0; i < size; i++) {
tab = &table[i];
l = tab->links;
if (showlist)
sendto_one(sptr,
"NOTICE %s :Hash Entry:%6d Hits:%7d Links:%6d",
parv[0], i, tab->hits, l);
if (l > 0) {
if (l < 10)
link_pop[l]++;
else
link_pop[9]++;
used_now++;
totlink += l;
if (l > deepest) {
deepest = l;
deeplink = i;
}
}
else
link_pop[0]++;
l = tab->hits;
if (l) {
used++;
tothits += l;
if (l > mosthits) {
mosthits = l;
mosthit = i;
}
}
}
switch((int)ch)
{
case 'V' : case 'v' :
{
register aClient *acptr;
int bad = 0, listlength = 0;
for (acptr = client; acptr; acptr = acptr->next) {
if (hash_find_client(acptr->name,acptr) != acptr) {
if (ch == 'V')
sendto_one(sptr, "NOTICE %s :Bad hash for %s",
parv[0], acptr->name);
bad++;
}
listlength++;
}
sendto_one(sptr,"NOTICE %s :List Length: %d Bad Hashes: %d",
parv[0], listlength, bad);
}
case 'P' : case 'p' :
for (i = 0; i < 10; i++)
sendto_one(sptr,"NOTICE %s :Entires with %d links : %d",
parv[0], i, link_pop[i]);
return (0);
case 'r' :
{
Reg1 aClient *acptr;
sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]);
clear_client_hash_table();
for (acptr = client; acptr; acptr = acptr->next)
if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
!IsPing(acptr))
(void)add_to_client_hash_table(acptr->name, acptr);
break;
}
case 'R' :
{
Reg1 aChannel *acptr;
sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]);
clear_channel_hash_table();
for (acptr = channel; acptr; acptr = acptr->nextch)
(void)add_to_channel_hash_table(acptr->chname, acptr);
break;
}
case 'H' :
if (parc > 2)
sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
parv[0], parv[2],
hash_channel_name(parv[2]));
return (0);
case 'h' :
if (parc > 2)
sendto_one(sptr,"NOTICE %s :%s hash to entry %d",
parv[0], parv[2],
hash_nick_name(parv[2]));
return (0);
case 'n' :
{
aClient *tmp;
int max;
if (parc <= 2)
return (0);
l = atoi(parv[2]) % HASHSIZE;
if (parc > 3)
max = atoi(parv[3]) % HASHSIZE;
else
max = l;
for (;l <= max; l++)
for (i = 0, tmp = (aClient *)clientTable[l].list; tmp;
i++, tmp = tmp->hnext)
{
if (parv[1][2] == '1' && tmp != tmp->from)
continue;
sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
parv[0], l, i, tmp->name);
}
return (0);
}
case 'N' :
{
aChannel *tmp;
int max;
if (parc <= 2)
return (0);
l = atoi(parv[2]) % CHANNELHASHSIZE;
if (parc > 3)
max = atoi(parv[3]) % CHANNELHASHSIZE;
else
max = l;
for (;l <= max; l++)
for (i = 0, tmp = (aChannel *)channelTable[l].list; tmp;
i++, tmp = tmp->hnextch)
sendto_one(sptr,"NOTICE %s :Node: %d #%d %s",
parv[0], l, i, tmp->chname);
return (0);
}
case 'S' :
#else
if (parc>1&&!strcmp(parv[1],"sums")){
#endif
sendto_one(sptr, "NOTICE %s :SUSER SSERV", parv[0]);
sendto_one(sptr, "NOTICE %s :SBSDC IRCDC", parv[0]);
sendto_one(sptr, "NOTICE %s :CHANC SMISC", parv[0]);
sendto_one(sptr, "NOTICE %s :HASHC VERSH", parv[0]);
sendto_one(sptr, "NOTICE %s :MAKEF HOSTID", parv[0]);
#ifndef DEBUGMODE
}
#endif
return 0;
#ifdef DEBUGMODE
case 'z' :
{
Reg1 aClient *acptr;
if (parc <= 2)
return 0;
l = atoi(parv[2]);
if (l < 256)
return 0;
(void)free((char *)clientTable);
clientTable = (aHashEntry *)malloc(sizeof(aHashEntry) * l);
HASHSIZE = l;
clear_client_hash_table();
for (acptr = client; acptr; acptr = acptr->next)
if (!IsUnknown(acptr) && !IsConnecting(acptr) &&
!IsPing(acptr))
{
acptr->hnext = NULL;
(void)add_to_client_hash_table(acptr->name, acptr);
}
sendto_one(sptr, "NOTICE %s :HASHSIZE now %d", parv[0], l);
break;
}
case 'Z' :
{
Reg1 aChannel *acptr;
if (parc <= 2)
return 0;
l = atoi(parv[2]);
if (l < 256)
return 0;
(void)free((char *)channelTable);
channelTable = (aHashEntry *)malloc(sizeof(aHashEntry) * l);
CHANNELHASHSIZE = l;
clear_channel_hash_table();
for (acptr = channel; acptr; acptr = acptr->nextch)
{
acptr->hnextch = NULL;
(void)add_to_channel_hash_table(acptr->chname, acptr);
}
sendto_one(sptr, "NOTICE %s :CHANNELHASHSIZE now %d",
parv[0], l);
break;
}
default :
break;
}
sendto_one(sptr,"NOTICE %s :Entries Hashed: %d NonEmpty: %d of %d",
parv[0], totlink, used_now, size);
if (!used_now)
used_now = 1;
sendto_one(sptr,"NOTICE %s :Hash Ratio (av. depth): %f %Full: %f",
parv[0], (float)((1.0 * totlink) / (1.0 * used_now)),
(float)((1.0 * used_now) / (1.0 * size)));
sendto_one(sptr,"NOTICE %s :Deepest Link: %d Links: %d",
parv[0], deeplink, deepest);
if (!used)
used = 1;
sendto_one(sptr,"NOTICE %s :Total Hits: %d Unhit: %d Av Hits: %f",
parv[0], tothits, size-used,
(float)((1.0 * tothits) / (1.0 * used)));
sendto_one(sptr,"NOTICE %s :Entry Most Hit: %d Hits: %d",
parv[0], mosthit, mosthits);
sendto_one(sptr,"NOTICE %s :Client hits %d miss %d",
parv[0], clhits, clmiss);
sendto_one(sptr,"NOTICE %s :Channel hits %d miss %d",
parv[0], chhits, chmiss);
return 0;
#endif
}

882
ircd/ircd.c Normal file
View File

@@ -0,0 +1,882 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/ircd.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.
*/
#ifndef lint
static char sccsid[] = "@(#)ircd.c 2.48 3/9/94 (C) 1988 University of Oulu, \
Computing Center and Jarkko Oikarinen";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "userload.h"
#include <sys/file.h>
#include <sys/stat.h>
#include <pwd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>
#include "h.h"
aClient me; /* That's me */
aClient *client = &me; /* Pointer to beginning of Client list */
void server_reboot();
void restart PROTO((char *));
static void open_debugfile(), setup_signals();
char **myargv;
int portnum = -1; /* Server port number, listening this */
char *configfile = CONFIGFILE; /* Server configuration file */
int debuglevel = -1; /* Server debug level */
int bootopt = 0; /* Server boot option flags */
char *debugmode = ""; /* -"- -"- -"- */
char *sbrk0; /* initial sbrk(0) */
int dorehash = 0;
static char *dpath = DPATH;
time_t nextconnect = 1; /* time for next try_connections call */
time_t nextping = 1; /* same as above for check_pings() */
time_t nextdnscheck = 0; /* next time to poll dns to force timeouts */
time_t nextexpire = 1; /* next expire run on the dns cache */
time_t now; /* Updated every time we leave select(), and used everywhere else */
extern char *last_dead_comment;
#ifdef PROFIL
extern etext();
VOIDSIG s_monitor()
{
static int mon = 0;
#ifdef POSIX_SIGNALS
struct sigaction act;
#endif
(void)moncontrol(mon);
mon = 1 - mon;
#ifdef POSIX_SIGNALS
act.sa_handler = s_rehash;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGUSR1);
(void)sigaction(SIGUSR1, &act, NULL);
#else
(void)signal(SIGUSR1, s_monitor);
#endif
}
#endif
VOIDSIG s_die()
{
#ifdef USE_SYSLOG
(void)syslog(LOG_CRIT, "Server Killed By SIGTERM");
#endif
flush_connections(me.fd);
exit(-1);
}
static VOIDSIG s_rehash()
{
#ifdef POSIX_SIGNALS
struct sigaction act;
#endif
dorehash = 1;
#ifdef POSIX_SIGNALS
act.sa_handler = s_rehash;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGHUP);
(void)sigaction(SIGHUP, &act, NULL);
#else
(void)signal(SIGHUP, s_rehash); /* sysV -argv */
#endif
}
void restart(mesg)
char *mesg;
{
#ifdef USE_SYSLOG
(void)syslog(LOG_WARNING, "Restarting Server because: %s",mesg);
#endif
server_reboot();
}
VOIDSIG s_restart()
{
static int restarting = 0;
#ifdef USE_SYSLOG
(void)syslog(LOG_WARNING, "Server Restarting on SIGINT");
#endif
if (restarting == 0)
{
/* Send (or attempt to) a dying scream to oper if present */
restarting = 1;
server_reboot();
}
}
void server_reboot()
{
Reg1 int i;
sendto_ops("Aieeeee!!! Restarting server...");
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
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);
if (!(bootopt & (BOOT_INETD|BOOT_OPER)))
(void)execv(MYNAME, myargv);
#ifdef USE_SYSLOG
/* Have to reopen since it has been closed above */
openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
syslog(LOG_CRIT, "execv(%s,%s) failed: %m\n", MYNAME, myargv[0]);
closelog();
#endif
Debug((DEBUG_FATAL,"Couldn't restart server: %s", strerror(errno)));
exit(-1);
}
/*
** 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()
{
Reg1 aConfItem *aconf;
Reg2 aClient *cptr;
aConfItem **pconf;
int connecting, confrq;
time_t next = 0;
aClass *cltmp;
aConfItem *cconf, *con_conf;
int con_class = 0;
connecting = FALSE;
Debug((DEBUG_NOTICE,"Connection check at : %s", myctime(now)));
for (aconf = conf; aconf; aconf = aconf->next )
{
/* Also when already connecting! (update holdtimes) --SRB */
if (!(aconf->status & CONF_CONNECT_SERVER) || aconf->port <= 0)
continue;
cltmp = Class(aconf);
/*
** Skip this entry if the use of it is still on hold until
** future. Otherwise handle this entry (and set it on hold
** until next time). Will reset only hold times, if already
** made one successfull connection... [this algorithm is
** a bit fuzzy... -- msa >;) ]
*/
if ((aconf->hold > now))
{
if ((next > aconf->hold) || (next == 0))
next = aconf->hold;
continue;
}
confrq = get_con_freq(cltmp);
aconf->hold = now + confrq;
/*
** Found a CONNECT config with port specified, scan clients
** and see if this server is already connected?
*/
cptr = find_name(aconf->name, (aClient *)NULL);
if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) &&
(!connecting || (Class(cltmp) > con_class)))
{
/* Check connect rules to see if we're allowed to try */
for (cconf = conf; cconf; cconf = cconf->next)
if ((cconf->status & CONF_CRULE) &&
(matches(cconf->host, aconf->name) == 0))
if (crule_eval (cconf->passwd))
break;
if (!cconf)
{
con_class = Class(cltmp);
con_conf = aconf;
/* We connect only one at time... */
connecting = TRUE;
}
}
if ((next > aconf->hold) || (next == 0))
next = aconf->hold;
}
if (connecting)
{
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;
}
if (connect_server(con_conf, (aClient *)NULL,
(struct hostent *)NULL) == 0)
sendto_ops("Connection to %s[%s] activated.",
con_conf->name, con_conf->host);
}
Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next)));
return (next);
}
static time_t check_pings()
{
Reg1 aClient *cptr;
int ping = 0, i, rflag = 0;
time_t oldest = 0, timeout;
for (i = 0; i <= highest_fd; i++)
{
if (!(cptr = local[i]) || IsMe(cptr) ||
IsLog(cptr) || IsPing(cptr)) continue;
/*
** Note: No need to notify opers here. It's
** already done when "FLAGS_DEADSOCKET" is set.
*/
if (IsDead(cptr))
{
(void)exit_client(cptr, cptr, &me, last_dead_comment);
continue;
}
#ifdef R_LINES_OFTEN
rflag = IsPerson(cptr) ? find_restrict(cptr) : 0;
#endif
ping = IsRegistered(cptr) ? get_client_ping(cptr) :
CONNECTTIMEOUT;
Debug((DEBUG_DEBUG, "c(%s)=%d p %d r %d a %d",
cptr->name, cptr->status, ping, rflag,
now - 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 (!rflag && IsRegistered(cptr) &&
(ping >= now - 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 (rflag ||
((now - cptr->lasttime) >= (2 * ping) &&
(cptr->flags & FLAGS_PINGSENT)) ||
(!IsRegistered(cptr) && !IsHandshake(cptr) &&
(now - cptr->firsttime) >= ping))
{
if (!IsRegistered(cptr) &&
(DoingDNS(cptr) || DoingAuth(cptr)))
{
if (cptr->authfd >= 0)
{
(void)close(cptr->authfd);
cptr->authfd = -1;
cptr->count = 0;
*cptr->buffer = '\0';
}
Debug((DEBUG_NOTICE,
"DNS/AUTH timeout %s",
get_client_name(cptr,TRUE)));
del_queries((char *)cptr);
ClearAuth(cptr);
ClearDNS(cptr);
SetAccess(cptr);
cptr->firsttime = now;
cptr->lasttime = now;
continue;
}
if (IsServer(cptr) || IsConnecting(cptr) ||
IsHandshake(cptr))
{
sendto_ops("No response from %s, closing link",
get_client_name(cptr, FALSE));
(void)exit_client(cptr, cptr, &me,
"Ping timeout");
continue;
}
/*
* this is used for KILL lines with time restrictions
* on them - send a messgae to the user being killed
* first.
*/
#if defined(R_LINES) && defined(R_LINES_OFTEN)
else if (IsPerson(cptr) && rflag)
{
sendto_ops("Restricting %s, closing link.",
get_client_name(cptr,FALSE));
(void)exit_client(cptr, cptr, &me, "R-lined");
}
#endif
else
{
if((!IsRegistered(cptr)) && (cptr->name) &&
(cptr->user->username))
{
sendto_one(cptr,
":%s %d %s :Your client may not be compatible with this server.",
me.name, ERR_BADPING, cptr->name);
sendto_one(cptr,
":%s %d %s :Compatible clients are available at ftp://ftp.undernet.org/pub/irc/clients",
me.name, ERR_BADPING, cptr->name);
}
(void)exit_client_msg(cptr, cptr, &me,
"Ping timeout for %s",
get_client_name(cptr,FALSE));
}
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 = now - ping;
sendto_one(cptr, "PING :%s", me.name);
}
ping_timeout:
timeout = cptr->lasttime + ping;
while (timeout <= now)
timeout += ping;
if (timeout < oldest || !oldest)
oldest = timeout;
}
if (!oldest || oldest < now)
oldest = now + PINGFREQUENCY;
Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d",
myctime(oldest), ping, oldest, now));
return (oldest);
}
/*
** bad_command
** This is called when the commandline is not acceptable.
** Give error message and exit without starting anything.
*/
static int bad_command()
{
(void)printf(
"Usage: ircd %s[-h servername] [-p portnumber] [-x loglevel] [-t]\n",
#ifdef CMDLINE_CONFIG
"[-f config] "
#else
""
#endif
);
(void)printf("Server not started\n\n");
return (-1);
}
int main(argc, argv)
int argc;
char *argv[];
{
int portarg = 0;
uid_t uid, euid;
time_t delay = 0;
#ifdef FORCE_CORE
struct rlimit corelim;
#endif
sbrk0 = (char *)sbrk((size_t)0);
uid = getuid();
euid = geteuid();
now = time(NULL);
#ifdef PROFIL
(void)monstartup(0, etext);
(void)moncontrol(1);
(void)signal(SIGUSR1, s_monitor);
#endif
#ifdef CHROOTDIR
if (chdir(dpath))
{
perror("chdir");
exit(-1);
}
res_init();
if (chroot(DPATH))
{
(void)fprintf(stderr,"ERROR: Cannot chdir/chroot\n");
exit(5);
}
#endif /*CHROOTDIR*/
myargv = argv;
(void)umask(077); /* better safe than sorry --SRB */
bzero((char *)&me, sizeof(me));
setup_signals();
initload();
#ifdef FORCE_CORE
corelim.rlim_cur = corelim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &corelim))
printf("unlimit core size failed; errno = %d\n", errno);
#endif
/*
** All command line parameters have the syntax "-fstring"
** or "-f string" (e.g. the space is optional). String may
** be empty. Flag characters cannot be concatenated (like
** "-fxyz"), it would conflict with the form "-fstring".
*/
while (--argc > 0 && (*++argv)[0] == '-')
{
char *p = argv[0]+1;
int flag = *p++;
if (flag == '\0' || *p == '\0')
if (argc > 1 && argv[1][0] != '-')
{
p = *++argv;
argc -= 1;
}
else
p = "";
switch (flag)
{
case 'a':
bootopt |= BOOT_AUTODIE;
break;
case 'c':
bootopt |= BOOT_CONSOLE;
break;
case 'q':
bootopt |= BOOT_QUICK;
break;
case 'd' :
(void)setuid((uid_t)uid);
dpath = p;
break;
case 'o': /* Per user local daemon... */
(void)setuid((uid_t)uid);
bootopt |= BOOT_OPER;
break;
#ifdef CMDLINE_CONFIG
case 'f':
(void)setuid((uid_t)uid);
configfile = p;
break;
#endif
case 'h':
strncpyzt(me.name, p, sizeof(me.name));
break;
case 'i':
bootopt |= BOOT_INETD|BOOT_AUTODIE;
break;
case 'p':
if ((portarg = atoi(p)) > 0 )
portnum = portarg;
break;
case 't':
(void)setuid((uid_t)uid);
bootopt |= BOOT_TTY;
break;
case 'v':
(void)printf("ircd %s\n", version);
exit(0);
case 'x':
#ifdef DEBUGMODE
(void)setuid((uid_t)uid);
debuglevel = atoi(p);
debugmode = *p ? p : "0";
bootopt |= BOOT_DEBUG;
break;
#else
(void)fprintf(stderr,
"%s: DEBUGMODE must be defined for -x y\n",
myargv[0]);
exit(0);
#endif
default:
bad_command();
break;
}
}
#ifndef CHROOT
if (chdir(dpath))
{
perror("chdir");
exit(-1);
}
#endif
#ifndef IRC_UID
if ((uid != euid) && !euid)
{
(void)fprintf(stderr,
"ERROR: do not run ircd setuid root. Make it setuid a\
normal user.\n");
exit(-1);
}
#endif
#if !defined(CHROOTDIR) || (defined(IRC_UID) && defined(IRC_GID))
# ifndef AIX
(void)setuid((uid_t)uid);
(void)setuid((uid_t)euid);
# endif
if ((int)getuid() == 0)
{
# if defined(IRC_UID) && defined(IRC_GID)
/* run as a specified user */
(void)fprintf(stderr,"WARNING: running ircd with uid = %d\n",
IRC_UID);
(void)fprintf(stderr," changing to gid %d.\n",IRC_GID);
(void)setuid(IRC_UID);
(void)setgid(IRC_GID);
#else
/* check for setuid root as usual */
(void)fprintf(stderr,
"ERROR: do not run ircd setuid root. Make it setuid a\
normal user.\n");
exit(-1);
# endif
}
#endif /*CHROOTDIR/UID/GID*/
/* didn't set debuglevel */
/* but asked for debugging output to tty */
if ((debuglevel < 0) && (bootopt & BOOT_TTY))
{
(void)fprintf(stderr,
"you specified -t without -x. use -x <n>\n");
exit(-1);
}
if (argc > 0)
return bad_command(); /* This should exit out */
clear_client_hash_table();
clear_channel_hash_table();
initlists();
initclass();
initwhowas();
initstats();
open_debugfile();
if (portnum < 0)
portnum = PORTNUM;
me.port = portnum;
(void)init_sys();
me.flags = FLAGS_LISTEN;
if (bootopt & BOOT_INETD)
{
me.fd = 0;
local[0] = &me;
me.flags = FLAGS_LISTEN;
}
else
me.fd = -1;
#ifdef USE_SYSLOG
openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY);
#endif
if (initconf(bootopt) == -1)
{
Debug((DEBUG_FATAL, "Failed in reading configuration file %s",
configfile));
(void)printf("Couldn't open configuration file %s\n",
configfile);
exit(-1);
}
if (!(bootopt & BOOT_INETD))
{
static char star[] = "*";
aConfItem *aconf;
if ((aconf = find_me()) && portarg <= 0 && aconf->port > 0)
portnum = aconf->port;
Debug((DEBUG_ERROR, "Port = %d", portnum));
if (inetport(&me, star, portnum))
exit(1);
}
else if (inetport(&me, "*", 0))
exit(1);
(void)setup_ping();
(void)get_my_name(&me, me.sockhost, sizeof(me.sockhost)-1);
if (me.name[0] == '\0')
strncpyzt(me.name, "undernet.org", sizeof(me.name));
now = time(NULL);
me.hopcount = 0;
me.authfd = -1;
me.confs = NULL;
me.next = NULL;
me.user = NULL;
me.from = &me;
SetMe(&me);
make_server(&me);
/* Abuse own link timestamp as start timestamp: */
me.serv->timestamp = TStime();
me.serv->prot = atoi(MAJOR_PROTOCOL);
me.serv->up = &me;
me.serv->down = NULL;
me.serv->client = NULL;
me.lasttime = me.since = me.firsttime = now;
(void)add_to_client_hash_table(me.name, &me);
check_class();
if (bootopt & BOOT_OPER)
{
aClient *tmp = add_connection(&me, 0);
if (!tmp)
exit(1);
SetMaster(tmp);
}
else
write_pidfile();
Debug((DEBUG_NOTICE,"Server ready..."));
#ifdef USE_SYSLOG
syslog(LOG_NOTICE, "Server Ready");
#endif
for (;;)
{
/*
** We only want to connect if a connection is due,
** not every time through. Note, if there are no
** active C lines, this call to Tryconnections is
** made once only; it will return 0. - avalon
*/
if (nextconnect && now >= nextconnect)
nextconnect = try_connections();
/*
** DNS checks. One to timeout queries, one for cache expiries.
*/
if (now >= nextdnscheck)
nextdnscheck = timeout_query_list();
if (now >= nextexpire)
nextexpire = expire_cache();
/*
** take the smaller of the two 'timed' event times as
** the time of next event (stops us being late :) - avalon
** WARNING - nextconnect can return 0!
*/
if (nextconnect)
delay = MIN(nextping, nextconnect);
else
delay = nextping;
delay = MIN(nextdnscheck, delay);
delay = MIN(nextexpire, delay);
delay -= now;
/*
** Adjust delay to something reasonable [ad hoc values]
** (one might think something more clever here... --msa)
** We don't really need to check that often and as long
** as we don't delay too long, everything should be ok.
** waiting too long can cause things to timeout...
** i.e. PINGS -> a disconnection :(
** - avalon
*/
if (delay < 1)
delay = 1;
else
delay = MIN(delay, TIMESEC);
(void)read_message(delay);
Debug((DEBUG_DEBUG ,"Got message(s)"));
/*
** ...perhaps should not do these loops every time,
** but only if there is some chance of something
** happening (but, note that conf->hold times may
** be changed elsewhere--so precomputed next event
** time might be too far away... (similarly with
** ping times) --msa
*/
if (now >= nextping)
nextping = check_pings();
if (dorehash)
{
(void)rehash(&me, &me, 1);
dorehash = 0;
}
/*
** Flush output buffers on all connections now if they
** have data in them (or at least try to flush)
** -avalon
*/
/* What is this doing here ??? Pure cpu waste...
flush_connections(me.fd);
writes are already done in read_message(), which
uses select(). flush_connections doesn't even !!!
--Run
*/
}
}
/*
* open_debugfile
*
* If the -t option is not given on the command line when the server is
* started, all debugging output is sent to the file set by LPATH in config.h
* Here we just open that file and make sure it is opened to fd 2 so that
* any fprintf's to stderr also goto the logfile. If the debuglevel is not
* set from the command line by -x, use /dev/null as the dummy logfile as long
* as DEBUGMODE has been defined, else dont waste the fd.
*/
static void open_debugfile()
{
#ifdef DEBUGMODE
int fd;
aClient *cptr;
if (debuglevel >= 0)
{
cptr = make_client(NULL);
cptr->fd = 2;
SetLog(cptr);
cptr->port = debuglevel;
cptr->flags = 0;
cptr->acpt = cptr;
local[2] = cptr;
(void)strcpy(cptr->sockhost, me.sockhost);
(void)printf("isatty = %d ttyname = %#x\n",
isatty(2), (u_int)ttyname(2));
if (!(bootopt & BOOT_TTY)) /* leave debugging output on fd 2 */
{
(void)truncate(LOGFILE, 0);
if ((fd = open(LOGFILE, O_WRONLY | O_CREAT, 0600)) < 0)
if ((fd = open("/dev/null", O_WRONLY)) < 0)
exit(-1);
if (fd != 2)
{
(void)dup2(fd, 2);
(void)close(fd);
}
strncpyzt(cptr->name, LOGFILE, sizeof(cptr->name));
}
else if (isatty(2) && ttyname(2))
strncpyzt(cptr->name, ttyname(2), sizeof(cptr->name));
else
(void)strcpy(cptr->name, "FD2-Pipe");
Debug((DEBUG_FATAL, "Debug: File <%s> Level: %d at %s",
cptr->name, cptr->port, myctime(now)));
}
else
local[2] = NULL;
#endif
return;
}
static void setup_signals()
{
#ifdef POSIX_SIGNALS
struct sigaction act;
act.sa_handler = SIG_IGN;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGPIPE);
(void)sigaddset(&act.sa_mask, SIGALRM);
# ifdef SIGWINCH
(void)sigaddset(&act.sa_mask, SIGWINCH);
(void)sigaction(SIGWINCH, &act, NULL);
# endif
(void)sigaction(SIGPIPE, &act, NULL);
act.sa_handler = dummy;
(void)sigaction(SIGALRM, &act, NULL);
act.sa_handler = s_rehash;
(void)sigemptyset(&act.sa_mask);
(void)sigaddset(&act.sa_mask, SIGHUP);
(void)sigaction(SIGHUP, &act, NULL);
act.sa_handler = s_restart;
(void)sigaddset(&act.sa_mask, SIGINT);
(void)sigaction(SIGINT, &act, NULL);
act.sa_handler = s_die;
(void)sigaddset(&act.sa_mask, SIGTERM);
(void)sigaction(SIGTERM, &act, NULL);
#else
# ifndef HAVE_RELIABLE_SIGNALS
(void)signal(SIGPIPE, dummy);
# ifdef SIGWINCH
(void)signal(SIGWINCH, dummy);
# endif
# else
# ifdef SIGWINCH
(void)signal(SIGWINCH, SIG_IGN);
# endif
(void)signal(SIGPIPE, SIG_IGN);
# endif
(void)signal(SIGALRM, dummy);
(void)signal(SIGHUP, s_rehash);
(void)signal(SIGTERM, s_die);
(void)signal(SIGINT, s_restart);
#endif
#ifdef RESTARTING_SYSTEMCALLS
/*
** At least on Apollo sr10.1 it seems continuing system calls
** after signal is the default. The following 'siginterrupt'
** should change that default to interrupting calls.
*/
(void)siginterrupt(SIGALRM, 1);
#endif
}

543
ircd/list.c Normal file
View File

@@ -0,0 +1,543 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/list.c
* Copyright (C) 1990 Jarkko Oikarinen and
* University of Oulu, Finland
*
* 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.
*/
/* -- Jto -- 20 Jun 1990
* extern void free() fixed as suggested by
* gruner@informatik.tu-muenchen.de
*/
/* -- Jto -- 03 Jun 1990
* Added chname initialization...
*/
/* -- Jto -- 24 May 1990
* Moved is_full() to channel.c
*/
/* -- Jto -- 10 May 1990
* Added #include <sys.h>
* Changed memset(xx,0,yy) into bzero(xx,yy)
*/
#ifndef lint
static char sccsid[] = "@(#)list.c 2.24 4/20/94 (C) 1988 University of Oulu, \
Computing Center and Jarkko Oikarinen";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "numeric.h"
#ifdef DBMALLOC
#include "malloc.h"
#endif
void free_link PROTO((Link *));
Link *make_link PROTO(());
#ifdef DEBUGMODE
static struct liststats {
int inuse;
} cloc, crem, users, servs, links, classs, aconfs;
#endif
void outofmemory();
int numclients = 0;
void initlists()
{
#ifdef DEBUGMODE
bzero((char *)&cloc, sizeof(cloc));
bzero((char *)&crem, sizeof(crem));
bzero((char *)&users, sizeof(users));
bzero((char *)&servs, sizeof(servs));
bzero((char *)&links, sizeof(links));
bzero((char *)&classs, sizeof(classs));
bzero((char *)&aconfs, sizeof(aconfs));
#endif
}
void outofmemory()
{
Debug((DEBUG_FATAL, "Out of memory: restarting server..."));
restart("Out of Memory");
}
/*
** Create a new aClient structure and set it to initial state.
**
** from == NULL, create local client (a client connected
** to a socket).
**
** from, create remote client (behind a socket
** associated with the client defined by
** 'from'). ('from' is a local client!!).
*/
aClient *make_client(from)
aClient *from;
{
Reg1 aClient *cptr = NULL;
Reg2 unsigned size = CLIENT_REMOTE_SIZE;
/*
* Check freelists first to see if we can grab a client without
* having to call malloc.
*/
if (!from)
size = CLIENT_LOCAL_SIZE;
if (!(cptr = (aClient *)MyMalloc(size)))
outofmemory();
bzero((char *)cptr, (int)size);
#ifdef DEBUGMODE
if (size == CLIENT_LOCAL_SIZE)
cloc.inuse++;
else
crem.inuse++;
#endif
/* Note: structure is zero (calloc) */
cptr->from = from ? from : cptr; /* 'from' of local client is self! */
cptr->next = NULL; /* For machines with NON-ZERO NULL pointers >;) */
cptr->prev = NULL;
cptr->hnext = NULL;
cptr->user = NULL;
cptr->serv = NULL;
cptr->status = STAT_UNKNOWN;
cptr->fd = -1;
(void)strcpy(cptr->username, "unknown");
if (size == CLIENT_LOCAL_SIZE)
{
cptr->since = cptr->lasttime = cptr->firsttime = now;
cptr->lastnick = TStime();
#ifdef NICK_DELAY
cptr->nextnick = now - NICK_DELAY;
#endif /* NICK_DELAY */
cptr->cookie = 0;
cptr->confs = NULL;
cptr->sockhost[0] = '\0';
cptr->buffer[0] = '\0';
cptr->authfd = -1;
cptr->listing = NULL;
}
return (cptr);
}
void free_client(cptr)
aClient *cptr;
{
MyFree((char *)cptr);
}
/*
** 'make_user' add's an User information block to a client
** if it was not previously allocated.
*/
anUser *make_user(cptr)
aClient *cptr;
{
Reg1 anUser *user;
user = cptr->user;
if (!user)
{
user = (anUser *)MyMalloc(sizeof(anUser));
#ifdef DEBUGMODE
users.inuse++;
#endif
user->away = NULL;
user->refcnt = 1;
user->joined = 0;
user->channel = NULL;
user->invited = NULL;
user->silence = NULL;
cptr->user = user;
}
return user;
}
aServer *make_server(cptr)
aClient *cptr;
{
Reg1 aServer *serv = cptr->serv;
if (!serv)
{
serv = (aServer *)MyMalloc(sizeof(aServer));
#ifdef DEBUGMODE
servs.inuse++;
#endif
serv->ghost = 0;
cptr->serv = serv;
serv->user = NULL;
serv->nexts = NULL;
*serv->by = '\0';
serv->up = NULL;
serv->down = NULL;
serv->client = NULL;
}
return cptr->serv;
}
/*
** free_user
** Decrease user reference count by one and realease block,
** if count reaches 0
*/
void free_user(user, cptr)
Reg1 anUser *user;
aClient *cptr;
{
if (--user->refcnt <= 0)
{
if (user->away)
MyFree((char *)user->away);
/*
* sanity check
*/
if (user->joined || user->refcnt < 0 ||
user->invited || user->channel)
#ifdef DEBUGMODE
dumpcore("%#x user (%s!%s@%s) %#x %#x %#x %d %d",
cptr, cptr ? cptr->name : "<noname>",
user->username, user->host, user,
user->invited, user->channel, user->joined,
user->refcnt);
#else
sendto_ops("* %#x user (%s!%s@%s) %#x %#x %#x %d %d *",
cptr, cptr ? cptr->name : "<noname>",
user->username, user->host, user,
user->invited, user->channel, user->joined,
user->refcnt);
#endif
MyFree((char *)user);
#ifdef DEBUGMODE
users.inuse--;
#endif
}
}
/*
* taken the code from ExitOneClient() for this and placed it here.
* - avalon
*/
void remove_client_from_list(cptr)
Reg1 aClient *cptr;
{
checklist();
if (cptr->prev)
cptr->prev->next = cptr->next;
else
{
client = cptr->next;
client->prev = NULL;
}
if (cptr->next)
cptr->next->prev = cptr->prev;
if (IsPerson(cptr) && cptr->user)
{
add_history(cptr);
off_history(cptr);
}
if (cptr->user)
{
cptr->user->clink = NULL;
(void)free_user(cptr->user, cptr);
}
if (cptr->serv)
{
if (cptr->serv->user)
free_user(cptr->serv->user, cptr);
MyFree((char *)cptr->serv);
#ifdef DEBUGMODE
servs.inuse--;
#endif
}
#ifdef DEBUGMODE
if (cptr->fd == -2)
cloc.inuse--;
else
crem.inuse--;
#endif
(void)free_client(cptr);
numclients--;
return;
}
/*
* although only a small routine, it appears in a number of places
* as a collection of a few lines...functions like this *should* be
* in this file, shouldnt they ? after all, this is list.c, isnt it ?
* -avalon
*/
void add_client_to_list(cptr)
aClient *cptr;
{
/*
* since we always insert new clients to the top of the list,
* this should mean the "me" is the bottom most item in the list.
*/
cptr->next = client;
client = cptr;
if (cptr->next)
cptr->next->prev = cptr;
return;
}
/*
* Look for ptr in the linked listed pointed to by link.
*/
Link *find_user_link(lp, ptr)
Reg1 Link *lp;
Reg2 aClient *ptr;
{
if (ptr)
while (lp)
{
if (lp->value.cptr == ptr)
return (lp);
lp = lp->next;
}
return NULL;
}
Link *make_link()
{
Reg1 Link *lp;
lp = (Link *)MyMalloc(sizeof(Link));
#ifdef DEBUGMODE
links.inuse++;
#endif
return lp;
}
void free_link(lp)
Reg1 Link *lp;
{
MyFree((char *)lp);
#ifdef DEBUGMODE
links.inuse--;
#endif
}
Dlink *add_dlink(lpp, cp)
Dlink **lpp;
aClient *cp;
{ register Dlink *lp;
lp = (Dlink *)MyMalloc(sizeof(Dlink));
lp->value.cptr = cp;
lp->prev = NULL;
if ((lp->next = *lpp))
lp->next->prev = lp;
*lpp = lp;
return lp;
}
void remove_dlink(lpp, lp)
Dlink **lpp, *lp;
{
if (lp->prev)
{ if ((lp->prev->next = lp->next))
lp->next->prev = lp->prev; }
else if ((*lpp = lp->next))
lp->next->prev = NULL;
MyFree(lp);
}
aClass *make_class()
{
Reg1 aClass *tmp;
tmp = (aClass *)MyMalloc(sizeof(aClass));
#ifdef DEBUGMODE
classs.inuse++;
#endif
return tmp;
}
void free_class(tmp)
Reg1 aClass *tmp;
{
MyFree((char *)tmp);
#ifdef DEBUGMODE
classs.inuse--;
#endif
}
aConfItem *make_conf()
{
Reg1 aConfItem *aconf;
aconf = (struct ConfItem *)MyMalloc(sizeof(aConfItem));
#ifdef DEBUGMODE
aconfs.inuse++;
#endif
bzero((char *)&aconf->ipnum, sizeof(struct in_addr));
aconf->next = NULL;
aconf->host = aconf->passwd = aconf->name = NULL;
aconf->status = CONF_ILLEGAL;
aconf->clients = 0;
aconf->port = 0;
aconf->hold = 0;
Class(aconf) = 0;
return (aconf);
}
void delist_conf(aconf)
aConfItem *aconf;
{
if (aconf == conf)
conf = conf->next;
else
{
aConfItem *bconf;
for (bconf = conf; aconf != bconf->next; bconf = bconf->next)
;
bconf->next = aconf->next;
}
aconf->next = NULL;
}
void free_conf(aconf)
aConfItem *aconf;
{
aClient *cptr = &me;
del_queries((char *)aconf);
MyFree(aconf->host);
if (aconf->passwd)
bzero(aconf->passwd, strlen(aconf->passwd));
MyFree(aconf->passwd);
MyFree(aconf->name);
MyFree((char *)aconf);
#ifdef DEBUGMODE
aconfs.inuse--;
#endif
return;
}
aGline *make_gline(host, reason, name, expire)
char *host, *reason, *name;
time_t expire;
{
Reg4 aGline *agline;
agline = (struct Gline *)MyMalloc(sizeof(aGline)); /* alloc memory */
DupString(agline->host, host); /* copy vital information */
DupString(agline->reason, reason);
DupString(agline->name, name);
agline->expire = expire;
agline->active = GLINE_ACTIVE; /* gline is active */
agline->next = gline; /* link it into the list */
return (gline = agline);
}
aGline *find_gline(host, name, pgline)
Reg1 char *host, *name;
aGline **pgline;
{
Reg3 aGline *agline = gline, *a2gline = NULL;
while (agline) { /* look through all glines */
if (agline->expire <= TStime()) { /* handle expired glines */
free_gline(agline, a2gline);
agline = a2gline ? a2gline->next : gline;
if (!agline) break; /* agline == NULL means gline == NULL */
continue;
}
/* does gline match? */
if (match(agline->host, host) == 0 && match(agline->name, name) == 0) {
if (pgline) *pgline = a2gline; /* if they need it, give them the
previous gline entry (probably
for free_gline, below) */
return agline;
}
a2gline = agline;
agline = agline->next;
}
return NULL; /* found no glines */
}
void free_gline(agline, pgline)
aGline *agline, *pgline;
{
if (pgline) pgline->next = agline->next; /* squeeze agline out */
else gline = agline->next;
MyFree(agline->host); /* and free up the memory */
MyFree(agline->reason);
MyFree(agline->name);
MyFree((char *)agline);
}
#ifdef DEBUGMODE
void send_listinfo(cptr, name)
aClient *cptr;
char *name;
{
int inuse = 0, mem = 0, tmp = 0;
sendto_one(cptr, ":%s %d %s :Local: inuse: %d(%d)",
me.name, RPL_STATSDEBUG, name, inuse += cloc.inuse,
tmp = cloc.inuse * CLIENT_LOCAL_SIZE);
mem += tmp;
sendto_one(cptr, ":%s %d %s :Remote: inuse: %d(%d)",
me.name, RPL_STATSDEBUG, name,
crem.inuse, tmp = crem.inuse * CLIENT_REMOTE_SIZE);
mem += tmp;
inuse += crem.inuse;
sendto_one(cptr, ":%s %d %s :Users: inuse: %d(%d)",
me.name, RPL_STATSDEBUG, name, users.inuse,
tmp = users.inuse * sizeof(anUser));
mem += tmp;
inuse += users.inuse,
sendto_one(cptr, ":%s %d %s :Servs: inuse: %d(%d)",
me.name, RPL_STATSDEBUG, name, servs.inuse,
tmp = servs.inuse * sizeof(aServer));
mem += tmp;
inuse += servs.inuse,
sendto_one(cptr, ":%s %d %s :Links: inuse: %d(%d)",
me.name, RPL_STATSDEBUG, name, links.inuse,
tmp = links.inuse * sizeof(Link));
mem += tmp;
inuse += links.inuse,
sendto_one(cptr, ":%s %d %s :Classes: inuse: %d(%d)",
me.name, RPL_STATSDEBUG, name, classs.inuse,
tmp = classs.inuse * sizeof(aClass));
mem += tmp;
inuse += classs.inuse,
sendto_one(cptr, ":%s %d %s :Confs: inuse: %d(%d)",
me.name, RPL_STATSDEBUG, name, aconfs.inuse,
tmp = aconfs.inuse * sizeof(aConfItem));
mem += tmp;
inuse += aconfs.inuse,
sendto_one(cptr, ":%s %d %s :Totals: inuse %d %d",
me.name, RPL_STATSDEBUG, name, inuse, mem);
}
#endif

97
ircd/map.c Normal file
View File

@@ -0,0 +1,97 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/s_ping.c
* Copyright (C) 1994 Carlo K ( Run @ undernet.org )
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)s_ping.c 1.0 9/30/94 (C) 1994 Carlo Kid";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "numeric.h"
void dump_map(cptr, server, mask, prompt_length)
aClient *cptr, *server;
char *mask;
register int prompt_length;
{
static char prompt[64];
register Dlink *lp;
register char *p = &prompt[prompt_length];
register int cnt = 0;
*p='\0';
if (prompt_length > 60)
sendto_one(cptr, rpl_str(RPL_MAPMORE), me.name, cptr->name,
prompt, server->name);
else
sendto_one(cptr, rpl_str(RPL_MAP), me.name, cptr->name,
prompt, server->name);
if (prompt_length > 0)
{
p[-1] = ' ';
if (p[-2] == '`')
p[-2] = ' ';
}
if (prompt_length > 60)
return;
strcpy(p, "|-");
for (lp=server->serv->down; lp; lp=lp->next)
if (matches(mask, lp->value.cptr->name))
lp->value.cptr->flags &= ~FLAGS_MAP;
else
{
lp->value.cptr->flags |= FLAGS_MAP;
cnt++;
}
for (lp=server->serv->down; lp; lp=lp->next)
{
if ((lp->value.cptr->flags & FLAGS_MAP) == 0)
continue;
if (--cnt == 0)
*p = '`';
dump_map(cptr, lp->value.cptr, mask, prompt_length+2);
}
if (prompt_length > 0)
p[-1] = '-';
}
/*
** m_map -- by Run
**
** parv[0] = sender prefix
** parv[1] = server mask
**/
int m_map(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
if (check_registered_user(sptr))
return 0;
if (parc < 2)
parv[1]="*";
dump_map(sptr, &me, parv[1], 0);
sendto_one(sptr, rpl_str(RPL_MAPEND), me.name, parv[0]);
return 0;
}

3563
ircd/note.c Normal file

File diff suppressed because it is too large Load Diff

158
ircd/random.c Normal file
View File

@@ -0,0 +1,158 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/random.c
*
* 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.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "config.h"
char localkey[8] = RANDOM_SEED;
/*
* MD5 transform algorithm, taken from code written by Colin Plumb,
* and put into the public domain
*
* Kev: Taken from Ted T'so's /dev/random random.c code and modified to
* be slightly simpler. That code is released under a BSD-style copyright
* OR under the terms of the GNU Public License, which should be included
* at the top of this source file.
*
* record: Cleaned up to work with ircd. RANDOM_TOKEN is defined in
* setup.h by the make script; if people start to "guess" your cookies,
* consider recompiling your server with a different random token.
*/
/* The four core functions - F1 is optimized somewhat */
#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) F1(z, x, y)
#define F3(x, y, z) (x ^ y ^ z)
#define F4(x, y, z) (y ^ (x | ~z))
/* This is the central step in the MD5 algorithm. */
#define MD5STEP(f, w, x, y, z, data, s) \
( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
/*
* The core of the MD5 algorithm, this alters an existing MD5 hash to
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*
* original comment left in; this used to be called MD5Transform and took
* two arguments; I've internalized those arguments, creating the character
* array "localkey," which should contain 8 bytes of data. The function also
* originally returned nothing; now it returns an unsigned long that is the
* random number. It appears to be reallyrandom, so... -Kev
*
* I don't really know what this does. I tried to figure it out and got
* a headache. If you know what's good for you, you'll leave this stuff
* for the smart people and do something else. -record
*/
unsigned long ircrandom(void)
{
unsigned long a, b, c, d;
unsigned char in[16];
struct timeval tv;
(void)gettimeofday(&tv, NULL);
(void)memcpy((void *)in, (void *)localkey, 8);
(void)memcpy((void *)(in+8), (void *)&tv.tv_sec, 4);
(void)memcpy((void *)(in+12), (void *)&tv.tv_usec, 4);
a = 0x67452301;
b = 0xefcdab89;
c = 0x98badcfe;
d = 0x10325476;
MD5STEP(F1, a, b, c, d, (long)in[ 0]+0xd76aa478, 7);
MD5STEP(F1, d, a, b, c, (long)in[ 1]+0xe8c7b756, 12);
MD5STEP(F1, c, d, a, b, (long)in[ 2]+0x242070db, 17);
MD5STEP(F1, b, c, d, a, (long)in[ 3]+0xc1bdceee, 22);
MD5STEP(F1, a, b, c, d, (long)in[ 4]+0xf57c0faf, 7);
MD5STEP(F1, d, a, b, c, (long)in[ 5]+0x4787c62a, 12);
MD5STEP(F1, c, d, a, b, (long)in[ 6]+0xa8304613, 17);
MD5STEP(F1, b, c, d, a, (long)in[ 7]+0xfd469501, 22);
MD5STEP(F1, a, b, c, d, (long)in[ 8]+0x698098d8, 7);
MD5STEP(F1, d, a, b, c, (long)in[ 9]+0x8b44f7af, 12);
MD5STEP(F1, c, d, a, b, (long)in[10]+0xffff5bb1, 17);
MD5STEP(F1, b, c, d, a, (long)in[11]+0x895cd7be, 22);
MD5STEP(F1, a, b, c, d, (long)in[12]+0x6b901122, 7);
MD5STEP(F1, d, a, b, c, (long)in[13]+0xfd987193, 12);
MD5STEP(F1, c, d, a, b, (long)in[14]+0xa679438e, 17);
MD5STEP(F1, b, c, d, a, (long)in[15]+0x49b40821, 22);
MD5STEP(F2, a, b, c, d, (long)in[ 1]+0xf61e2562, 5);
MD5STEP(F2, d, a, b, c, (long)in[ 6]+0xc040b340, 9);
MD5STEP(F2, c, d, a, b, (long)in[11]+0x265e5a51, 14);
MD5STEP(F2, b, c, d, a, (long)in[ 0]+0xe9b6c7aa, 20);
MD5STEP(F2, a, b, c, d, (long)in[ 5]+0xd62f105d, 5);
MD5STEP(F2, d, a, b, c, (long)in[10]+0x02441453, 9);
MD5STEP(F2, c, d, a, b, (long)in[15]+0xd8a1e681, 14);
MD5STEP(F2, b, c, d, a, (long)in[ 4]+0xe7d3fbc8, 20);
MD5STEP(F2, a, b, c, d, (long)in[ 9]+0x21e1cde6, 5);
MD5STEP(F2, d, a, b, c, (long)in[14]+0xc33707d6, 9);
MD5STEP(F2, c, d, a, b, (long)in[ 3]+0xf4d50d87, 14);
MD5STEP(F2, b, c, d, a, (long)in[ 8]+0x455a14ed, 20);
MD5STEP(F2, a, b, c, d, (long)in[13]+0xa9e3e905, 5);
MD5STEP(F2, d, a, b, c, (long)in[ 2]+0xfcefa3f8, 9);
MD5STEP(F2, c, d, a, b, (long)in[ 7]+0x676f02d9, 14);
MD5STEP(F2, b, c, d, a, (long)in[12]+0x8d2a4c8a, 20);
MD5STEP(F3, a, b, c, d, (long)in[ 5]+0xfffa3942, 4);
MD5STEP(F3, d, a, b, c, (long)in[ 8]+0x8771f681, 11);
MD5STEP(F3, c, d, a, b, (long)in[11]+0x6d9d6122, 16);
MD5STEP(F3, b, c, d, a, (long)in[14]+0xfde5380c, 23);
MD5STEP(F3, a, b, c, d, (long)in[ 1]+0xa4beea44, 4);
MD5STEP(F3, d, a, b, c, (long)in[ 4]+0x4bdecfa9, 11);
MD5STEP(F3, c, d, a, b, (long)in[ 7]+0xf6bb4b60, 16);
MD5STEP(F3, b, c, d, a, (long)in[10]+0xbebfbc70, 23);
MD5STEP(F3, a, b, c, d, (long)in[13]+0x289b7ec6, 4);
MD5STEP(F3, d, a, b, c, (long)in[ 0]+0xeaa127fa, 11);
MD5STEP(F3, c, d, a, b, (long)in[ 3]+0xd4ef3085, 16);
MD5STEP(F3, b, c, d, a, (long)in[ 6]+0x04881d05, 23);
MD5STEP(F3, a, b, c, d, (long)in[ 9]+0xd9d4d039, 4);
MD5STEP(F3, d, a, b, c, (long)in[12]+0xe6db99e5, 11);
MD5STEP(F3, c, d, a, b, (long)in[15]+0x1fa27cf8, 16);
MD5STEP(F3, b, c, d, a, (long)in[ 2]+0xc4ac5665, 23);
MD5STEP(F4, a, b, c, d, (long)in[ 0]+0xf4292244, 6);
MD5STEP(F4, d, a, b, c, (long)in[ 7]+0x432aff97, 10);
MD5STEP(F4, c, d, a, b, (long)in[14]+0xab9423a7, 15);
MD5STEP(F4, b, c, d, a, (long)in[ 5]+0xfc93a039, 21);
MD5STEP(F4, a, b, c, d, (long)in[12]+0x655b59c3, 6);
MD5STEP(F4, d, a, b, c, (long)in[ 3]+0x8f0ccc92, 10);
MD5STEP(F4, c, d, a, b, (long)in[10]+0xffeff47d, 15);
MD5STEP(F4, b, c, d, a, (long)in[ 1]+0x85845dd1, 21);
MD5STEP(F4, a, b, c, d, (long)in[ 8]+0x6fa87e4f, 6);
MD5STEP(F4, d, a, b, c, (long)in[15]+0xfe2ce6e0, 10);
MD5STEP(F4, c, d, a, b, (long)in[ 6]+0xa3014314, 15);
MD5STEP(F4, b, c, d, a, (long)in[13]+0x4e0811a1, 21);
MD5STEP(F4, a, b, c, d, (long)in[ 4]+0xf7537e82, 6);
MD5STEP(F4, d, a, b, c, (long)in[11]+0xbd3af235, 10);
MD5STEP(F4, c, d, a, b, (long)in[ 2]+0x2ad7d2bb, 15);
MD5STEP(F4, b, c, d, a, (long)in[ 9]+0xeb86d391, 21);
/*
* we have 4 unsigned longs generated by the above sequence; this scrambles
* them together so that if there is any pattern, it will be obscured.
*/
return (a ^ b ^ c ^ d);
}

1417
ircd/res.c Normal file

File diff suppressed because it is too large Load Diff

329
ircd/res_comp.c Normal file
View File

@@ -0,0 +1,329 @@
/*
* Copyright (c) 1985 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_comp.c 6.18 (Berkeley) 6/27/90";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <stdio.h>
#include "nameser.h"
static dn_find();
/*
* Expand compressed domain name 'comp_dn' to full domain name.
* 'msg' is a pointer to the begining of the message,
* 'eomorig' points to the first location after the message,
* 'exp_dn' is a pointer to a buffer of size 'length' for the result.
* Return size of compressed name or -1 if there was an error.
*/
dn_expand(msg, eomorig, comp_dn, exp_dn, length)
u_char *msg, *eomorig, *comp_dn, *exp_dn;
int length;
{
register u_char *cp, *dn;
register int n, c;
u_char *eom;
int len = -1, checked = 0;
dn = exp_dn;
cp = comp_dn;
eom = exp_dn + length;
/*
* fetch next label in domain name
*/
while (n = *cp++) {
/*
* Check for indirection
*/
switch (n & INDIR_MASK) {
case 0:
if (dn != exp_dn) {
if (dn >= eom)
return (-1);
*dn++ = '.';
}
if (dn+n >= eom)
return (-1);
checked += n + 1;
while (--n >= 0) {
if ((c = *cp++) == '.') {
if (dn + n + 2 >= eom)
return (-1);
*dn++ = '\\';
}
*dn++ = c;
if (cp >= eomorig) /* out of range */
return(-1);
}
break;
case INDIR_MASK:
if (len < 0)
len = cp - comp_dn + 1;
cp = msg + (((n & 0x3f) << 8) | (*cp & 0xff));
if (cp < msg || cp >= eomorig) /* out of range */
return(-1);
checked += 2;
/*
* Check for loops in the compressed name;
* if we've looked at the whole message,
* there must be a loop.
*/
if (checked >= eomorig - msg)
return (-1);
break;
default:
return (-1); /* flag error */
}
}
*dn = '\0';
if (len < 0)
len = cp - comp_dn;
return (len);
}
/*
* Compress domain name 'exp_dn' into 'comp_dn'.
* Return the size of the compressed name or -1.
* 'length' is the size of the array pointed to by 'comp_dn'.
* 'dnptrs' is a list of pointers to previous compressed names. dnptrs[0]
* is a pointer to the beginning of the message. The list ends with NULL.
* 'lastdnptr' is a pointer to the end of the arrary pointed to
* by 'dnptrs'. Side effect is to update the list of pointers for
* labels inserted into the message as we compress the name.
* If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
* is NULL, we don't update the list.
*/
dn_comp(exp_dn, comp_dn, length, dnptrs, lastdnptr)
u_char *exp_dn, *comp_dn;
int length;
u_char **dnptrs, **lastdnptr;
{
register u_char *cp, *dn;
register int c, l;
u_char **cpp, **lpp, *sp, *eob;
u_char *msg;
dn = exp_dn;
cp = comp_dn;
eob = cp + length;
if (dnptrs != NULL) {
if ((msg = *dnptrs++) != NULL) {
for (cpp = dnptrs; *cpp != NULL; cpp++)
;
lpp = cpp; /* end of list to search */
}
} else
msg = NULL;
for (c = *dn++; c != '\0'; ) {
/* look to see if we can use pointers */
if (msg != NULL) {
if ((l = dn_find(dn-1, msg, dnptrs, lpp)) >= 0) {
if (cp+1 >= eob)
return (-1);
*cp++ = (l >> 8) | INDIR_MASK;
*cp++ = l % 256;
return (cp - comp_dn);
}
/* not found, save it */
if (lastdnptr != NULL && cpp < lastdnptr-1) {
*cpp++ = cp;
*cpp = NULL;
}
}
sp = cp++; /* save ptr to length byte */
do {
if (c == '.') {
c = *dn++;
break;
}
if (c == '\\') {
if ((c = *dn++) == '\0')
break;
}
if (cp >= eob) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*cp++ = c;
} while ((c = *dn++) != '\0');
/* catch trailing '.'s but not '..' */
if ((l = cp - sp - 1) == 0 && c == '\0') {
cp--;
break;
}
if (l <= 0 || l > MAXLABEL) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*sp = l;
}
if (cp >= eob) {
if (msg != NULL)
*lpp = NULL;
return (-1);
}
*cp++ = '\0';
return (cp - comp_dn);
}
/*
* Skip over a compressed domain name. Return the size or -1.
*/
dn_skipname(comp_dn, eom)
u_char *comp_dn, *eom;
{
register u_char *cp;
register int n;
cp = comp_dn;
while (cp < eom && (n = *cp++)) {
/*
* check for indirection
*/
switch (n & INDIR_MASK) {
case 0: /* normal case, n == len */
cp += n;
continue;
default: /* illegal type */
return (-1);
case INDIR_MASK: /* indirection */
cp++;
}
break;
}
return (cp - comp_dn);
}
/*
* Search for expanded name from a list of previously compressed names.
* Return the offset from msg if found or -1.
* dnptrs is the pointer to the first name on the list,
* not the pointer to the start of the message.
*/
static
dn_find(exp_dn, msg, dnptrs, lastdnptr)
u_char *exp_dn, *msg;
u_char **dnptrs, **lastdnptr;
{
register u_char *dn, *cp, **cpp;
register int n;
u_char *sp;
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
dn = exp_dn;
sp = cp = *cpp;
while (n = *cp++) {
/*
* check for indirection
*/
switch (n & INDIR_MASK) {
case 0: /* normal case, n == len */
while (--n >= 0) {
if (*dn == '.')
goto next;
if (*dn == '\\')
dn++;
if (*dn++ != *cp++)
goto next;
}
if ((n = *dn++) == '\0' && *cp == '\0')
return (sp - msg);
if (n == '.')
continue;
goto next;
default: /* illegal type */
return (-1);
case INDIR_MASK: /* indirection */
cp = msg + (((n & 0x3f) << 8) | *cp);
}
}
if (*dn == '\0')
return (sp - msg);
next: ;
}
return (-1);
}
/*
* Routines to insert/extract short/long's. Must account for byte
* order and non-alignment problems. This code at least has the
* advantage of being portable.
*
* used by sendmail.
*/
u_short
_getshort(msgp)
u_char *msgp;
{
register u_char *p = (u_char *) msgp;
#ifdef vax
/*
* vax compiler doesn't put shorts in registers
*/
register u_long u;
#else
register u_short u;
#endif
u = *p++ << 8;
return ((u_short)(u | *p));
}
u_long
_getlong(msgp)
u_char *msgp;
{
register u_char *p = (u_char *) msgp;
register u_long u;
u = *p++; u <<= 8;
u |= *p++; u <<= 8;
u |= *p++; u <<= 8;
return (u | *p);
}
putshort(s, msgp)
register u_short s;
register u_char *msgp;
{
msgp[1] = s;
msgp[0] = s >> 8;
}
putlong(l, msgp)
register u_long l;
register u_char *msgp;
{
msgp[3] = l;
msgp[2] = (l >>= 8);
msgp[1] = (l >>= 8);
msgp[0] = l >> 8;
}

206
ircd/res_init.c Normal file
View File

@@ -0,0 +1,206 @@
/*-
* Copyright (c) 1985, 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_init.c 6.14.1 (Berkeley) 6/27/90";
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include "config.h" /* To get #define SOL20 Vesa */
#include "sys.h"
#include "nameser.h"
#include "resolv.h"
/*
* Resolver state default settings
*/
struct state _res = {
RES_TIMEOUT, /* retransmition time interval */
4, /* number of times to retransmit */
RES_DEFAULT, /* options flags */
1, /* number of name servers */
};
/*
* Set up default settings. If the configuration file exist, the values
* there will have precedence. Otherwise, the server address is set to
* INADDR_ANY and the default domain name comes from the gethostname().
*
* The configuration file should only be used if you want to redefine your
* domain or run without a server on your machine.
*
* Return 0 if completes successfully, -1 on error
*/
res_init()
{
register FILE *fp;
register char *cp, *dp, **pp;
register int n;
char buf[BUFSIZ];
extern u_long inet_addr();
extern char *getenv();
int nserv = 0; /* number of nameserver records read from file */
int norder = 0;
int haveenv = 0;
int havesearch = 0;
_res.nsaddr.sin_addr.s_addr = INADDR_ANY;
_res.nsaddr.sin_family = AF_INET;
_res.nsaddr.sin_port = htons(NAMESERVER_PORT);
_res.nscount = 1;
/* Allow user to override the local domain definition */
if ((cp = getenv("LOCALDOMAIN")) != NULL) {
(void)strncpy(_res.defdname, cp, sizeof(_res.defdname));
haveenv++;
}
if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
/* read the config file */
while (fgets(buf, sizeof(buf), fp) != NULL) {
/* read default domain name */
if (!strncmp(buf, "domain", sizeof("domain") - 1)) {
if (haveenv) /* skip if have from environ */
continue;
cp = buf + sizeof("domain") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
(void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
if ((cp = index(_res.defdname, '\n')) != NULL)
*cp = '\0';
havesearch = 0;
continue;
}
/* set search list */
if (!strncmp(buf, "search", sizeof("search") - 1)) {
if (haveenv) /* skip if have from environ */
continue;
cp = buf + sizeof("search") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
(void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
if ((cp = index(_res.defdname, '\n')) != NULL)
*cp = '\0';
/*
* Set search list to be blank-separated strings
* on rest of line.
*/
cp = _res.defdname;
pp = _res.dnsrch;
*pp++ = cp;
for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
if (*cp == ' ' || *cp == '\t') {
*cp = 0;
n = 1;
} else if (n) {
*pp++ = cp;
n = 0;
}
}
/* null terminate last domain if there are excess */
while (*cp != '\0' && *cp != ' ' && *cp != '\t')
cp++;
*cp = '\0';
*pp++ = 0;
havesearch = 1;
continue;
}
/* read nameservers to query */
if (!strncmp(buf, "nameserver", sizeof("nameserver") - 1) &&
nserv < MAXNS) {
cp = buf + sizeof("nameserver") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
if ((_res.nsaddr_list[nserv].sin_addr.s_addr =
inet_addr(cp)) == (unsigned)-1) {
_res.nsaddr_list[nserv].sin_addr.s_addr
= INADDR_ANY;
continue;
}
_res.nsaddr_list[nserv].sin_family = AF_INET;
_res.nsaddr_list[nserv].sin_port = htons(NAMESERVER_PORT);
nserv++;
continue;
}
/* read service order */
if (!strncmp(buf, "order", sizeof("order") - 1)) {
cp = buf + sizeof("order") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
norder = 0;
do {
if ((dp = index(cp, ',')) != NULL)
*dp = '\0';
if (norder >= MAXSERVICES)
continue;
if (!strncmp(cp, "bind", sizeof("bind") - 1))
_res.order[norder++] = RES_SERVICE_BIND;
else if (!strncmp(cp, "local", sizeof("local") - 1))
_res.order[norder++] = RES_SERVICE_LOCAL;
cp = dp + 1;
} while (dp != NULL);
_res.order[norder] = RES_SERVICE_NONE;
continue;
}
}
if (nserv > 1)
_res.nscount = nserv;
(void) fclose(fp);
}
if (_res.defdname[0] == 0) {
if (gethostname(buf, sizeof(_res.defdname)) == 0 &&
(cp = index(buf, '.')))
(void)strcpy(_res.defdname, cp + 1);
}
/* find components of local domain that might be searched */
if (havesearch == 0) {
pp = _res.dnsrch;
*pp++ = _res.defdname;
for (cp = _res.defdname, n = 0; *cp; cp++)
if (*cp == '.')
n++;
cp = _res.defdname;
for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH;
n--) {
cp = index(cp, '.');
*pp++ = ++cp;
}
*pp++ = 0;
}
/* default search order to bind only */
if (norder == 0) {
_res.order[0] = RES_SERVICE_BIND;
_res.order[1] = RES_SERVICE_NONE;
}
_res.options |= RES_INIT;
return (0);
}

192
ircd/res_mkquery.c Normal file
View File

@@ -0,0 +1,192 @@
/*
* Copyright (c) 1985 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that: (1) source distributions retain this entire copyright
* notice and comment, and (2) distributions including binaries display
* the following acknowledgement: ``This product includes software
* developed by the University of California, Berkeley and its contributors''
* in the documentation or other materials provided with the distribution
* and in all advertising materials mentioning features or use of this
* software. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)res_mkquery.c 6.12 (Berkeley) 6/1/90";
#endif /* LIBC_SCCS and not lint */
#include <stdio.h>
#include <sys/types.h>
#include <netinet/in.h>
#include "config.h"
#include "sys.h"
#include "nameser.h"
#include "resolv.h"
/*
* Form all types of queries.
* Returns the size of the result or -1.
*/
res_mkquery(op, dname, class, type, data, datalen, newrr, buf, buflen)
int op; /* opcode of query */
char *dname; /* domain name */
int class, type; /* class and type of query */
char *data; /* resource record data */
int datalen; /* length of data */
struct rrec *newrr; /* new rr for modify or append */
char *buf; /* buffer to put query */
int buflen; /* size of buffer */
{
register HEADER *hp;
register char *cp;
register int n;
char *dnptrs[10], **dpp, **lastdnptr;
#ifdef DEBUG
if (_res.options & RES_DEBUG)
printf("res_mkquery(%d, %s, %d, %d)\n", op, dname, class, type);
#endif /*DEBUG*/
/*
* Initialize header fields.
*/
if ((buf == NULL) || (buflen < sizeof(HEADER)))
return(-1);
bzero(buf, sizeof(HEADER));
hp = (HEADER *) buf;
hp->id = htons(++_res.id);
hp->opcode = op;
hp->pr = (_res.options & RES_PRIMARY) != 0;
hp->rd = (_res.options & RES_RECURSE) != 0;
hp->rcode = NOERROR;
cp = buf + sizeof(HEADER);
buflen -= sizeof(HEADER);
dpp = dnptrs;
*dpp++ = buf;
*dpp++ = NULL;
lastdnptr = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
/*
* perform opcode specific processing
*/
switch (op) {
case QUERY:
if ((buflen -= QFIXEDSZ) < 0)
return(-1);
if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
return (-1);
cp += n;
buflen -= n;
putshort(type, cp);
cp += sizeof(u_short);
putshort(class, cp);
cp += sizeof(u_short);
hp->qdcount = htons(1);
if (op == QUERY || data == NULL)
break;
/*
* Make an additional record for completion domain.
*/
buflen -= RRFIXEDSZ;
if ((n = dn_comp(data, cp, buflen, dnptrs, lastdnptr)) < 0)
return (-1);
cp += n;
buflen -= n;
putshort(T_NULL, cp);
cp += sizeof(u_short);
putshort(class, cp);
cp += sizeof(u_short);
putlong(0, cp);
cp += sizeof(u_long);
putshort(0, cp);
cp += sizeof(u_short);
hp->arcount = htons(1);
break;
case IQUERY:
/*
* Initialize answer section
*/
if (buflen < 1 + RRFIXEDSZ + datalen)
return (-1);
*cp++ = '\0'; /* no domain name */
putshort(type, cp);
cp += sizeof(u_short);
putshort(class, cp);
cp += sizeof(u_short);
putlong(0, cp);
cp += sizeof(u_long);
putshort(datalen, cp);
cp += sizeof(u_short);
if (datalen) {
bcopy(data, cp, datalen);
cp += datalen;
}
hp->ancount = htons(1);
break;
#ifdef ALLOW_UPDATES
/*
* For UPDATEM/UPDATEMA, do UPDATED/UPDATEDA followed by UPDATEA
* (Record to be modified is followed by its replacement in msg.)
*/
case UPDATEM:
case UPDATEMA:
case UPDATED:
/*
* The res code for UPDATED and UPDATEDA is the same; user
* calls them differently: specifies data for UPDATED; server
* ignores data if specified for UPDATEDA.
*/
case UPDATEDA:
buflen -= RRFIXEDSZ + datalen;
if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
return (-1);
cp += n;
putshort(type, cp);
cp += sizeof(u_short);
putshort(class, cp);
cp += sizeof(u_short);
putlong(0, cp);
cp += sizeof(u_long);
putshort(datalen, cp);
cp += sizeof(u_short);
if (datalen) {
bcopy(data, cp, datalen);
cp += datalen;
}
if ( (op == UPDATED) || (op == UPDATEDA) ) {
hp->ancount = htons(0);
break;
}
/* Else UPDATEM/UPDATEMA, so drop into code for UPDATEA */
case UPDATEA: /* Add new resource record */
buflen -= RRFIXEDSZ + datalen;
if ((n = dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0)
return (-1);
cp += n;
putshort(newrr->r_type, cp);
cp += sizeof(u_short);
putshort(newrr->r_class, cp);
cp += sizeof(u_short);
putlong(0, cp);
cp += sizeof(u_long);
putshort(newrr->r_size, cp);
cp += sizeof(u_short);
if (newrr->r_size) {
bcopy(newrr->r_data, cp, newrr->r_size);
cp += newrr->r_size;
}
hp->ancount = htons(0);
break;
#endif /* ALLOW_UPDATES */
}
return (cp - buf);
}

267
ircd/s_auth.c Normal file
View File

@@ -0,0 +1,267 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/s_auth.c
* Copyright (C) 1992 Darren Reed
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)s_auth.c 1.18 4/18/94 (C) 1992 Darren Reed";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "res.h"
#include "numeric.h"
#include "patchlevel.h"
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#ifdef UNIXPORT
# include <sys/un.h>
#endif
#if defined(__hpux)
# include "inet.h"
#endif
#include <fcntl.h>
#include "sock.h" /* If FD_ZERO isn't define up to this point, */
/* define it (BSD4.2 needs this) */
#include "h.h"
/*
* 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(cptr)
Reg1 aClient *cptr;
{
struct sockaddr_in sock;
int err;
#ifdef VIRTUAL_HOST
extern struct sockaddr_in vserv;
#endif
Debug((DEBUG_NOTICE,"start_auth(%x) fd %d status %d",
cptr, cptr->fd, cptr->status));
(void)alarm(2);
cptr->authfd = socket(AF_INET, SOCK_STREAM, 0);
err = errno;
(void)alarm(0);
if (cptr->authfd < 0 && err == EAGAIN)
sendto_ops(
"Can't allocate fd for auth on %s : socket: No more sockets",
get_client_name(cptr, TRUE));
if (cptr->authfd < 0)
{
#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))));
if (!DoingDNS(cptr))
SetAccess(cptr);
ircstp->is_abad++;
return;
}
if (cptr->authfd >= (MAXCONNECTIONS - 2))
{
sendto_ops("Can't allocate fd for auth on %s",
get_client_name(cptr, TRUE));
(void)close(cptr->authfd);
return;
}
set_non_blocking(cptr->authfd, cptr);
#ifdef VIRTUAL_HOST
if (bind(cptr->authfd, (struct sockaddr *)&vserv,
sizeof(vserv)) == -1)
{
report_error("binding auth stream socket %s:%s", cptr);
(void)close(cptr->fd);
return;
}
#endif
bcopy((char *)&cptr->ip, (char *)&sock.sin_addr,
sizeof(struct in_addr));
sock.sin_port = htons(113);
sock.sin_family = AF_INET;
(void)alarm((unsigned)4);
if (connect(cptr->authfd, (struct sockaddr *)&sock,
sizeof(sock)) == -1 && errno != EINPROGRESS)
{
ircstp->is_abad++;
/*
* No error report from this...
*/
(void)alarm((unsigned)0);
(void)close(cptr->authfd);
cptr->authfd = -1;
if (!DoingDNS(cptr))
SetAccess(cptr);
return;
}
(void)alarm((unsigned)0);
cptr->flags |= (FLAGS_WRAUTH|FLAGS_AUTH);
if (cptr->authfd > highest_fd)
highest_fd = cptr->authfd;
return;
}
/*
* send_authports
*
* Send the ident server a query giving "theirport , ourport".
* The write is only attempted *once* so it is deemed to be a fail if the
* entire write doesn't write all the data given. This shouldnt be a
* problem since the socket should have a write buffer far greater than
* this message to store it in should problems arise. -avalon
*/
void send_authports(cptr)
aClient *cptr;
{
struct sockaddr_in us, them;
char authbuf[32];
int ulen, tlen;
Debug((DEBUG_NOTICE,"write_authports(%x) fd %d authfd %d stat %d",
cptr, cptr->fd, cptr->authfd, cptr->status));
tlen = ulen = sizeof(us);
if (getsockname(cptr->fd, (struct sockaddr *)&us, &ulen) ||
getpeername(cptr->fd, (struct sockaddr *)&them, &tlen))
{
#ifdef USE_SYSLOG
syslog(LOG_ERR, "auth get{sock,peer}name error for %s:%m",
get_client_name(cptr, TRUE));
#endif
goto authsenderr;
}
(void)sprintf(authbuf, "%u , %u\r\n",
(unsigned int)ntohs(them.sin_port),
(unsigned int)ntohs(us.sin_port));
Debug((DEBUG_SEND, "sending [%s] to auth port %s.113",
authbuf, inetntoa((char *)&them.sin_addr)));
if (write(cptr->authfd, authbuf, strlen(authbuf)) != strlen(authbuf))
{
authsenderr:
ircstp->is_abad++;
(void)close(cptr->authfd);
if (cptr->authfd == highest_fd)
while (!local[highest_fd])
highest_fd--;
cptr->authfd = -1;
cptr->flags &= ~FLAGS_AUTH;
if (!DoingDNS(cptr))
SetAccess(cptr);
}
cptr->flags &= ~FLAGS_WRAUTH;
return;
}
/*
* read_authports
*
* read the reply (if any) from the ident server we connected to.
* The actual read processijng here is pretty weak - no handling of the reply
* if it is fragmented by IP.
*/
void read_authports(cptr)
Reg1 aClient *cptr;
{
Reg1 char *s, *t;
Reg2 int len;
char ruser[USERLEN+1], system[8];
u_short remp = 0, locp = 0;
*system = *ruser = '\0';
Debug((DEBUG_NOTICE,"read_authports(%x) fd %d authfd %d stat %d",
cptr, cptr->fd, cptr->authfd, cptr->status));
/*
* Nasty. Cant allow any other reads from client fd while we're
* waiting on the authfd to return a full valid string. Use the
* client's input buffer to buffer the authd reply.
* Oh. this is needed because an authd reply may come back in more
* than 1 read! -avalon
*/
if ((len = read(cptr->authfd, cptr->buffer + cptr->count,
sizeof(cptr->buffer) - 1 - cptr->count)) >= 0)
{
cptr->count += len;
cptr->buffer[cptr->count] = '\0';
}
cptr->lasttime = now;
if ((len > 0) && (cptr->count != (sizeof(cptr->buffer) - 1)) &&
(sscanf(cptr->buffer, "%hd , %hd : USERID : %*[^:]: %10s",
&remp, &locp, ruser) == 3))
{
s = rindex(cptr->buffer, ':');
*s++ = '\0';
for (t = (rindex(cptr->buffer, ':') + 1); *t; t++)
if (!isspace(*t))
break;
strncpyzt(system, t, sizeof(system));
for (t = ruser; *s && (t < ruser + sizeof(ruser)); s++)
if (!isspace(*s) && *s != ':' && *s != '@')
*t++ = *s;
*t = '\0';
Debug((DEBUG_INFO,"auth reply ok [%s] [%s]", system, ruser));
}
else if (len != 0)
{
if (!index(cptr->buffer, '\n') && !index(cptr->buffer, '\r'))
return;
Debug((DEBUG_ERROR,"local %d remote %d", locp, remp));
Debug((DEBUG_ERROR,"bad auth reply in [%s]", cptr->buffer));
*ruser = '\0';
}
(void)close(cptr->authfd);
if (cptr->authfd == highest_fd)
while (!local[highest_fd])
highest_fd--;
cptr->count = 0;
cptr->authfd = -1;
ClearAuth(cptr);
if (!DoingDNS(cptr))
SetAccess(cptr);
if (len > 0)
Debug((DEBUG_INFO,"ident reply: [%s]", cptr->buffer));
if (!locp || !remp || !*ruser)
{
ircstp->is_abad++;
return;
}
ircstp->is_asuc++;
strncpyzt(cptr->username, ruser, USERLEN+1);
if (strncmp(system, "OTHER", 5))
cptr->flags |= FLAGS_GOTID;
Debug((DEBUG_INFO, "got username [%s]", ruser));
return;
}

2601
ircd/s_bsd.c Normal file

File diff suppressed because it is too large Load Diff

1438
ircd/s_conf.c Normal file

File diff suppressed because it is too large Load Diff

475
ircd/s_debug.c Normal file
View File

@@ -0,0 +1,475 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/s_debug.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.
*/
#ifndef lint
static char sccsid[] = "@(#)s_debug.c 2.30 1/3/94 (C) 1988 University of Oulu, \
Computing Center and Jarkko Oikarinen";
#endif
#include "struct.h"
/*
* Option string. Must be before #ifdef DEBUGMODE.
*/
char serveropts[] = {
#ifdef CHROOTDIR
'c',
#endif
#ifdef CMDLINE_CONFIG
'C',
#endif
#ifdef DO_ID
'd',
#endif
#ifdef DEBUGMODE
'D',
#endif
#ifdef LOCOP_REHASH
'e',
#endif
#ifdef OPER_REHASH
'E',
#endif
#ifdef NOTE_FORWARDER
'f',
#endif
#ifdef HUB
'H',
#endif
#ifdef SHOW_INVISIBLE_LUSERS
'i',
#endif
#ifdef OPER_KILL
# ifdef LOCAL_KILL_ONLY
'k',
# else
'K',
# endif
#endif
#ifdef LEAST_IDLE
'L',
#endif
#ifdef M4_PREPROC
'm',
#endif
#ifdef IDLE_FROM_MSG
'M',
#endif
#ifdef CRYPT_OPER_PASSWORD
'p',
#endif
#ifdef CRYPT_LINK_PASSWORD
'P',
#endif
#ifdef NPATH
'N',
#endif
#ifdef LOCOP_RESTART
'r',
#endif
#ifdef OPER_RESTART
'R',
#endif
#ifdef ENABLE_SUMMON
'S',
#endif
#ifdef OPER_REMOTE
't',
#endif
#ifdef IRCII_KLUDGE
'u',
#endif
#ifdef ENABLE_USERS
'U',
#endif
#ifdef VALLOC
'V',
#endif
#ifdef UNIXPORT
'X',
#endif
#ifdef USE_SYSLOG
'Y',
#endif
#ifdef V28PlusOnly
'8',
#endif
'\0'};
#include "numeric.h"
#include "common.h"
#include "sys.h"
#include "whowas.h"
#include "hash.h"
#include <sys/file.h>
#ifdef HPUX
#include <fcntl.h>
#endif
#if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
!defined(__convex__)
# include <sys/param.h>
#endif
#ifdef HPUX
# include <sys/syscall.h>
# define getrusage(a,b) syscall(SYS_GETRUSAGE, a, b)
#endif
#ifdef GETRUSAGE_2
# ifdef SOL20
# include <sys/time.h>
# include <sys/rusage.h>
# endif
# include <sys/resource.h>
#else
# ifdef TIMES_2
# include <sys/times.h>
# endif
#endif
#ifdef PCS
# include <time.h>
#endif
#ifdef HPUX
#include <unistd.h>
#ifdef DYNIXPTX
#include <sys/types.h>
#include <time.h>
#endif
#endif
#include "h.h"
#ifndef ssize_t
#define ssize_t unsigned int
#endif
#ifdef DEBUGMODE
static char debugbuf[1024];
#ifndef USE_VARARGS
/*VARARGS2*/
void debug(level, form, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
int level;
char *form, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10;
{
int err = errno;
#else
void debug(level, form, va_alist)
int level;
char *form;
va_dcl
{
va_list vl;
int err = errno;
va_start(vl);
#endif
if ((debuglevel >= 0) && (level <= debuglevel))
{
#ifndef USE_VARARGS
(void)sprintf(debugbuf, form,
p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
#else
(void)vsprintf(debugbuf, form, vl);
#endif
if (local[2])
{
local[2]->sendM++;
local[2]->sendB += strlen(debugbuf);
}
(void)fprintf(stderr, "%s", debugbuf);
(void)fputc('\n', stderr);
}
errno = err;
}
/*
* This is part of the STATS replies. There is no offical numeric for this
* since this isnt an official command, in much the same way as HASH isnt.
* It is also possible that some systems wont support this call or have
* different field names for "struct rusage".
* -avalon
*/
void send_usage(cptr, nick)
aClient *cptr;
char *nick;
{
#ifdef GETRUSAGE_2
struct rusage rus;
time_t secs, rup;
#ifdef hz
# define hzz hz
#else
# ifdef HZ
# define hzz HZ
# else
int hzz = 1;
# ifdef HPUX
hzz = (int)sysconf(_SC_CLK_TCK);
# endif
# endif
#endif
if (getrusage(RUSAGE_SELF, &rus) == -1)
{
#if !defined(__FreeBSD__) && !defined(__NetBSD__)
extern char *sys_errlist[];
#endif
sendto_one(cptr,":%s NOTICE %s :Getruseage error: %s.",
me.name, nick, sys_errlist[errno]);
return;
}
secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
rup = now - me.since;
if (secs == 0)
secs = 1;
sendto_one(cptr,
":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
me.name, RPL_STATSDEBUG, nick, secs/60, secs%60,
rus.ru_utime.tv_sec/60, rus.ru_utime.tv_sec%60,
rus.ru_stime.tv_sec/60, rus.ru_stime.tv_sec%60);
sendto_one(cptr, ":%s %d %s :RSS %d ShMem %d Data %d Stack %d",
me.name, RPL_STATSDEBUG, nick, rus.ru_maxrss,
rus.ru_ixrss / (rup * hzz), rus.ru_idrss / (rup * hzz),
rus.ru_isrss / (rup * hzz));
sendto_one(cptr, ":%s %d %s :Swaps %d Reclaims %d Faults %d",
me.name, RPL_STATSDEBUG, nick, rus.ru_nswap,
rus.ru_minflt, rus.ru_majflt);
sendto_one(cptr, ":%s %d %s :Block in %d out %d",
me.name, RPL_STATSDEBUG, nick, rus.ru_inblock,
rus.ru_oublock);
sendto_one(cptr, ":%s %d %s :Msg Rcv %d Send %d",
me.name, RPL_STATSDEBUG, nick, rus.ru_msgrcv, rus.ru_msgsnd);
sendto_one(cptr, ":%s %d %s :Signals %d Context Vol. %d Invol %d",
me.name, RPL_STATSDEBUG, nick, rus.ru_nsignals,
rus.ru_nvcsw, rus.ru_nivcsw);
#else
# ifdef TIMES_2
struct tms tmsbuf;
time_t secs, mins;
int hzz = 1, ticpermin;
int umin, smin, usec, ssec;
# ifdef HPUX
hzz = sysconf(_SC_CLK_TCK);
# endif
ticpermin = hzz * 60;
umin = tmsbuf.tms_utime / ticpermin;
usec = (tmsbuf.tms_utime%ticpermin)/(float)hzz;
smin = tmsbuf.tms_stime / ticpermin;
ssec = (tmsbuf.tms_stime%ticpermin)/(float)hzz;
secs = usec + ssec;
mins = (secs/60) + umin + smin;
secs %= hzz;
if (times(&tmsbuf) == -1)
{
sendto_one(cptr,":%s %d %s :times(2) error: %s.",
me.name, RPL_STATSDEBUG, nick, strerror(errno));
return;
}
secs = tmsbuf.tms_utime + tmsbuf.tms_stime;
sendto_one(cptr,
":%s %d %s :CPU Secs %d:%d User %d:%d System %d:%d",
me.name, RPL_STATSDEBUG, nick, mins, secs, umin, usec,
smin, ssec);
# endif
#endif
sendto_one(cptr, ":%s %d %s :Reads %d Writes %d",
me.name, RPL_STATSDEBUG, nick, readcalls, writecalls);
sendto_one(cptr, ":%s %d %s :DBUF alloc %d blocks %d",
me.name, RPL_STATSDEBUG, nick, dbufalloc, dbufblocks);
sendto_one(cptr,
":%s %d %s :Writes: <0 %d 0 %d <16 %d <32 %d <64 %d",
me.name, RPL_STATSDEBUG, nick,
writeb[0], writeb[1], writeb[2], writeb[3], writeb[4]);
sendto_one(cptr,
":%s %d %s :<128 %d <256 %d <512 %d <1024 %d >1024 %d",
me.name, RPL_STATSDEBUG, nick,
writeb[5], writeb[6], writeb[7], writeb[8], writeb[9]);
return;
}
#endif
void count_memory(cptr, nick)
aClient *cptr;
char *nick;
{
extern aChannel *channel;
extern aClass *classes;
extern aConfItem *conf;
Reg1 aClient *acptr;
Reg2 Link *link;
Reg3 aChannel *chptr;
Reg4 aConfItem *aconf;
Reg5 aClass *cltmp;
int lc = 0, /* local clients */
ch = 0, /* channels */
lcc = 0, /* local client conf links */
rc = 0, /* remote clients */
us = 0, /* user structs */
chu = 0, /* channel users */
chi = 0, /* channel invites */
chb = 0, /* channel bans */
wwu = 0, /* whowas users */
cl = 0, /* classes */
co = 0; /* conf lines */
int usi = 0, /* users invited */
usc = 0, /* users in channels */
aw = 0, /* aways set */
wwa = 0; /* whowas aways */
u_long chm = 0, /* memory used by channels */
chbm = 0, /* memory used by channel bans */
lcm = 0, /* memory used by local clients */
rcm = 0, /* memory used by remote clients */
awm = 0, /* memory used by aways */
wwam = 0, /* whowas away memory used */
wwm = 0, /* whowas array memory used */
com = 0, /* memory used by conf lines */
db = 0, /* memory used by dbufs */
rm = 0, /* res memory used */
totcl = 0,
totch = 0,
totww = 0,
tot = 0;
count_whowas_memory(&wwu, &wwa, &wwam);
wwm = sizeof(aName) * NICKNAMEHISTORYLENGTH;
for (acptr = client; acptr; acptr = acptr->next)
{
if (IsPing(acptr))
continue;
if (MyConnect(acptr))
{
lc++;
for (link = acptr->confs; link; link = link->next)
lcc++;
}
else
rc++;
if (acptr->user)
{
us++;
for (link = acptr->user->invited; link;
link = link->next)
usi++;
for (link = acptr->user->channel; link;
link = link->next)
usc++;
if (acptr->user->away)
{
aw++;
awm += (strlen(acptr->user->away)+1);
}
}
}
lcm = lc * CLIENT_LOCAL_SIZE;
rcm = rc * CLIENT_REMOTE_SIZE;
for (chptr = channel; chptr; chptr = chptr->nextch)
{
ch++;
chm += (strlen(chptr->chname) + sizeof(aChannel));
for (link = chptr->members; link; link = link->next)
chu++;
for (link = chptr->invites; link; link = link->next)
chi++;
for (link = chptr->banlist; link; link = link->next)
{
chb++;
chbm += (strlen(link->value.cp)+1+sizeof(Link));
}
}
for (aconf = conf; aconf; aconf = aconf->next)
{
co++;
com += aconf->host ? strlen(aconf->host)+1 : 0;
com += aconf->passwd ? strlen(aconf->passwd)+1 : 0;
com += aconf->name ? strlen(aconf->name)+1 : 0;
com += sizeof(aConfItem);
}
for (cltmp = classes; cltmp; cltmp = cltmp->next)
cl++;
sendto_one(cptr, ":%s %d %s :Client Local %d(%d) Remote %d(%d)",
me.name, RPL_STATSDEBUG, nick, lc, lcm, rc, rcm);
sendto_one(cptr, ":%s %d %s :Users %d(%d) Invites %d(%d)",
me.name, RPL_STATSDEBUG, nick, us, us*sizeof(anUser), usi,
usi * sizeof(Link));
sendto_one(cptr, ":%s %d %s :User channels %d(%d) Aways %d(%d)",
me.name, RPL_STATSDEBUG, nick, usc, usc*sizeof(Link),
aw, awm);
sendto_one(cptr, ":%s %d %s :Attached confs %d(%d)",
me.name, RPL_STATSDEBUG, nick, lcc, lcc*sizeof(Link));
totcl = lcm + rcm + us*sizeof(anUser) + usc*sizeof(Link) + awm;
totcl += lcc*sizeof(Link) + usi*sizeof(Link);
sendto_one(cptr, ":%s %d %s :Conflines %d(%d)",
me.name, RPL_STATSDEBUG, nick, co, com);
sendto_one(cptr, ":%s %d %s :Classes %d(%d)",
me.name, RPL_STATSDEBUG, nick, cl, cl*sizeof(aClass));
sendto_one(cptr, ":%s %d %s :Channels %d(%d) Bans %d(%d)",
me.name, RPL_STATSDEBUG, nick, ch, chm, chb, chbm);
sendto_one(cptr, ":%s %d %s :Channel membrs %d(%d) invite %d(%d)",
me.name, RPL_STATSDEBUG, nick, chu, chu*sizeof(Link),
chi, chi*sizeof(Link));
totch = chm + chbm + chu*sizeof(Link) + chi*sizeof(Link);
sendto_one(cptr, ":%s %d %s :Whowas users %d(%d) away %d(%d)",
me.name, RPL_STATSDEBUG, nick, wwu, wwu*sizeof(anUser),
wwa, wwam);
sendto_one(cptr, ":%s %d %s :Whowas array %d(%d)",
me.name, RPL_STATSDEBUG, nick, NICKNAMEHISTORYLENGTH, wwm);
totww = wwu*sizeof(anUser) + wwam + wwm;
sendto_one(cptr, ":%s %d %s :Hash: client %d(%d) chan %d(%d)",
me.name, RPL_STATSDEBUG, nick, HASHSIZE,
sizeof(aHashEntry) * HASHSIZE,
CHANNELHASHSIZE, sizeof(aHashEntry) * CHANNELHASHSIZE);
db = dbufblocks * sizeof(dbufbuf);
sendto_one(cptr, ":%s %d %s :Dbuf blocks %d(%d)",
me.name, RPL_STATSDEBUG, nick, dbufblocks, db);
rm = cres_mem(cptr);
tot = totww + totch + totcl + com + cl*sizeof(aClass) + db + rm;
tot += sizeof(aHashEntry) * HASHSIZE;
tot += sizeof(aHashEntry) * CHANNELHASHSIZE;
sendto_one(cptr, ":%s %d %s :Total: ww %d ch %d cl %d co %d db %d",
me.name, RPL_STATSDEBUG, nick, totww, totch, totcl, com, db);
sendto_one(cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %u",
me.name, RPL_STATSDEBUG, nick, tot,
(u_int)sbrk((size_t)0)-(u_int)sbrk0);
return;
}

367
ircd/s_err.c Normal file
View File

@@ -0,0 +1,367 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/s_err.c
* Copyright (C) 1992 Darren Reed
*
* 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.
*/
#include "struct.h"
#include "numeric.h"
#ifndef lint
static char sccsid[] = "@(#)s_err.c 1.12 11/1/93 (C) 1992 Darren Reed";
#endif
typedef struct {
int num_val;
char *num_form;
} Numeric;
static char *prepbuf PROTO((char *, int, char *));
static char numbuff[512];
static char numbers[] = "0123456789";
static Numeric local_replies[] = {
/* 000 */ 0, (char *)NULL,
/* 001 */ RPL_WELCOME, ":Welcome to the Internet Relay Network %s",
/* 002 */ RPL_YOURHOST, ":Your host is %s, running version %s",
/* 003 */ RPL_CREATED, ":This server was created %s",
/* 004 */ RPL_MYINFO, "%s %s dioswk biklmnopstv",
/* 005 */ RPL_MAP, ":%s%s",
/* 006 */ RPL_MAPMORE, ":%s%s --> *more*",
/* 007 */ RPL_MAPEND, ":End of /MAP",
0, (char *)NULL
};
static Numeric numeric_errors[] = {
/* 401 */ ERR_NOSUCHNICK, "%s :No such nick/channel",
/* 402 */ ERR_NOSUCHSERVER, "%s :No such server",
/* 402 */ ERR_NOSUCHCHANNEL, "%s :No such channel",
/* 402 */ ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel",
/* 402 */ ERR_TOOMANYCHANNELS, "%s :You have joined too many channels",
/* 402 */ ERR_WASNOSUCHNICK, "%s :There was no such nickname",
/* 402 */ ERR_TOOMANYTARGETS,
"%s :Duplicate recipients. No message delivered",
/* 402 */ ERR_NOSUCHSERVICE, (char *)NULL,
/* 402 */ ERR_NOORIGIN, ":No origin specified",
0, (char *)NULL,
/* 411 */ ERR_NORECIPIENT, ":No recipient given (%s)",
/* 411 */ ERR_NOTEXTTOSEND, ":No text to send",
/* 411 */ ERR_NOTOPLEVEL, "%s :No toplevel domain specified",
/* 411 */ ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 421 */ ERR_UNKNOWNCOMMAND, "%s :Unknown command",
/* 422 */ ERR_NOMOTD, ":MOTD File is missing",
/* 422 */ ERR_NOADMININFO,
"%s :No administrative info available",
/* 422 */ ERR_FILEERROR, ":File error doing %s on %s",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 431 */ ERR_NONICKNAMEGIVEN, ":No nickname given",
/* 432 */ ERR_ERRONEUSNICKNAME, "%s :Erroneus Nickname",
/* 433 */ ERR_NICKNAMEINUSE, "%s :Nickname is already in use.",
/* 434 */ ERR_SERVICENAMEINUSE, (char *)NULL,
/* 435 */ ERR_SERVICECONFUSED, (char *)NULL,
/* 436 */ ERR_NICKCOLLISION, "%s :Nickname collision KILL",
/* 437 */ ERR_BANNICKCHANGE,
"%s :Cannot change nickname while banned on channel",
/* 438 */ ERR_NICKTOOFAST, "%s :Nick change too fast. Please wait %d seconds.",
0, (char *)NULL, 0, (char *)NULL,
/* 441 */ ERR_USERNOTINCHANNEL, "%s %s :They aren't on that channel",
/* 442 */ ERR_NOTONCHANNEL, "%s :You're not on that channel",
/* 443 */ ERR_USERONCHANNEL, "%s %s :is already on channel",
/* 444 */ ERR_NOLOGIN, "%s :User not logged in",
#ifndef ENABLE_SUMMON
/* 445 */ ERR_SUMMONDISABLED, ":SUMMON has been disabled",
#else
0, (char *)NULL,
#endif
#ifndef ENABLE_USERS
/* 446 */ ERR_USERSDISABLED, ":USERS has been disabled",
#else
0, (char *)NULL,
#endif
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 451 */ ERR_NOTREGISTERED, ":You have not registered",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 461 */ ERR_NEEDMOREPARAMS, "%s :Not enough parameters",
/* 462 */ ERR_ALREADYREGISTRED, ":You may not reregister",
/* 463 */ ERR_NOPERMFORHOST, ":Your host isn't among the privileged",
/* 464 */ ERR_PASSWDMISMATCH, ":Password Incorrect",
/* 465 */ ERR_YOUREBANNEDCREEP, ":You are banned from this server",
/* 466 */ ERR_YOUWILLBEBANNED, (char *)NULL,
/* 467 */ ERR_KEYSET, "%s :Channel key already set",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 471 */ ERR_CHANNELISFULL, "%s :Cannot join channel (+l)",
/* 472 */ ERR_UNKNOWNMODE , "%c :is unknown mode char to me",
/* 473 */ ERR_INVITEONLYCHAN, "%s :Cannot join channel (+i)",
/* 474 */ ERR_BANNEDFROMCHAN, "%s :Cannot join channel (+b)",
/* 475 */ ERR_BADCHANNELKEY, "%s :Cannot join channel (+k)",
/* 476 */ ERR_BADCHANMASK, "%s :Bad Channel Mask",
0, (char *)NULL,
/* 478 */ ERR_BANLISTFULL, "%s %s :Channel ban/ignore list is full",
0, (char *)NULL, 0, (char *)NULL,
/* 481 */ ERR_NOPRIVILEGES,
":Permission Denied- You're not an IRC operator",
/* 482 */ ERR_CHANOPRIVSNEEDED, "%s :You're not channel operator",
/* 483 */ ERR_CANTKILLSERVER, ":You cant kill a server!",
/* 484 */ ERR_ISCHANSERVICE, "%s %s :Cannot kick or deop channel service",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 491 */ ERR_NOOPERHOST, ":No O-lines for your host",
/* 492 */ ERR_NOSERVICEHOST, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL,
/* 501 */ ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag",
/* 502 */ ERR_USERSDONTMATCH, ":Cant change mode for other users",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL,
/* 511 */ ERR_SILELISTFULL, "%s :Your silence list is full",
/* 512 */ ERR_NOSUCHGLINE, "%s@%s :No such gline",
/* 513 */ ERR_BADPING, (char*)NULL
};
static Numeric numeric_replies[] = {
/* 300 */ RPL_NONE, (char *)NULL,
/* 301 */ RPL_AWAY, "%s :%s",
/* 302 */ RPL_USERHOST, ":",
/* 303 */ RPL_ISON, ":",
/* 304 */ RPL_TEXT, (char *)NULL,
/* 305 */ RPL_UNAWAY, ":You are no longer marked as being away",
/* 306 */ RPL_NOWAWAY, ":You have been marked as being away",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 311 */ RPL_WHOISUSER, "%s %s %s * :%s",
/* 312 */ RPL_WHOISSERVER, "%s %s :%s",
/* 313 */ RPL_WHOISOPERATOR, "%s :is an IRC Operator",
/* 314 */ RPL_WHOWASUSER, "%s %s %s * :%s",
/* 315 */ RPL_ENDOFWHO, "%s :End of /WHO list.",
/* 316 */ RPL_WHOISCHANOP, (char *)NULL,
/* 317 */ RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time",
/* 318 */ RPL_ENDOFWHOIS, "%s :End of /WHOIS list.",
/* 319 */ RPL_WHOISCHANNELS, "%s :%s",
0, (char *)NULL,
/* 321 */ RPL_LISTSTART, "Channel :Users Name",
/* 322 */ RPL_LIST, "%s %d :%s",
/* 323 */ RPL_LISTEND, ":End of /LIST",
/* 324 */ RPL_CHANNELMODEIS, "%s %s %s",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 329 */ RPL_CREATIONTIME, "%s %lu",
0, (char *)NULL,
/* 331 */ RPL_NOTOPIC, "%s :No topic is set.",
/* 332 */ RPL_TOPIC, "%s :%s",
/* 333 */ RPL_TOPICWHOTIME, "%s %s %lu",
/* 334 */ RPL_LISTUSAGE, ":%s",
0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 341 */ RPL_INVITING, "%s %s",
/* 342 */ RPL_SUMMONING, "%s :User summoned to irc",
0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 351 */ RPL_VERSION, "%s.%s %s :%s",
/* 352 */ RPL_WHOREPLY, "%s %s %s %s %s %s :%d %s",
/* 353 */ RPL_NAMREPLY, "%s",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 361 */ RPL_KILLDONE, (char *)NULL,
/* 362 */ RPL_CLOSING, "%s :Closed. Status = %d",
/* 363 */ RPL_CLOSEEND, "%d: Connections Closed",
/* 364 */ RPL_LINKS, "%s %s :%d P%u %s",
/* 365 */ RPL_ENDOFLINKS, "%s :End of /LINKS list.",
/* 366 */ RPL_ENDOFNAMES, "%s :End of /NAMES list.",
/* 367 */ RPL_BANLIST, "%s %s %s %lu",
/* 368 */ RPL_ENDOFBANLIST, "%s :End of Channel Ban List",
/* 369 */ RPL_ENDOFWHOWAS, "%s :End of WHOWAS",
0, (char *)NULL,
/* 371 */ RPL_INFO, ":%s",
/* 372 */ RPL_MOTD, ":- %s",
/* 373 */ RPL_INFOSTART, ":Server INFO",
/* 374 */ RPL_ENDOFINFO, ":End of /INFO list.",
/* 375 */ RPL_MOTDSTART, ":- %s Message of the Day - ",
/* 376 */ RPL_ENDOFMOTD, ":End of /MOTD command.",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 381 */ RPL_YOUREOPER, ":You are now an IRC Operator",
/* 382 */ RPL_REHASHING, "%s :Rehashing",
/* 383 */ RPL_YOURESERVICE, (char *)NULL,
/* 384 */ RPL_MYPORTIS, "%d :Port to local server is\r\n",
/* 385 */ RPL_NOTOPERANYMORE, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL,
/* 391 */ RPL_TIME, "%s %lu %ld :%s",
#ifdef ENABLE_USERS
/* 392 */ RPL_USERSSTART, ":UserID Terminal Host",
/* 393 */ RPL_USERS, ":%-8s %-9s %-8s",
/* 394 */ RPL_ENDOFUSERS, ":End of Users",
/* 395 */ RPL_NOUSERS, ":Nobody logged in.",
#else
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
#endif
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 200 */ RPL_TRACELINK, "Link %s%s %s %s",
/* 201 */ RPL_TRACECONNECTING, "Try. %d %s",
/* 202 */ RPL_TRACEHANDSHAKE, "H.S. %d %s",
/* 203 */ RPL_TRACEUNKNOWN, "???? %d %s",
/* 204 */ RPL_TRACEOPERATOR, "Oper %d %s %ld",
/* 205 */ RPL_TRACEUSER, "User %d %s %ld",
/* 206 */ RPL_TRACESERVER, "Serv %d %dS %dC %s %s!%s@%s %ld",
/* 207 */ RPL_TRACESERVICE, "Service %d %s",
/* 208 */ RPL_TRACENEWTYPE, "<newtype> 0 %s",
/* 209 */ RPL_TRACECLASS, "Class %d %d",
0, (char *)NULL,
/* 211 */ RPL_STATSLINKINFO, (char *)NULL,
/* 212 */ RPL_STATSCOMMANDS, "%s %u %u",
/* 213 */ RPL_STATSCLINE, "%c %s * %s %d %d",
/* 214 */ RPL_STATSNLINE, "%c %s * %s %d %d",
/* 215 */ RPL_STATSILINE, "%c %s * %s %d %d",
/* 216 */ RPL_STATSKLINE, "%c %s %s %s %d %d",
/* 217 */ RPL_STATSQLINE, "%c %s * %s %d %d",
/* 218 */ RPL_STATSYLINE, "%c %d %d %d %d %ld",
/* 219 */ RPL_ENDOFSTATS, "%c :End of /STATS report",
0, (char *)NULL,
/* 221 */ RPL_UMODEIS, "%s",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 231 */ RPL_SERVICEINFO, (char *)NULL,
/* 232 */ RPL_ENDOFSERVICES, (char *)NULL,
/* 233 */ RPL_SERVICE, (char *)NULL,
/* 234 */ RPL_SERVLIST, (char *)NULL,
/* 235 */ RPL_SERVLISTEND, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL,
/* 241 */ RPL_STATSLLINE, "%c %s * %s %d %d",
/* 242 */ RPL_STATSUPTIME, ":Server Up %d days, %d:%02d:%02d",
/* 243 */ RPL_STATSOLINE, "%c %s * %s %d %d",
/* 244 */ RPL_STATSHLINE, "%c %s * %s %d %d",
/* 245 */ RPL_STATSSLINE, "%c %s * %s %d %d",
/* 246 */ RPL_STATSTLINE, "%c %s %s",
/* 247 */ RPL_STATSGLINE, "%c %s@%s %lu :%s",
/* 248 */ RPL_STATSULINE, "%c %s * %s %d %d",
0, (char *)NULL,
/* 250 */ RPL_STATSCONN,
":Highest connection count: %d (%d clients)",
/* 251 */ RPL_LUSERCLIENT,
":There are %d users and %d invisible on %d servers",
/* 252 */ RPL_LUSEROP, "%d :operator(s) online",
/* 253 */ RPL_LUSERUNKNOWN, "%d :unknown connection(s)",
/* 254 */ RPL_LUSERCHANNELS, "%d :channels formed",
/* 255 */ RPL_LUSERME, ":I have %d clients and %d servers",
/* 256 */ RPL_ADMINME, ":Administrative info about %s",
/* 257 */ RPL_ADMINLOC1, ":%s",
/* 258 */ RPL_ADMINLOC2, ":%s",
/* 259 */ RPL_ADMINEMAIL, ":%s",
0, (char *)NULL,
/* 261 */ RPL_TRACELOG, "File %s %d",
/* 262 */ RPL_TRACEPING, "Ping %s %s",
0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
/* 271 */ RPL_SILELIST, "%s %s",
/* 272 */ RPL_ENDOFSILELIST, ":End of Silence List",
0, (char *)NULL, 0, (char *)NULL,
/* 275 */ RPL_STATSDLINE, "%c %s %s",
0, (char *)NULL, 0, (char *)NULL, 0, (char *)NULL,
0, (char *)NULL,
/* 280 */ RPL_GLIST, "%s@%s %lu %s%s",
/* 281 */ RPL_ENDOFGLIST, ":End of G-line List"
};
char *err_str(numeric)
int numeric;
{
Reg1 Numeric *nptr;
Reg2 int num = numeric;
num -= numeric_errors[0].num_val;
if (num < 0 || num > ERR_USERSDONTMATCH)
(void)sprintf(numbuff,
":%%s %d %%s :INTERNAL ERROR: BAD NUMERIC! %d",
numeric, num);
else
{
nptr = &numeric_errors[num];
if (!nptr->num_form || !nptr->num_val)
(void)sprintf(numbuff,
":%%s %d %%s :NO ERROR FOR NUMERIC ERROR %d",
numeric, num);
else
(void)prepbuf(numbuff, nptr->num_val, nptr->num_form);
}
return numbuff;
}
char *rpl_str(numeric)
int numeric;
{
Reg1 Numeric *nptr;
Reg2 int num = numeric;
if (num > 7)
num -= (num > 300) ? 300 : 100;
if (num < 0 || num > 200)
(void)sprintf(numbuff,
":%%s %d %%s :INTERNAL REPLY ERROR: BAD NUMERIC! %d",
numeric, num);
else
{
if (numeric > 99)
nptr = &numeric_replies[num];
else
nptr = &local_replies[num];
Debug((DEBUG_NUM, "rpl_str: numeric %d num %d nptr %x %d %x",
numeric, num, nptr, nptr->num_val, nptr->num_form));
if (!nptr->num_form || !nptr->num_val)
(void)sprintf(numbuff,
":%%s %d %%s :NO REPLY FOR NUMERIC ERROR %d",
numeric, num);
else
(void)prepbuf(numbuff, nptr->num_val, nptr->num_form);
}
return numbuff;
}
static char *prepbuf(buffer, num, tail)
char *buffer;
Reg1 int num;
char *tail;
{
Reg1 char *s;
(void)strcpy(buffer, ":%s ");
s = buffer + 4;
*s++ = numbers[num/100];
num %= 100;
*s++ = numbers[num/10];
*s++ = numbers[num%10];
(void)strcpy(s, " %s ");
(void)strcpy(s+4, tail);
return buffer;
}

777
ircd/s_misc.c Normal file
View File

@@ -0,0 +1,777 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/s_misc.c (formerly ircd/date.c)
* Copyright (C) 1990 Jarkko Oikarinen and
* University of Oulu, Computing Center
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)s_misc.c 2.42 3/1/94 (C) 1988 University of Oulu, \
Computing Center and Jarkko Oikarinen";
#endif
#include <sys/time.h>
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "userload.h"
#include <sys/stat.h>
#include <fcntl.h>
#if !defined(ULTRIX) && !defined(SGI) && !defined(sequent) && \
!defined(__convex__)
# include <sys/param.h>
#endif
#if defined(PCS) || defined(AIX) || defined(SVR3)
# include <time.h>
#endif
#ifdef HPUX
#include <unistd.h>
#endif
#ifdef DYNIXPTX
#include <sys/types.h>
#include <time.h>
#endif
#include "h.h"
static void exit_one_client PROTO((aClient *,aClient *,char *,int));
static char *months[] = {
"January", "February", "March", "April",
"May", "June", "July", "August",
"September", "October", "November", "December"
};
static char *weekdays[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
/*
* stats stuff
*/
struct stats ircst, *ircstp = &ircst;
char *date(clock)
time_t clock;
{
static char buf[80], plus;
Reg1 struct tm *lt, *gm;
struct tm gmbuf;
int minswest;
if (!clock)
clock = now;
gm = gmtime(&clock);
bcopy((char *)gm, (char *)&gmbuf, sizeof(gmbuf));
gm = &gmbuf;
lt = localtime(&clock);
if (lt->tm_yday == gm->tm_yday)
minswest = (gm->tm_hour - lt->tm_hour) * 60 +
(gm->tm_min - lt->tm_min);
else if (lt->tm_yday > gm->tm_yday)
minswest = (gm->tm_hour - (lt->tm_hour + 24)) * 60;
else
minswest = ((gm->tm_hour + 24) - lt->tm_hour) * 60;
plus = (minswest > 0) ? '-' : '+';
if (minswest < 0)
minswest = -minswest;
(void)sprintf(buf, "%s %s %d 19%02d -- %02d:%02d %c%02d:%02d",
weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday,
lt->tm_year, lt->tm_hour, lt->tm_min,
plus, minswest/60, minswest%60);
return buf;
}
/**
** myctime()
** This is like standard ctime()-function, but it zaps away
** the newline from the end of that string. Also, it takes
** the time value as parameter, instead of pointer to it.
** Note that it is necessary to copy the string to alternate
** buffer (who knows how ctime() implements it, maybe it statically
** has newline there and never 'refreshes' it -- zapping that
** might break things in other places...)
**
**/
char *myctime(value)
time_t value;
{
static char buf[28];
Reg1 char *p;
(void)strcpy(buf, ctime(&value));
if ((p = (char *)index(buf, '\n')) != NULL)
*p = '\0';
return buf;
}
/*
** check_registered_user is used to cancel message, if the
** originator is a server or not registered yet. In other
** words, passing this test, *MUST* guarantee that the
** sptr->user exists (not checked after this--let there
** be coredumps to catch bugs... this is intentional --msa ;)
**
** There is this nagging feeling... should this NOT_REGISTERED
** error really be sent to remote users? This happening means
** that remote servers have this user registered, althout this
** one has it not... Not really users fault... Perhaps this
** error message should be restricted to local clients and some
** other thing generated for remotes...
*/
int check_registered_user(sptr)
aClient *sptr;
{
if (!IsRegisteredUser(sptr))
{
sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
return -1;
}
return 0;
}
/*
** check_registered user cancels message, if 'x' is not
** registered (e.g. we don't know yet whether a server
** or user)
*/
int check_registered(sptr)
aClient *sptr;
{
if (!IsRegistered(sptr))
{
sendto_one(sptr, err_str(ERR_NOTREGISTERED), me.name, "*");
return -1;
}
return 0;
}
/*
** get_client_name
** Return the name of the client for various tracking and
** admin purposes. The main purpose of this function is to
** return the "socket host" name of the client, if that
** differs from the advertised name (other than case).
** But, this can be used to any client structure.
**
** Returns:
** "name[user@ip#.port]" if 'showip' is true;
** "name[sockethost]", if name and sockhost are different and
** showip is false; else
** "name".
**
** NOTE 1:
** Watch out the allocation of "nbuf", if either sptr->name
** or sptr->sockhost gets changed into pointers instead of
** directly allocated within the structure...
**
** NOTE 2:
** Function return either a pointer to the structure (sptr) or
** to internal buffer (nbuf). *NEVER* use the returned pointer
** to modify what it points!!!
*/
char *get_client_name(sptr, showip)
aClient *sptr;
int showip;
{
static char nbuf[HOSTLEN * 2 + USERLEN + 5];
if (MyConnect(sptr))
{
if (IsUnixSocket(sptr))
{
if (showip)
(void) sprintf(nbuf, "%s[%s]",
sptr->name, sptr->sockhost);
else
(void) sprintf(nbuf, "%s[%s]",
sptr->name, me.sockhost);
}
else
{
if (showip)
(void)sprintf(nbuf, "%s[%s@%s]",
sptr->name,
(!(sptr->flags & FLAGS_GOTID)) ? "" :
sptr->username,
inetntoa((char *)&sptr->ip));
else
{
if (mycmp(sptr->name, sptr->sockhost))
(void)sprintf(nbuf, "%s[%s]",
sptr->name, sptr->sockhost);
else
return sptr->name;
}
}
return nbuf;
}
return sptr->name;
}
char *get_client_host(cptr)
aClient *cptr;
{
static char nbuf[HOSTLEN * 2 + USERLEN + 5];
if (!MyConnect(cptr))
return cptr->name;
if (!cptr->hostp)
return get_client_name(cptr, FALSE);
if (IsUnixSocket(cptr))
(void) sprintf(nbuf, "%s[%s]", cptr->name, me.name);
else
(void)sprintf(nbuf, "%s[%-.*s@%-.*s]",
cptr->name, USERLEN,
(!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->username,
HOSTLEN, cptr->hostp->h_name);
return nbuf;
}
/*
* Form sockhost such that if the host is of form user@host, only the host
* portion is copied.
*/
void get_sockhost(cptr, host)
Reg1 aClient *cptr;
Reg2 char *host;
{
Reg3 char *s;
if ((s = (char *)index(host, '@')))
s++;
else
s = host;
strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost));
}
/*
* Return wildcard name of my server name according to given config entry
* --Jto
*/
char *my_name_for_link(name, aconf)
char *name;
aConfItem *aconf;
{
static char namebuf[HOSTLEN];
register int count = aconf->port;
register char *start = name;
if (count <= 0 || count > 5)
return start;
while (count-- && name)
{
name++;
name = (char *)index(name, '.');
}
if (!name)
return start;
namebuf[0] = '*';
(void)strncpy(&namebuf[1], name, HOSTLEN - 1);
namebuf[HOSTLEN - 1] = '\0';
return namebuf;
}
/*
** exit_downlinks - added by Run 25-9-94
**
** Removes all clients and downlinks (+clients) of any server
** QUITs are generated and sent to local users.
**
** cptr : server that must have all dependents removed
** sptr : source who thought that this was a good idea
** comment : comment sent as sign off message to local clients
*/
void exit_downlinks(cptr, sptr, comment)
aClient *cptr, *sptr;
char *comment;
{
Reg1 aClient *acptr;
Reg2 Dlink *next;
Reg3 Dlink *lp;
/* Run over all its downlinks */
for (lp=cptr->serv->down; lp; lp=next)
{
next=lp->next;
acptr=lp->value.cptr;
/* Remove the downlinks and client of the downlink */
exit_downlinks(acptr, sptr, comment);
/* Remove the downlink itself */
exit_one_client(acptr, sptr, me.name, 1);
}
/* Remove all clients of this server */
for (lp=cptr->serv->client; lp; lp=next)
{
next=lp->next;
exit_one_client(lp->value.cptr, sptr, comment, 1);
}
}
/*
** exit_client, rewritten 25-9-94 by Run
**
** 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.
**
** This function implicitly exits all other clients depending on
** this connection.
**
** For convenience, this function returns a suitable value for
** m_funtion return value:
**
** CPTR_KILLED if (cptr == bcptr)
** 0 if (cptr != bcptr)
**
** This function can be called in two ways:
** 1) From before or in parse(), exitting the 'cptr', in which case it was
** invoked as exit_client(cptr, cptr, &me,...), causing it to always
** return CPTR_KILLED.
** 2) Via parse from a m_function call, in which case it was invoked as
** exit_client(cptr, acptr, sptr, ...). Here 'sptr' is known; the client
** that generated the message in a way that we can assume he already
** did remove acptr from memory himself (or in other cases we don't mind
** because he will be delinked.) Or invoked as:
** exit_client(cptr, acptr/sptr, &me, ...) when WE decide this one should
** be removed.
** In general: No generated SQUIT or QUIT should be sent to source link
** sptr->from. And CPTR_KILLED should be returned if cptr got removed (too).
**
** --Run
*/
int exit_client(cptr, bcptr, sptr, comment)
aClient *cptr; /* Connection being handled by read_message right now */
aClient *bcptr; /* Client being killed */
aClient *sptr; /* The client that made the decision to remove this
one, never NULL */
char *comment; /* Reason for the exit */
{
Reg1 aClient *acptr;
Reg2 aClient *next;
Reg3 Dlink *dlp;
#ifdef FNAME_USERLOG
time_t on_for;
#endif
char comment1[HOSTLEN + HOSTLEN + 2];
if (MyConnect(bcptr))
{
bcptr->flags |= FLAGS_CLOSING;
current_load_data.conn_count--;
if (IsPerson(bcptr))
{
char mydom_mask[HOSTLEN + 1];
mydom_mask[0] = '*';
sendto_realops ("Client exiting: %s (%s@%s) [%s]",
bcptr->name, bcptr->user->username, bcptr->user->host, comment);
strncpy(&mydom_mask[1], DOMAINNAME, HOSTLEN - 1);
current_load_data.client_count--;
if (matches(mydom_mask, bcptr->sockhost) == 0)
current_load_data.local_count--;
}
update_load();
#ifdef FNAME_USERLOG
on_for = now - bcptr->firsttime;
# if defined(USE_SYSLOG) && defined(SYSLOG_USERS)
if (IsPerson(bcptr))
syslog(LOG_NOTICE, "%s (%3d:%02d:%02d): %s@%s (%s)\n",
myctime(bcptr->firsttime), on_for / 3600, (on_for % 3600)/60,
on_for % 60, bcptr->user->username, bcptr->sockhost, bcptr->name);
# else
{
char linebuf[160];
int logfile;
/*
* This conditional makes the logfile active only after
* it's been created - thus logging can be turned off by
* removing the file.
*
* stop NFS hangs...most systems should be able to open a
* file in 3 seconds. -avalon (curtesy of wumpus)
*/
(void)alarm(3);
if (IsPerson(bcptr) &&
(logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1)
{
(void)alarm(0);
(void)sprintf(linebuf,
"%s (%3d:%02d:%02d): %s@%s [%s]\n",
myctime(bcptr->firsttime),
on_for / 3600, (on_for % 3600)/60,
on_for % 60,
bcptr->user->username, bcptr->user->host,
bcptr->username);
(void)alarm(3);
(void)write(logfile, linebuf, strlen(linebuf));
(void)alarm(0);
(void)close(logfile);
}
(void)alarm(0);
/* Modification by stealth@caen.engin.umich.edu */
}
# endif
#endif
if (bcptr != sptr->from && bcptr->status >= STAT_MASTER)
/* the source knows already --Run */
{
if (IsServer(bcptr) || IsHandshake(bcptr))
{
if (IsServer(bcptr) && Protocol(bcptr->from)<9)
sendto_one(bcptr, ":%s SQUIT %s :%s", sptr->name,
me.name, comment);
else /* If we are handshaking, use the newest protocol :/ */
sendto_one(bcptr, ":%s SQUIT %s 0 :%s", sptr->name,
me.name, comment);
}
else if (!IsConnecting(bcptr))
sendto_one(bcptr, "ERROR :Closing Link: %s by %s (%s)",
get_client_name(bcptr,FALSE), sptr->name, comment);
if ((IsServer(bcptr) || IsHandshake(bcptr) || IsConnecting(bcptr)) &&
(sptr == &me || (IsServer(sptr) &&
(strncmp(comment, "Leaf-only link", 14) ||
strncmp(comment, "Non-Hub link", 12)))))
{
if (bcptr->serv->user && (acptr=find_client(bcptr->serv->by, NULL)) &&
acptr->user == bcptr->serv->user)
sendto_one(acptr,
":%s NOTICE %s :Link with %s cancelled: %s",
me.name, acptr->name, bcptr->name, comment);
else
acptr = NULL;
if (sptr == &me)
sendto_lops_butone(acptr, "Link with %s cancelled: %s",
bcptr->name, comment);
}
}
/*
** Close the Client connection first.
*/
close_connection(bcptr);
}
if (IsServer(bcptr))
{
(void)strcpy(comment1, bcptr->serv->up->name);
(void)strcat(comment1," ");
(void)strcat(comment1, bcptr->name);
if (!IsServer(sptr) || Protocol(sptr)>4)
{
if (IsPerson(sptr))
sendto_lops_butone(sptr, "%s SQUIT by %s [%s]:",
(sptr->user->server == bcptr ||
sptr->user->server == bcptr->serv->up) ? "Local" : "Remote",
get_client_name(sptr,TRUE), sptr->user->server->name);
else if (sptr != &me && bcptr->serv->up != sptr)
sendto_ops("Received SQUIT %s from %s :", bcptr->name,
IsServer(sptr) ? sptr->name : get_client_name(sptr,TRUE));
sendto_ops("Net break: %s (%s)", comment1, comment);
}
exit_downlinks(bcptr, sptr, comment1);
}
/*
** Now generate the needed protocol for the other server links
** except the source: USE_SERVICES not supported
*/
for (dlp = me.serv->down; dlp; dlp = dlp->next)
if (dlp->value.cptr != sptr->from &&
dlp->value.cptr != bcptr)
{
if (IsServer(bcptr))
sendto_one(dlp->value.cptr, ":%s SQUIT %s %lu :%s",
sptr->name, bcptr->name, bcptr->serv->timestamp, comment);
else if (IsClient(bcptr) && (bcptr->flags & FLAGS_KILLED) == 0)
sendto_one(dlp->value.cptr, ":%s QUIT :%s", bcptr->name, comment);
}
exit_one_client(bcptr, sptr, comment, 0);
/*
** cptr can only have been killed if it was cptr itself that got killed here,
** because cptr can never have been a dependant of bcptr --Run
*/
return (cptr == bcptr) ? CPTR_KILLED : 0;
}
/*
** Exit client with formatted message, added 25-9-94 by Run
*/
#ifndef USE_VARARGS
/*VARARGS*/
int exit_client_msg(cptr, bcptr, sptr, pattern, p1, p2, p3, p4, p5, p6)
aClient *cptr, *bcptr, *sptr;
char *pattern, *p1, *p2, *p3, *p4, *p5, *p6;
{
#else
int exit_client_msg(cptr, bcptr, sptr, pattern, va_alist)
aClient *cptr, *bcptr, *sptr;
char *pattern;
va_dcl
{
va_list vl;
#endif
char msgbuf[1024];
#ifdef USE_VARARGS
va_start(vl);
(void)vsprintf(msgbuf, pattern, vl);
va_end(vl);
#else
(void)sprintf(msgbuf, pattern, p1, p2, p3, p4, p5, p6);
#endif
return exit_client(cptr, bcptr, sptr, msgbuf);
}
/*
** Exit one client, local or remote. Assuming for local client that
** all dependants already have been removed, and socket is closed.
**
** Rewritten by Run - 24 sept 94
**
** bcptr : client being (s)quitted
** sptr : The source (prefix) of the QUIT or SQUIT
**
** --Run
*/
static void exit_one_client(bcptr, sptr, comment, OldProtocolFlag)
aClient *bcptr, *sptr;
char *comment;
int OldProtocolFlag;
{
Reg1 aClient *acptr;
Reg2 int i;
Reg3 Link *lp;
Reg4 Link *prev;
Reg5 Dlink *dlp;
if (IsClient(bcptr))
{
/* Stop a running /LIST clean */
if (MyClient(bcptr) && bcptr->listing)
{
bcptr->listing->mode.mode &= ~MODE_LISTED;
bcptr->listing = NULL;
}
if (AskedPing(bcptr))
cancel_ping(bcptr, NULL);
/*
** If this exit is generated from "m_kill", then there
** is no sense in sending the QUIT--KILL's have been
** sent instead.
*/
/* Old Protocol : */
if ((bcptr->flags & FLAGS_KILLED) == 0)
{
for (dlp = me.serv->down; dlp; dlp = dlp->next)
if (Protocol(dlp->value.cptr)<9 && bcptr->from != dlp->value.cptr)
sendto_one(dlp->value.cptr,":%s QUIT :%s", bcptr->name, comment);
}
/*
** 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*)
*/
sendto_common_channels(bcptr, ":%s QUIT :%s", bcptr->name, comment);
#ifdef NPATH
note_signoff(bcptr);
#endif
while ((lp = bcptr->user->channel))
remove_user_from_channel(bcptr,lp->value.chptr);
/* Clean up invitefield */
while ((lp = bcptr->user->invited))
del_invite(bcptr, lp->value.chptr);
/* Clean up silencefield */
while ((lp = bcptr->user->silence))
(void)del_silence(bcptr, lp->value.cp);
/* Remove from serv->client list */
remove_dlink(&bcptr->user->server->serv->client, bcptr->user->clink);
}
else if (IsServer(bcptr))
{
/* Old Protocol : */
for (dlp = me.serv->down; dlp; dlp = dlp->next)
if (Protocol(dlp->value.cptr)<9 && dlp->value.cptr->fd >= 0)
{
if (bcptr->from != dlp->value.cptr &&
(sptr->from != dlp->value.cptr->from || OldProtocolFlag))
sendto_one(dlp->value.cptr, "SQUIT %s :%s", bcptr->name, comment);
else if (sptr->from != dlp->value.cptr->from && !OldProtocolFlag)
sendto_one(dlp->value.cptr, ":%s SQUIT %s :%s", sptr->name,
bcptr->name, comment);
}
/* Remove downlink list node of uplink */
remove_dlink(&bcptr->serv->up->serv->down, bcptr->serv->updown);
}
else if (IsPing(bcptr)) /* Apperently, we are closing ALL links */
{
del_queries((char *)bcptr);
end_ping(bcptr);
return;
}
else if (IsService(bcptr))
{
/* Lame, lamer, Avalon. */
sendto_ops("ERROR: exit_one_client: Service? Whaisda?");
}
else if (IsMe(bcptr))
{
sendto_ops("ERROR: tried to exit me! : %s", comment);
return; /* ...must *never* exit self! */
}
/* Remove bcptr from the client list */
if (del_from_client_hash_table(bcptr->name, bcptr) != 1)
Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x",
bcptr, bcptr->name, bcptr->from ? bcptr->from->sockhost : "??host",
bcptr->from, bcptr->next, bcptr->prev, bcptr->fd,
bcptr->status, bcptr->user));
remove_client_from_list(bcptr);
return;
}
void checklist()
{
Reg1 aClient *acptr;
Reg2 int i,j;
if (!(bootopt & BOOT_AUTODIE))
return;
for (j = i = 0; i <= highest_fd; i++)
if (!(acptr = local[i]))
continue;
else if (IsClient(acptr))
j++;
if (!j)
{
#ifdef USE_SYSLOG
syslog(LOG_WARNING,"ircd exiting: autodie");
#endif
exit(0);
}
return;
}
void initstats()
{
bzero((char *)&ircst, sizeof(ircst));
}
void tstats(cptr, name)
aClient *cptr;
char *name;
{
Reg1 aClient *acptr;
Reg2 int i;
Reg3 struct stats *sp;
struct stats tmp;
sp = &tmp;
bcopy((char *)ircstp, (char *)sp, sizeof(*sp));
for (i = 0; i < MAXCONNECTIONS; i++)
{
if (!(acptr = local[i]))
continue;
if (IsServer(acptr))
{
sp->is_sbs += acptr->sendB;
sp->is_sbr += acptr->receiveB;
sp->is_sks += acptr->sendK;
sp->is_skr += acptr->receiveK;
sp->is_sti += now - acptr->firsttime;
sp->is_sv++;
if (sp->is_sbs > 1023)
{
sp->is_sks += (sp->is_sbs >> 10);
sp->is_sbs &= 0x3ff;
}
if (sp->is_sbr > 1023)
{
sp->is_skr += (sp->is_sbr >> 10);
sp->is_sbr &= 0x3ff;
}
}
else if (IsClient(acptr))
{
sp->is_cbs += acptr->sendB;
sp->is_cbr += acptr->receiveB;
sp->is_cks += acptr->sendK;
sp->is_ckr += acptr->receiveK;
sp->is_cti += now - acptr->firsttime;
sp->is_cl++;
if (sp->is_cbs > 1023)
{
sp->is_cks += (sp->is_cbs >> 10);
sp->is_cbs &= 0x3ff;
}
if (sp->is_cbr > 1023)
{
sp->is_ckr += (sp->is_cbr >> 10);
sp->is_cbr &= 0x3ff;
}
}
else if (IsUnknown(acptr))
sp->is_ni++;
}
sendto_one(cptr, ":%s %d %s :accepts %u refused %u",
me.name, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref);
sendto_one(cptr, ":%s %d %s :unknown commands %u prefixes %u",
me.name, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf);
sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u",
me.name, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni);
sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u",
me.name, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt);
sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u",
me.name, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake);
sendto_one(cptr, ":%s %d %s :auth successes %u fails %u",
me.name, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad);
sendto_one(cptr, ":%s %d %s :local connections %u udp packets %u",
me.name, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udp);
sendto_one(cptr, ":%s %d %s :Client Server",
me.name, RPL_STATSDEBUG, name);
sendto_one(cptr, ":%s %d %s :connected %u %u",
me.name, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv);
sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK",
me.name, RPL_STATSDEBUG, name,
sp->is_cks, sp->is_cbs, sp->is_sks, sp->is_sbs);
sendto_one(cptr, ":%s %d %s :bytes recv %u.%uK %u.%uK",
me.name, RPL_STATSDEBUG, name,
sp->is_ckr, sp->is_cbr, sp->is_skr, sp->is_sbr);
sendto_one(cptr, ":%s %d %s :time connected %u %u",
me.name, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti);
}

129
ircd/s_numeric.c Normal file
View File

@@ -0,0 +1,129 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/s_numeric.c
* Copyright (C) 1990 Jarkko Oikarinen
*
* Numerous fixes by Markku Savela
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)s_numeric.c 2.14 1/30/94 (C) 1988 University of Oulu, \
Computing Center and Jarkko Oikarinen";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "h.h"
static char buffer[1024];
/*
** DoNumeric (replacement for the old do_numeric)
**
** parc number of arguments ('sender' counted as one!)
** parv[0] pointer to 'sender' (may point to empty string) (not used)
** parv[1]..parv[parc-1]
** pointers to additional parameters, this is a NULL
** terminated list (parv[parc] == NULL).
**
** *WARNING*
** Numerics are mostly error reports. If there is something
** wrong with the message, just *DROP* it! Don't even think of
** sending back a neat error message -- big danger of creating
** a ping pong error message...
*/
int do_numeric(numeric, cptr, sptr, parc, parv)
int numeric;
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aClient *acptr;
aChannel *chptr;
char *nick, *p;
int i;
if (parc < 1 || !IsServer(sptr))
return 0;
/* Remap low number numerics. */
if (numeric < 100)
numeric += 100;
/*
** Prepare the parameter portion of the message into 'buffer'.
** (Because the buffer is twice as large as the message buffer
** for the socket, no overflow can occur here... ...on current
** assumptions--bets are off, if these are changed --msa)
** Note: if buffer is non-empty, it will begin with SPACE.
*/
buffer[0] = '\0';
if (parc > 1)
{
for (i = 2; i < (parc - 1); i++)
{
(void)strcat(buffer, " ");
(void)strcat(buffer, parv[i]);
}
(void)strcat(buffer, " :");
(void)strcat(buffer, parv[parc-1]);
}
for (; (nick = strtoken(&p, parv[1], ",")); parv[1] = NULL)
{
if ((acptr = find_client(nick, (aClient *)NULL)))
{
/*
** Drop to bit bucket if for me...
** ...one might consider sendto_ops
** here... --msa
** And so it was done. -avalon
** And regretted. Dont do it that way. Make sure
** it goes only to non-servers. -avalon
** Check added to make sure servers don't try to loop
** with numerics which can happen with nick collisions.
** - Avalon
*/
if (!IsMe(acptr) && IsPerson(acptr))
{
/* Added for .U3.2. drop remote 'You are not on
** that channel', we should be synced anyway,
** and this is an annoying message with TSpre7
** still on the net; would result in numeric 442 for
** every KICK... Can be removed when TSpre7 is gone.
** --Run
*/
if (numeric==ERR_NOTONCHANNEL) return 0;
sendto_prefix_one(acptr, sptr,":%s %d %s%s",
parv[0], numeric, nick, buffer);
}
else if (IsServer(acptr) && acptr->from != cptr)
sendto_prefix_one(acptr, sptr,":%s %d %s%s",
parv[0], numeric, nick, buffer);
}
else if ((acptr = find_server(nick, (aClient *)NULL)))
{
if (!IsMe(acptr) && acptr->from != cptr)
sendto_prefix_one(acptr, sptr,":%s %d %s%s",
parv[0], numeric, nick, buffer);
}
else if ((chptr = find_channel(nick, (aChannel *)NULL)))
sendto_channel_butone(cptr,sptr,chptr,":%s %d %s%s",
parv[0],
numeric, chptr->chname, buffer);
}
return 0;
}

500
ircd/s_ping.c Normal file
View File

@@ -0,0 +1,500 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/s_ping.c
* Copyright (C) 1994 Carlo K ( Run @ undernet.org )
*
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)s_ping.c 1.0 9/21/94 (C) 1994 Carlo Kid";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "patchlevel.h"
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#ifdef UNIXPORT
# include <sys/un.h>
#endif
#if defined(__hpux)
# include "inet.h"
#endif
#include <fcntl.h>
#include "sock.h" /* If FD_ZERO isn't defined up to this point, */
/* define it (BSD4.2 needs this) */
#include "h.h"
#define UPINGBUFSIZE 2000 /* Lot bigger then 1024, bit smaller then 2048 */
#define UPINGTIMEOUT 120 /* Timeout waitting for first ping response */
extern u_long inet_addr();
/*
* start_ping
*
* As for now, I am abusing the client structure for a ping connection.
* Used members are:
* These are used by existing routines as well, and do have their own meaning:
* fd : The socket file descriptor.
* status : To flag that this IS one of these abused ping structures
* sockhost : Name of requested server to ping (aconf->host).
* name : aconf->name
* ip : ip#
* These have more or less their own meaning,
* but are not used by existing routines:
* flags : To flag that a next ping is requested.
* port : Requested remote port.
* These are only used by the 'uping' routines
* and have totally different meanings:
* buffer : buffer hold pingtimes of received packets
* confs : recv/send (char *) buffer.
* hopcount : Total number of requested pings
* count : Number of pings left to send.
* hashv : Number of pings left to be received.
* acpt : client asking for this ping
* lasttime : last time a ping was sent
* firsttime: recvfrom timeout
* since : timeout in seconds to next recvfrom
* receiveK : minimum in ms
* sendM : average in ms
* receiveM : maximum in ms
*/
int start_ping(cptr)
Reg1 aClient *cptr;
{
struct sockaddr_in remote_addr;
Debug((DEBUG_NOTICE,"start_ping(%x) status %d", cptr, cptr->status));
if (!(cptr->acpt)) return -1;
bcopy((char *)&cptr->ip, (char *)&remote_addr.sin_addr,
sizeof(struct in_addr));
#ifdef TESTNET
remote_addr.sin_port = htons(cptr->port + 10000);
#else
remote_addr.sin_port = htons(cptr->port);
#endif
remote_addr.sin_family = AF_INET;
sendto_one(cptr->acpt,
":%s NOTICE %s :Sending %d ping%s to %s[%s] port %d",
me.name, cptr->acpt->name, cptr->hopcount,
(cptr->hopcount == 1) ? "" : "s", cptr->name,
#ifdef TESTNET
inetntoa((char *)&remote_addr.sin_addr), ntohs(remote_addr.sin_port)
- 10000);
#else
inetntoa((char *)&remote_addr.sin_addr), ntohs(remote_addr.sin_port));
#endif
cptr->firsttime = now + UPINGTIMEOUT;
cptr->since = UPINGTIMEOUT;
cptr->flags |= (FLAGS_PING);
return 0;
}
/*
* send_ping
*
*/
void send_ping(cptr)
aClient *cptr;
{
struct sockaddr_in remote_addr;
struct timeval tv;
bcopy((char *)&cptr->ip, (char *)&remote_addr.sin_addr,
sizeof(struct in_addr));
#ifdef TESTNET
remote_addr.sin_port = htons(cptr->port + 10000);
#else
remote_addr.sin_port = htons(cptr->port);
#endif
remote_addr.sin_family = AF_INET;
(void) gettimeofday(&tv, NULL);
(void)sprintf((char *)cptr->confs, " %10lu%c%6lu",
tv.tv_sec, '\0', tv.tv_usec);
Debug((DEBUG_SEND, "send_ping: sending [%s %s] to %s.%d on %d",
(char *)cptr->confs, (char *)cptr->confs + 12,
inetntoa((char *)&remote_addr.sin_addr), ntohs(remote_addr.sin_port),
cptr->fd));
if (sendto(cptr->fd, (char *)cptr->confs, 1024, 0,
(struct sockaddr *)&remote_addr, sizeof(struct sockaddr_in)) != 1024)
{
int err=errno;
if (cptr->acpt)
sendto_one(cptr->acpt, ":%s NOTICE %s :UPING: sendto() failed: %s",
me.name, cptr->acpt->name, strerror(get_sockerr(cptr)));
Debug((DEBUG_SEND, "send_ping: sendto failed on %d (%d)", cptr->fd, err));
end_ping(cptr);
}
else if (--(cptr->count) <= 0 )
{
ClearPing(cptr);
if (cptr->hashv <= 0) end_ping(cptr);
}
return;
}
/*
* read_ping
*
*/
void read_ping(cptr)
Reg1 aClient *cptr;
{
int addr_len = sizeof(struct sockaddr_in);
struct sockaddr_in remote_addr;
struct timeval tv;
int len;
unsigned long int pingtime;
char *s;
bcopy((char *)&cptr->ip, (char *)&remote_addr.sin_addr,
sizeof(struct in_addr));
#ifdef TESTNET
remote_addr.sin_port = htons(cptr->port + 10000);
#else
remote_addr.sin_port = htons(cptr->port);
#endif
remote_addr.sin_family = AF_INET;
(void)gettimeofday(&tv, NULL);
if ((len=recvfrom(cptr->fd, (char *)cptr->confs, UPINGBUFSIZE, 0,
(struct sockaddr *)&remote_addr, &addr_len)) == -1)
{
int err = errno;
sendto_one(cptr->acpt,
":%s NOTICE %s :UPING: recvfrom: %s",
me.name, cptr->acpt->name, strerror(get_sockerr(cptr)));
Debug((DEBUG_SEND, "read_ping: recvfrom: %d", err));
if (err != EAGAIN) end_ping(cptr);
return;
}
if (len<19) return; /* Broken packet */
pingtime = (tv.tv_sec - atoi((char *)cptr->confs + 1)) * 1000 +
(tv.tv_usec - atoi((char *)cptr->confs + strlen((char *)cptr->confs) +
1)) / 1000;
cptr->sendM += pingtime;
if (!(cptr->receiveK) || (cptr->receiveK > pingtime))
cptr->receiveK = pingtime;
if (pingtime > cptr->receiveM)
cptr->receiveM = pingtime;
/* Wait at most 10 times the average pingtime for the next one: */
if ((cptr->since =
cptr->sendM / ( 100 * (cptr->hopcount - cptr->hashv + 1))) < 2)
cptr->since = 2;
cptr->firsttime = tv.tv_sec + cptr->since;
Debug(("read_ping: %d bytes, ti %lu: [%s %s] %u ms",
len, cptr->since, (char *)cptr->confs,
(char *)cptr->confs + strlen((char *)cptr->confs) + 1, pingtime));
s = cptr->buffer + strlen(cptr->buffer);
sprintf(s, " %lu", pingtime);
if ((--(cptr->hashv) <= 0 && !DoPing(cptr)) || !(cptr->acpt))
end_ping(cptr);
return;
}
int ping_server(cptr, hp)
aClient *cptr;
struct hostent *hp;
{
if ( ( !cptr->ip.s_addr )
#ifdef UNIXPORT
&& ( ( cptr->sockhost[2] ) != '/' )
#endif
)
{
struct hostent *hp;
char *s;
Link lin;
if (!(cptr->acpt)) return -1; /* Oper left already */
lin.flags = ASYNC_PING;
lin.value.cptr = cptr;
nextdnscheck = 1;
s = (char *)index(cptr->sockhost, '@');
s++; /* should never be NULL; cptr->sockhost is actually a conf->host */
if ((cptr->ip.s_addr = inet_addr(s)) == -1)
{
cptr->ip.s_addr = 0;
hp = gethost_byname(s, &lin);
Debug((DEBUG_NOTICE, "ping_sv: hp %x ac %x ho %s", hp, cptr, s));
if (!hp) return 0;
bcopy(hp->h_addr, (char *)&cptr->ip, sizeof(struct in_addr));
}
}
return start_ping(cptr);
}
/*
** m_uping -- by Run
**
** parv[0] = sender prefix
** parv[1] = pinged server
** parv[2] = port
** parv[3] = hunted server
** parv[4] = number of requested pings
*/
int m_uping(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
aConfItem *aconf;
int port, fd, opt;
if (!IsPrivileged(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return -1;
}
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "UPING");
return 0;
}
if (MyClient(sptr))
{
if (parc == 2)
{
parv[parc++]=UDP_PORT;
parv[parc++]=me.name;
parv[parc++]="5";
}
else if (parc == 3)
{
if (isdigit(*parv[2]))
{
parv[parc++]=me.name;
}
else
{
parv[parc++]=parv[2];
parv[2]=UDP_PORT;
}
parv[parc++]="5";
}
else if (parc == 4)
{
if (isdigit(*parv[2]))
{
if (isdigit(*parv[3]))
{
parv[parc++]=parv[3];
parv[3]=me.name;
}
else
parv[parc++]="5";
}
else
{
parv[parc++]=parv[3];
parv[3]=parv[2];
parv[2]=UDP_PORT;
}
}
}
if (hunt_server(cptr,sptr,":%s UPING %s %s %s %s",3,parc,parv) != HUNTED_ISME)
return 0;
if (BadPtr(parv[4]) || atoi(parv[4])<=0)
{
sendto_one(sptr,":%s NOTICE %s :UPING: Illegal number of packets: %s",
me.name, parv[0], parv[4]);
return 0;
}
/* Check if a CONNECT would be possible at all (adapted from m_connect) */
for (aconf = conf; aconf; aconf = aconf->next)
if (aconf->status == CONF_CONNECT_SERVER &&
matches(parv[1], aconf->name) == 0)
break;
if (!aconf)
for (aconf = conf; aconf; aconf = aconf->next)
if (aconf->status == CONF_CONNECT_SERVER &&
(matches(parv[1], aconf->host) == 0 ||
matches(parv[1], index(aconf->host, '@')+1) == 0))
break;
if (!aconf)
{
sendto_one(sptr, "NOTICE %s :UPING: Host %s not listed in ircd.conf",
parv[0], parv[1]);
return 0;
}
if (AskedPing(sptr))
cancel_ping(sptr, sptr); /* Cancel previous ping request */
/*
* Determine port: First user supplied, then default : 7007
*/
if (!BadPtr(parv[2]) && (port = atoi(parv[2])) <= 0) port=atoi(UDP_PORT);
(void)alarm(2);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
int err = errno;
(void)alarm(0);
sendto_ops("m_uping: socket: %s", (err != EAGAIN) ?
strerror(err) : "No more sockets");
sendto_one(sptr, ":%s NOTICE %s :UPING: Unable to create udp ping socket",
me.name, parv[0]);
#ifdef USE_SYSLOG
syslog(LOG_ERR, "Unable to create udp ping socket");
#endif
return 0;
}
(void)alarm(0);
if (fcntl(fd, F_SETFL, FNDELAY)==-1)
{
sendto_ops("m_uping: fcntl FNDELAY: %s", strerror(errno));
sendto_one(sptr, ":%s NOTICE %s :UPING: Can't set fd non-blocking",
me.name, parv[0]);
close(fd);
return 0;
}
/*
** On some systems, receive and send buffers must be equal in size.
** Others block select() when the buffers are too small
** (Linux 1.1.50 blocks when < 2048) --Run
*/
opt = 2048;
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (OPT_TYPE *)&opt, sizeof(opt)) < 0 ||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (OPT_TYPE *)&opt, sizeof(opt)) < 0)
{
int err=errno;
sendto_ops("m_uping: setsockopt SO_SNDBUF|SO_RCVBUF: %s",
strerror(err));
sendto_one(sptr, ":%s NOTICE %s :UPING: error in setsockopt: %s",
me.name, parv[0], strerror(err));
close(fd);
return 0;
}
if (fd >= MAXCONNECTIONS)
{
sendto_ops("Can't allocate fd for uping (all connections in use)");
sendto_one(sptr, ":%s NOTICE %s :UPING: All connections in use",
me.name, parv[0]);
close(fd);
return 0;
}
if (fd > highest_fd)
highest_fd = fd;
local[fd] = cptr = make_client(NULL);
cptr->confs = (Link *)MyMalloc(UPINGBUFSIZE); /* Really a (char *) */
cptr->fd = fd;
cptr->port = port;
cptr->hopcount = cptr->hashv = cptr->count = MIN(20, atoi(parv[4]));
strcpy(cptr->sockhost, aconf->host);
cptr->acpt = sptr;
SetAskedPing(sptr);
bcopy((void *)&aconf->ipnum, (void *)&cptr->ip, sizeof(struct in_addr));
strcpy(cptr->name, aconf->name);
cptr->firsttime = 0;
SetPing(cptr);
switch (ping_server(cptr, NULL))
{
case 0:
break;
case -1:
del_queries((char *)cptr);
end_ping(cptr);
break;
}
return 0;
}
void end_ping(cptr)
register aClient *cptr;
{
Debug((DEBUG_DEBUG,"end_ping: %x", cptr));
if (cptr->acpt)
{
if (cptr->firsttime) /* Started at all ? */
{
if (cptr->hashv != cptr->hopcount) /* Received any pings at all ? */
{
sendto_one(cptr->acpt, ":%s NOTICE %s :UPING %s%s",
me.name, cptr->acpt->name, cptr->name, cptr->buffer);
sendto_one(cptr->acpt,
":%s NOTICE %s :UPING Stats: sent %d recvd %d ; min/avg/max = %lu/%lu/%lu ms",
me.name, cptr->acpt->name, cptr->hopcount - cptr->count,
cptr->hopcount - cptr->hashv, cptr->receiveK,
(2 * cptr->sendM + cptr->hopcount - cptr->hashv) /
(2 * ( cptr->hopcount - cptr->hashv)),
cptr->receiveM);
}
else
sendto_one(cptr->acpt,
":%s NOTICE %s :UPING: no response from %s within %d seconds",
me.name, cptr->acpt->name, cptr->name,
now + cptr->since - cptr->firsttime);
}
else
sendto_one(cptr->acpt,
":%s NOTICE %s :UPING: Could not start ping to %s %d",
me.name, cptr->acpt->name, cptr->name, cptr->port);
}
(void)close(cptr->fd);
local[cptr->fd] = NULL;
if (cptr->acpt)
ClearAskedPing(cptr->acpt);
MyFree((char *)cptr->confs);
free_client(cptr);
}
void cancel_ping(sptr, acptr)
aClient *sptr, *acptr;
{
int i;
aClient *cptr;
Debug((DEBUG_DEBUG, "Cancelling uping for %x (%s)", sptr, sptr->name));
for (i = highest_fd; i >= 0; i--)
if ((cptr = local[i]) && IsPing(cptr) && cptr->acpt == sptr)
{ cptr->acpt = acptr;
del_queries((char *)cptr);
end_ping(cptr);
break; }
ClearAskedPing(sptr);
}

3017
ircd/s_serv.c Normal file

File diff suppressed because it is too large Load Diff

2802
ircd/s_user.c Normal file

File diff suppressed because it is too large Load Diff

251
ircd/userload.c Normal file
View File

@@ -0,0 +1,251 @@
/****************************************************************************
* Userload module by Michael L. VanLoon (mlv) <michaelv@iastate.edu>
* Written 2/93. Originally grafted into irc2.7.2g 4/93.
*
* IRC - Internet Relay Chat, ircd/userload.c
* Copyright (C) 1990 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.
****************************************************************************/
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "userload.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <string.h>
#include <signal.h>
#include <sys/resource.h>
#include "h.h"
struct current_load_struct current_load_data;
struct load_entry *load_list_head = NULL, *load_list_tail = NULL,
*load_free_head = NULL, *load_free_tail = NULL;
void update_load()
{
static struct timeval nowt, last;
register struct load_entry *cur_load_entry;
/* This seems to get polluted on startup by an exit_client()
* before any connections have been recorded.
*/
if (current_load_data.local_count > MAXCONNECTIONS ||
current_load_data.client_count > MAXCONNECTIONS ||
current_load_data.conn_count > MAXCONNECTIONS)
bzero((char *)&current_load_data, sizeof(struct current_load_struct));
memcpy(&last, &nowt, sizeof(struct timeval));
if (gettimeofday(&nowt, NULL) != 0)
return; /* error getting time of day--can't calculate time diff */
if (load_free_tail == NULL) {
if ((cur_load_entry =
(struct load_entry *) malloc(sizeof(struct load_entry))) == NULL)
return;
/* printf("malloc pointer: %x\n", cur_load_entry); */
} else {
cur_load_entry = load_free_tail;
load_free_tail = cur_load_entry->prev;
if (load_free_tail == NULL)
load_free_head = NULL;
/* printf("free pointer: %x\n", cur_load_entry); */
}
if (load_list_tail != NULL) {
cur_load_entry->time_incr = ((nowt.tv_sec * 1000 + nowt.tv_usec / 1000 + 5)
- (last.tv_sec * 1000 + last.tv_usec / 1000)) / 10;
cur_load_entry->local_count = current_load_data.local_count;
cur_load_entry->client_count = current_load_data.client_count;
cur_load_entry->conn_count = current_load_data.conn_count;
} else {
load_list_head = cur_load_entry;
bzero((char *)cur_load_entry, sizeof(struct load_entry));
cur_load_entry->time_incr = 1;
}
cur_load_entry->prev = load_list_tail;
load_list_tail = cur_load_entry;
}
void calc_load(sptr, parv)
aClient *sptr;
char *parv; /* we only get passed the original parv[0] */
{
register struct load_entry *cur_load_entry;
struct load_entry *last;
u_long secs = 0, adj_secs, total[3], adj[3];/*[local,client,conn]*/
int i, times[5][3]; /* [min,hour,day,Yest,YYest][local,client,conn] */
char what[3][HOSTLEN + 1];
bzero((char *)total, 3 * sizeof(u_long));
current_load_data.entries = 0;
update_load(); /* we want stats accurate as of *now* */
for (cur_load_entry = load_list_tail; (secs < 6000) &&
(cur_load_entry != NULL); cur_load_entry = cur_load_entry->prev) {
u_long time_incr = cur_load_entry->time_incr;
total[0] += time_incr * cur_load_entry->local_count;
total[1] += time_incr * cur_load_entry->client_count;
total[2] += time_incr * cur_load_entry->conn_count;
last = cur_load_entry;
secs += cur_load_entry->time_incr;
current_load_data.entries++;
}
if ((secs > 6000) && (last != NULL)) {
adj_secs = secs - 6000;
adj[0] = adj_secs * last->local_count;
adj[1] = adj_secs * last->client_count;
adj[2] = adj_secs * last->conn_count;
} else
adj_secs = adj[0] = adj[1] = adj[2] = 0;
for (i = 0; i < 3; i++) {
times[0][i] = ((total[i] - adj[i]) * 1000 / (secs - adj_secs) + 5) / 10;
}
secs = (secs + 5) / 10;
for (i = 0; i < 3; i++)
total[i] = (total[i] + 5) / 10;
for ( ; (secs < 36000) && (cur_load_entry != NULL); secs +=
(cur_load_entry->time_incr + 5) / 10, cur_load_entry =
cur_load_entry->prev, current_load_data.entries++) {
u_long time_incr = (cur_load_entry->time_incr + 5) / 10;
total[0] += time_incr * cur_load_entry->local_count;
total[1] += time_incr * cur_load_entry->client_count;
total[2] += time_incr * cur_load_entry->conn_count;
last = cur_load_entry;
}
if ((secs > 36000) && (last != NULL)) {
adj_secs = secs - 36000;
adj[0] = adj_secs * last->local_count;
adj[1] = adj_secs * last->client_count;
adj[2] = adj_secs * last->conn_count;
} else
adj_secs = adj[0] = adj[1] = adj[2] = 0;
for (i = 0; i < 3; i++) {
times[1][i] = ((total[i] - adj[i]) * 100 / (secs - adj_secs) + 5) / 10;
}
secs = (secs + 5) / 10;
for (i = 0; i < 3; i++)
total[i] = (total[i] + 5) / 10;
for ( ; (secs < 86400) && (cur_load_entry != NULL); secs +=
(cur_load_entry->time_incr + 50) / 100, cur_load_entry =
cur_load_entry->prev, current_load_data.entries++) {
u_long time_incr = (cur_load_entry->time_incr + 50) / 100;
total[0] += time_incr * cur_load_entry->local_count;
total[1] += time_incr * cur_load_entry->client_count;
total[2] += time_incr * cur_load_entry->conn_count;
last = cur_load_entry;
}
if ((secs > 86400) && (last != NULL)) {
adj_secs = secs - 86400;
adj[0] = adj_secs * last->local_count;
adj[1] = adj_secs * last->client_count;
adj[2] = adj_secs * last->conn_count;
} else
adj_secs = adj[0] = adj[1] = adj[2] = 0;
for (i = 0; i < 3; i++) {
times[2][i] = ((total[i] - adj[i]) * 10 / (secs - adj_secs) + 5) / 10;
}
bzero((char *)total, 3 * sizeof(u_long));
for (secs = 1 ; (secs < 86400) && (cur_load_entry != NULL); secs +=
(cur_load_entry->time_incr + 50) / 100, cur_load_entry =
cur_load_entry->prev, current_load_data.entries++) {
u_long time_incr = (cur_load_entry->time_incr + 50) / 100;
total[0] += time_incr * cur_load_entry->local_count;
total[1] += time_incr * cur_load_entry->client_count;
total[2] += time_incr * cur_load_entry->conn_count;
last = cur_load_entry;
}
if ((secs > 86400) && (last != NULL)) {
adj_secs = secs - 86400;
adj[0] = adj_secs * last->local_count;
adj[1] = adj_secs * last->client_count;
adj[2] = adj_secs * last->conn_count;
} else
adj_secs = adj[0] = adj[1] = adj[2] = 0;
for (i = 0; i < 3; i++) {
times[3][i] = ((total[i] - adj[i]) * 10 / (secs - adj_secs) + 5) / 10;
}
bzero((char *)total, 3 * sizeof(u_long));
for (secs = 1 ; (secs < 86400) && (cur_load_entry != NULL); secs +=
(cur_load_entry->time_incr + 50) / 100, cur_load_entry =
cur_load_entry->prev, current_load_data.entries++) {
u_long time_incr = (cur_load_entry->time_incr + 50) / 100;
total[0] += time_incr * cur_load_entry->local_count;
total[1] += time_incr * cur_load_entry->client_count;
total[2] += time_incr * cur_load_entry->conn_count;
last = cur_load_entry;
}
if ((secs > 86400) && (last != NULL)) {
adj_secs = secs - 86400;
adj[0] = adj_secs * last->local_count;
adj[1] = adj_secs * last->client_count;
adj[2] = adj_secs * last->conn_count;
} else
adj_secs = adj[0] = adj[1] = adj[2] = 0;
for (i = 0; i < 3; i++) {
times[4][i] = ((total[i] - adj[i]) * 10 / (secs - adj_secs) + 5) / 10;
}
if ((cur_load_entry != NULL) && (cur_load_entry->prev != NULL) &&
(secs > 86400)) { /* have nodes to free -- more than 3 days old */
struct load_entry *cur_free_entry = load_free_head;
load_free_head = load_list_head;
load_list_head = cur_load_entry;
if (cur_free_entry != NULL)
cur_free_entry->prev = cur_load_entry->prev;
else
load_free_tail = cur_load_entry->prev;
/* printf("freeing: %x (head: %x, tail: %x)\n", cur_load_entry->prev,
load_free_head, load_free_tail); */
cur_load_entry->prev = NULL;
}
strcpy(what[0], DOMAINNAME);
strcat(what[0], " clients");
strcpy(what[1], "total clients");
strcpy(what[2], "total connections");
sendto_one(sptr,
":%s NOTICE %s :Minute Hour Day Yest. YYest. Userload for:",
me.name, parv);
for (i = 0; i < 3; i++)
sendto_one(sptr,
":%s NOTICE %s :%3d.%02d %3d.%01d %3d %3d %3d %s",
me.name, parv, times[0][i] / 100, times[0][i] % 100, times[1][i] / 10,
times[1][i] % 10, times[2][i], times[3][i], times[4][i], what[i]);
}
void initload()
{
bzero((char *)&current_load_data, sizeof(struct current_load_struct));
update_load(); /* Initialize the load list */
}

118
ircd/version.c.SH Executable file
View File

@@ -0,0 +1,118 @@
case $CONFIG in
'') if test -r ../config.sh
then
. ../config.sh ;
else
spitshell=cat
package=IRC
fi
;;
esac
echo "Extracting $package/ircd/version.c..."
if test -r version.c
then
generation=`sed -n 's/^char \*generation = \"\(.*\)\";/\1/p' < version.c`
if test ! "$generation" ; then generation=0; fi
else
generation=0
fi
generation=`expr $generation + 1`
sumsserv=`sum s_serv.c`;
sumsuser=`sum s_user.c`;
sumchan=`sum channel.c`;
sumsbsd=`sum s_bsd.c`;
sumhash=`sum hash.c`;
sumsmisc=`sum s_misc.c`;
sumircd=`sum ircd.c`;
creation=`date | \
awk '{if (NF == 6) \
{ print $1 " " $2 " " $3 " " $6 " at " $4 " " $5 } \
else \
{ print $1 " " $2 " " $3 " " $7 " at " $4 " " $5 " " $6 }}'`
$spitshell >version.c <<!SUB!THIS!
/*
* IRC - Internet Relay Chat, ircd/version.c
* Copyright (C) 1990 Chelsea Ashley Dyerman
*
* 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.
*/
/*
* This file is generated by version.c.SH. Any changes made will go away.
*/
#include "struct.h"
#include "patchlevel.h"
char *generation = "$generation";
char *creation = "$creation";
char *version = BASE_VERSION PATCH1 PATCH2 PATCH3 PATCH4\
PATCH5 PATCH6 PATCH7 PATCH8 PATCH9;
char *infotext[] =
{
"$package --",
"Based on the original code written by Jarkko Oikarinen",
"Copyright 1988, 1989, 1990, 1991 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.",
"",
"The following persons have made many changes and enhancements to the",
"code and still know how IRC really works if you have questions about it:",
"",
"Run Carlo Kid carlo@runaway.xs4all.nl",
"Avalon Darren Reed avalon@coombs.anu.edu.au",
"msa Markku Savela Markku.Savela@vtt.fi",
"Wumpus Greg Lindahl gl8f@virginia.edu",
"WiZ Jarkko Oikarinen jto@tolsun.oulu.fi",
"Argv Armin Gruner Armin.Gruner@Informatik.TU-Muenchen.de",
"",
"Thanks to the following people for help with preparing 2.8",
"",
"phone Matthew Green phone@coombs.anu.edu.au",
"Sodapop Chuck Kane ckane@ece.uiuc.edu",
"Skygod Matt Lyle matt@oc.com",
"Vesa Vesa Ruokonen ruokonen@lut.fi",
"Nap Nicolas PIOCH pioch@poly.polytechnique.fr",
"",
"Those who helped in prior versions and continue to be helpful:",
"",
"Stellan Klebom Dan Goodwin Mike Bolotski",
"Ian Frechette Markku Jarvinen Kimmo Suominen",
"Jeff Trim Vijay Subramaniam Karl Kleinpaste",
"Bill Wisner Tom Davis Hugo Calendar",
"Tom Hopkins Stephen van den Berg",
"Bo Adler Michael Sandrof Jon Solomon",
"Jan Peterson Helen Rose Paul Graham",
"",
"Thanks also goes to those persons not mentioned here who have added",
"their advice, opinions, and code to IRC.",
"Thanks also to those who provide the kind sys admins who let me and",
"others continue to develop IRC.",
"",
"[$sumsserv] [$sumchan] [$sumsbsd] [$sumsuser]",
"[$sumhash] [$sumsmisc] [$sumircd]",
0,
};
!SUB!THIS!

224
ircd/whowas.c Normal file
View File

@@ -0,0 +1,224 @@
/************************************************************************
* IRC - Internet Relay Chat, ircd/whowas.c
* Copyright (C) 1990 Markku Savela
*
* 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 --- 6th April 1992
* rewritten to scrap linked lists and use a table of structures which
* is referenced like a circular loop. Should be faster and more efficient.
*/
#ifndef lint
static char sccsid[] = "@(#)whowas.c 2.16 08 Nov 1993 (C) 1988 Markku Savela";
#endif
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "whowas.h"
#include "h.h"
static aName was[NICKNAMEHISTORYLENGTH];
static int ww_index = 0;
void add_history(cptr)
Reg1 aClient *cptr;
{
aName ntmp;
Reg2 aName *np = &ntmp, *np2;
strncpyzt(np->ww_nick, cptr->name, NICKLEN+1);
strncpyzt(np->ww_info, cptr->info, REALLEN+1);
np->ww_user = cptr->user;
np->ww_logout = now;
np->ww_online = (cptr->from != NULL) ? cptr : NULL;
np->ww_user->refcnt++;
np->ww_server = (char *)MyMalloc(strlen(np->ww_user->server->name)+1);
strcpy(np->ww_server, np->ww_user->server->name);
np2 = &was[ww_index];
if (np2->ww_user)
{
free_user(np2->ww_user, np2->ww_online);
MyFree(np2->ww_server);
}
bcopy((char *)&ntmp, (char *)np2, sizeof(aName));
ww_index++;
if (ww_index >= NICKNAMEHISTORYLENGTH)
ww_index = 0;
return;
}
/*
** get_history
** Return the current client that was using the given
** nickname within the timelimit. Returns NULL, if no
** one found...
*/
aClient *get_history(nick, timelimit)
char *nick;
time_t timelimit;
{
Reg1 aName *wp, *wp2;
Reg2 int i = 0;
if (ww_index == 0)
wp = wp2 = &was[NICKNAMEHISTORYLENGTH - 1];
else
wp = wp2 = &was[ww_index - 1];
timelimit = now-timelimit;
do {
if (!mycmp(nick, wp->ww_nick) && wp->ww_logout >= timelimit)
break;
if (wp == was)
{
i = 1;
wp = &was[NICKNAMEHISTORYLENGTH - 1];
}
else
wp--;
} while (wp != wp2);
if (wp != wp2 || !i)
return (wp->ww_online);
return (NULL);
}
void off_history(cptr)
Reg3 aClient *cptr;
{
Reg1 aName *wp;
Reg2 int i;
for (i = NICKNAMEHISTORYLENGTH, wp = was; i; wp++, i--)
if (wp->ww_online == cptr)
wp->ww_online = NULL;
return;
}
void initwhowas()
{
bzero((char *)was, NICKNAMEHISTORYLENGTH * sizeof(aName));
}
/*
** m_whowas
** parv[0] = sender prefix
** parv[1] = nickname queried
*/
int m_whowas(cptr, sptr, parc, parv)
aClient *cptr, *sptr;
int parc;
char *parv[];
{
Reg1 aName *wp, *wp2 = NULL;
Reg2 int j = 0;
Reg3 anUser *up = NULL;
int max = -1;
char *p, *nick, *s;
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN),
me.name, parv[0]);
return 0;
}
if (parc > 2)
max = atoi(parv[2]);
if (parc > 3)
if (hunt_server(cptr,sptr,":%s WHOWAS %s %s :%s", 3,parc,parv))
return 0;
for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL)
{
wp = wp2 = &was[ww_index - 1];
do {
if (wp < was)
wp = &was[NICKNAMEHISTORYLENGTH - 1];
if (mycmp(nick, wp->ww_nick) == 0)
{
up = wp->ww_user;
sendto_one(sptr, rpl_str(RPL_WHOWASUSER),
me.name, parv[0], wp->ww_nick,
up->username,
up->host, wp->ww_info);
sendto_one(sptr, rpl_str(RPL_WHOISSERVER),
me.name, parv[0], wp->ww_nick,
wp->ww_server,
myctime(wp->ww_logout));
if (up->away)
sendto_one(sptr, rpl_str(RPL_AWAY),
me.name, parv[0],
wp->ww_nick, up->away);
j++;
}
if (max > 0 && j >= max)
break;
wp--;
} while (wp != wp2);
if (up == NULL)
sendto_one(sptr, err_str(ERR_WASNOSUCHNICK),
me.name, parv[0], nick);
up = NULL;
if (p)
p[-1] = ',';
}
sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS), me.name, parv[0], parv[1]);
return 0;
}
void count_whowas_memory(wwu, wwa, wwam)
int *wwu, *wwa;
u_long *wwam;
{
Reg1 anUser *tmp;
Reg2 int i, j;
int u = 0, a = 0;
u_long am = 0;
for (i = 0; i < NICKNAMEHISTORYLENGTH; i++)
if ((tmp = was[i].ww_user))
if (!was[i].ww_online)
{
for (j = 0; j < i; j++)
if (was[j].ww_user == tmp)
break;
if (j < i)
continue;
u++;
if (tmp->away)
{
a++;
am += (strlen(tmp->away)+1);
}
}
*wwu = u;
*wwa = a;
*wwam = am;
return;
}